Skip to content

Commit a4a4b8e

Browse files
committed
initial port - based off therubyrhino
0 parents  commit a4a4b8e

14 files changed

+839
-0
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.idea
2+
nbproject
3+
doc
4+
*.gem
5+
.rvmrc
6+
.bundle
7+
Gemfile.lock
8+
spec/deprecations.log

.rspec

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--color --format documentation

Gemfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
source "https://rubygems.org"
2+
3+
gemspec
4+
5+
group :test do
6+
# NOTE: some specs might be excluded @see #spec/spec_helper.rb
7+
#gem 'redjs', :git => 'git://github.com/cowboyd/redjs.git', :group => :test,
8+
# :ref => "0d844f066666f967a78b20beb164c52d9ac3f5ca"
9+
#gem 'less', '>= 2.2.1', :require => nil
10+
end
11+
12+
gem 'rake', :require => false, :group => :development

Rakefile

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
task :default => :spec
3+
4+
begin
5+
require 'bundler/setup'
6+
rescue LoadError => e
7+
warn "Bundler not available: #{e.inspect}"
8+
else
9+
require 'bundler/gem_tasks'
10+
Bundler::GemHelper.install_tasks
11+
end
12+
13+
require 'rspec/core'
14+
require 'rspec/core/rake_task'
15+
RSpec::Core::RakeTask.new(:spec) do |spec|
16+
spec.pattern = 'spec/**/*_spec.rb'
17+
spec.rspec_opts = '--color'
18+
end

dienashorner.gemspec

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# -*- encoding: utf-8 -*-
2+
3+
Gem::Specification.new do |gem|
4+
gem.name = 'therubyrhino becomes dienashorner'.split.last
5+
gem.authors = ['Karol Bucek']
6+
gem.email = ['[email protected]']
7+
gem.licenses = ['Apache-2.0']
8+
9+
path = File.expand_path("lib/nashorn/version.rb", File.dirname(__FILE__))
10+
gem.version = File.read(path).match( /.*VERSION\s*=\s*['"](.*)['"]/m )[1]
11+
12+
gem.summary = %q{The Nashorn JavaScript interpreter for JRuby}
13+
gem.description = %q{Nashorn, a Rhino's sucessor, allows embeded JavaScript interaction from within Ruby.}
14+
gem.homepage = "https://github.com/kares/dienashorner"
15+
16+
gem.require_paths = ["lib"]
17+
gem.files = `git ls-files`.split("\n").sort
18+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
19+
20+
gem.extra_rdoc_files = %w[ README.md LICENSE ]
21+
22+
gem.add_development_dependency "rspec", "~> 2.14.1"
23+
gem.add_development_dependency "mocha", "~> 0.13.3"
24+
end

lib/nashorn.rb

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
begin
2+
require 'java'
3+
rescue LoadError => e
4+
raise e if defined? JRUBY_VERSION
5+
raise LoadError, "Please use JRuby with Nashorn : #{e.message}", e.backtrace
6+
end
7+
8+
if ENV_JAVA['java.version'] < '1.8'
9+
warn "Nashorn needs Java >= 8, you're Java version #{ENV_JAVA['java.version']} won't work!"
10+
end
11+
12+
module Nashorn
13+
# @private
14+
module JS
15+
include_package 'jdk.nashorn.api.scripting'
16+
end
17+
18+
class << self
19+
20+
def eval_js(source, options = {})
21+
factory = JS::NashornScriptEngineFactory.new
22+
factory.getScriptEngine.eval(source)
23+
end
24+
alias_method :eval, :eval_js
25+
26+
end
27+
end
28+
29+
require 'nashorn/version'
30+
require 'nashorn/ext'
31+
require 'nashorn/convert'
32+
require 'nashorn/ruby'

lib/nashorn/convert.rb

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class << Nashorn
2+
3+
def to_rb(object)
4+
return nil if Nashorn::JS::ScriptObjectMirror.isUndefined(object)
5+
# ConsString for optimized String + operations :
6+
return object.toString if object.is_a?(Java::JavaLang::CharSequence)
7+
object
8+
end
9+
alias_method :to_ruby, :to_rb
10+
11+
def to_js(object)
12+
case object
13+
when NilClass then object
14+
when String, Numeric then object.to_java
15+
when TrueClass, FalseClass then object.to_java
16+
when Nashorn::JS::JSObject then object
17+
#when Array then array_to_js(object)
18+
#when Hash then hash_to_js(object)
19+
when Time then time_to_js(object)
20+
when Method, UnboundMethod then Nashorn::Ruby::Function.wrap(object)
21+
when Proc then Nashorn::Ruby::Function.wrap(object)
22+
when Class then Nashorn::Ruby::Constructor.wrap(object)
23+
else Nashorn::Ruby::Object.wrap(object)
24+
end
25+
end
26+
alias_method :to_javascript, :to_js
27+
28+
def args_to_rb(args)
29+
args.map { |arg| to_rb(arg) }
30+
end
31+
32+
def args_to_js(args)
33+
args.map { |arg| to_js(arg) }.to_java
34+
end
35+
36+
private
37+
38+
#def array_to_js(rb_array)
39+
#end
40+
41+
#def hash_to_js(rb_hash)
42+
#end
43+
44+
def time_to_js(time)
45+
time.to_java
46+
end
47+
48+
end

lib/nashorn/error.rb

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
module Nashorn
2+
3+
class JSError < StandardError
4+
5+
def initialize(native)
6+
@native = native # NativeException wrapping a Java Throwable
7+
if ( value = self.value(true) ) != nil
8+
super value.is_a?(Exception) ? "#{value.class.name}: #{value.message}" : value
9+
else
10+
super cause ? cause.message : @native
11+
end
12+
end
13+
14+
def inspect
15+
"#<#{self.class.name}: #{message}>"
16+
end
17+
18+
def message; super.to_s end
19+
20+
# Returns the (nested) cause of this error if any.
21+
def cause
22+
return @cause if defined?(@cause)
23+
if @native.respond_to?(:cause) && @native.cause
24+
@cause = @native.cause
25+
else
26+
@native.is_a?(JS::NashornException) ? @native : nil
27+
end
28+
end
29+
30+
# Attempts to unwrap the (native) JavaScript/Java exception.
31+
def unwrap
32+
return @unwrap if defined?(@unwrap)
33+
cause = self.cause
34+
if cause && cause.is_a?(JS::NashornException)
35+
e = cause.getCause
36+
if e && e.is_a?(Java::OrgJrubyExceptions::RaiseException)
37+
@unwrap = e.getException
38+
else
39+
@unwrap = e
40+
end
41+
else
42+
@unwrap = nil
43+
end
44+
end
45+
46+
# Return the thown (native) JavaScript value.
47+
def value(unwrap = false)
48+
return @value if defined?(@value) && ! unwrap
49+
@value = get_thrown unless defined?(@value)
50+
return @value.unwrap if unwrap && @value.respond_to?(:unwrap)
51+
@value
52+
end
53+
alias_method :thrown, :value
54+
55+
# The backtrace is constructed using #javascript_backtrace + the Ruby part.
56+
def backtrace
57+
if js_backtrace = javascript_backtrace
58+
js_backtrace.push(*super)
59+
else
60+
super
61+
end
62+
end
63+
64+
# Returns the JavaScript back-trace part for this error (the script stack).
65+
def javascript_backtrace(raw_elements = false)
66+
return nil unless cause.is_a?(JS::NashornException)
67+
JS::NashornException.getScriptFrames(cause).map do |element|
68+
raw_elements ? element : element.to_s # ScriptStackElement
69+
end
70+
end
71+
72+
private
73+
74+
def get_thrown
75+
if ( cause = self.cause ) && cause.respond_to?(:thrown)
76+
cause.thrown # e.g. NashornException.getThrown
77+
else
78+
nil
79+
end
80+
end
81+
82+
end
83+
84+
end

lib/nashorn/ext.rb

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
module Nashorn
2+
module JS
3+
4+
JSObject.module_eval do
5+
6+
def [](key)
7+
Nashorn.to_rb key.is_a?(Fixnum) ? getSlot(key) : getMember(key.to_s)
8+
end
9+
10+
def []=(key, value)
11+
name.is_a?(Fixnum) ? setSlot(key, value) : setMember(key.to_s, value)
12+
end
13+
14+
# enumerate the key value pairs contained in this javascript object. e.g.
15+
#
16+
# eval_js("{foo: 'bar', baz: 'bang'}").each do |key,value|
17+
# puts "#{key} -> #{value} "
18+
# end
19+
#
20+
# outputs foo -> bar baz -> bang
21+
#
22+
def each
23+
each_raw { |key, val| yield key, Nashorn.to_rb(val) }
24+
end
25+
26+
def each_key
27+
each_raw { |key, val| yield key }
28+
end
29+
30+
def each_value
31+
each_raw { |key, val| yield Nashorn.to_rb(val) }
32+
end
33+
34+
def each_raw
35+
for id in keySet do
36+
yield id, getMember(id)
37+
end
38+
end
39+
40+
def keys
41+
keySet.to_a
42+
end
43+
44+
def values
45+
values.to_a
46+
end
47+
48+
# Converts the native object to a hash. This isn't really a stretch since it's
49+
# pretty much a hash in the first place.
50+
def to_h
51+
hash = {}
52+
each do |key, val|
53+
hash[key] = val.is_a?(JSObject) && ! val.equal?(self) ? val.to_h : val
54+
end
55+
hash
56+
end
57+
58+
# def ==(other)
59+
# equivalentValues(other) == true # JS ==
60+
# end
61+
#
62+
# def eql?(other)
63+
# self.class == other.class && self.==(other)
64+
# end
65+
66+
# Convert this javascript object into a json string.
67+
def to_json(*args)
68+
to_h.to_json(*args)
69+
end
70+
71+
# Delegate methods to JS object if possible when called from Ruby.
72+
def method_missing(name, *args)
73+
name_str = name.to_s
74+
if name_str.end_with?('=') && args.size == 1 # writer -> JS put
75+
self[ name_str[0...-1] ] = args[0]
76+
else
77+
if hasMember(name_str) && property = getMember(name_str)
78+
if property.is_a?(JSObject) && property.isFunction
79+
js_args = Nashorn.args_to_js(args)
80+
Nashorn.to_rb property.__call__(self, js_args)
81+
else
82+
if args.size > 0
83+
raise ArgumentError, "can't call '#{name_str}' with args: #{args.inspect} as it's a property"
84+
end
85+
Nashorn.to_rb property
86+
end
87+
else
88+
super
89+
end
90+
end
91+
end
92+
93+
# function :
94+
95+
alias_method :__call__, :call
96+
97+
# make JavaScript functions callable Ruby style e.g. `fn.call('42')`
98+
#
99+
# NOTE: That invoking #call does not have the same semantics as
100+
# JavaScript's Function#call but rather as Ruby's Method#call !
101+
# Use #apply or #bind before calling to achieve the same effect.
102+
def call(*args)
103+
this = nil
104+
Nashorn.to_rb __call__ this, Nashorn.args_to_js(args)
105+
rescue JS::NashornException => e
106+
raise Nashorn::JSError.new(e)
107+
end
108+
109+
# bind a JavaScript function into the given (this) context
110+
#def bind(this, *args)
111+
# args = Nashorn.args_to_js(args)
112+
# Rhino::JS::BoundFunction.new(self, Nashorn.to_js(this), args)
113+
#end
114+
115+
# use JavaScript functions constructors from Ruby as `fn.new`
116+
def new(*args)
117+
construct Nashorn.args_to_js(args)
118+
rescue JS::NashornException => e
119+
raise Nashorn::JSError.new(e)
120+
end
121+
122+
# apply a function with the given context and (optional) arguments
123+
# e.g. `fn.apply(obj, 1, 2)`
124+
#
125+
# NOTE: That #call from Ruby does not have the same semantics as
126+
# JavaScript's Function#call but rather as Ruby's Method#call !
127+
def apply(this, *args)
128+
__call__ Nashorn.to_js(this), Nashorn.args_to_js(args)
129+
rescue JS::NashornException => e
130+
raise Nashorn::JSError.new(e)
131+
end
132+
alias_method :methodcall, :apply # V8::Function compatibility
133+
134+
end
135+
end
136+
end

0 commit comments

Comments
 (0)