Skip to content

Instantly share code, notes, and snippets.

@cowboyd
Created January 17, 2011 19:36
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cowboyd/783330 to your computer and use it in GitHub Desktop.
Save cowboyd/783330 to your computer and use it in GitHub Desktop.
Proof of concept for making all ruby available to javascript.
require 'v8'
require 'openssl'
class Module
def [](name)
self.const_get(name)
end
end
class RubyTopLevel
def [](constant)
Object.const_get(constant)
end
end
V8::Context.new do |cxt|
cxt['Ruby'] = RubyTopLevel.new
cxt.eval('var cipher = new Ruby.OpenSSL.Cipher("aes-128-cbc")')
cxt.eval('cipher.decrypt')
puts cxt['cipher'] #=> #<OpenSSL::Cipher:0x1015c7f40>
end
@judofyr
Copy link

judofyr commented Jan 17, 2011

You can safely replace eval("::#{constant}") with Object.const_get(constant).

@caius
Copy link

caius commented Jan 17, 2011

@judofyr:

const_get can't handle namespaced constants, whereas eval can. You can do it recursively using Object#const_get, splitting the string on '::' and then "walking" down the constants, calling const_get on each in turn though.

Foo = Class.new
Bar = Class.new(Foo)

const = "Foo::Bar"
eval(const) # => Bar
Object.const_get(const) # => NameError: "wrong constant name Foo::Bar"

@cowboyd
Copy link
Author

cowboyd commented Jan 17, 2011

@caius: in this case it will work because it will be invoked only with top level constants, hence RubyTopLevel.

@caius
Copy link

caius commented Jan 17, 2011

Hmm, true. Hadn't looked at the original code for the use of eval("::#{constant}"), was just pointing out the two aren't the same.

@judofyr
Copy link

judofyr commented Jan 17, 2011

General solution to this problem:

"Foo::Bar".split("::").inject(Object) { |m, e| m.const_get(e) }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment