Skip to content

Instantly share code, notes, and snippets.

@chancancode
Last active August 29, 2015 14:10
Show Gist options
  • Select an option

  • Save chancancode/0087d86c935db02453ae to your computer and use it in GitHub Desktop.

Select an option

Save chancancode/0087d86c935db02453ae to your computer and use it in GitHub Desktop.
require_relative 'javascript'
puts "This is totally Ruby"
javascript {
console.log("OMG JavaScript");
var a = 1;
console.log(a);
a = a + 1;
console.log(a);
var b = function(x) {
console.log(x + 1);
};
b(3);
function c(x) {
console.log(x + 2);
}
c(4);
function inspectArguments() {
console.log("I was called with " + String(arguments.length) + " arguments");
}
inspectArguments(1, 2, 3, 4, 5);
puts "Just kidding, it is Ruby in here too..."
}
% ruby test.rb
This is totally Ruby
OMG JavaScript
1
2
4
6
I was called with 5 arguments
Just kidding, it is Ruby in here too...
require 'binding_of_caller'
def supress_warnings
verbose, $VERBOSE = $VERBOSE, nil
yield
ensure
$VERBOSE = verbose
end
module JavaScript
# Make it an `Object` instead of `BasicObject` so that we can bind
# any instance methods from `Object` and call them here
class Scope < ::Object; end
supress_warnings do
Scope.instance_methods(true).each { |meth| Scope.send(:undef_method, meth) }
end
class Scope
def initialize(locals = {})
@locals = locals
end
def var(*); end
def function(*args, &block)
if args.length == 1 && Function === args[0]
@locals[args[0].name] = args[0]
else
Function.new(nil, args, block)
end
end
def console
@console ||= Console.new
end
def self.eval(&block)
new.__eval__(&block)
end
def __eval__(&block)
Object.new.method(:instance_eval).unbind.bind(self).call(&block)
end
def method_missing(name, *args, &block)
caller_binding = binding.of_caller(1)
result = nil
if caller_binding.local_variable_defined?(name)
result = caller_binding.local_variable_get(name)
elsif @locals.key?(name)
result = @locals[name]
end
if result && Function === result
result.call(*args)
elsif result
result
elsif args.empty? && block.nil?
Identifier.new(name)
else
Function.new(name, args, block)
end
end
end
class Identifier < Struct.new(:name); end
class Function < Struct.new(:name, :arg_names, :block)
def call(*arg_values)
locals = Hash[ arg_names.map(&:name).zip(arg_values) ]
locals[:arguments] = arg_values
Scope.new(locals).__eval__(&block)
end
end
class Console
def log(*args)
puts(*args)
end
end
end
module Kernel
def javascript(&block)
JavaScript::Scope.eval(&block)
end
end
@chancancode

Copy link
Copy Markdown
Author

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