lib/opal/context.rb in opal-0.3.9 vs lib/opal/context.rb in opal-0.3.10
- old
+ new
@@ -2,68 +2,60 @@
class Context
def initialize(root_dir = Dir.getwd)
@root_dir = root_dir
@builder = Opal::Builder.new
+ @loaded_paths = false
- @load_paths = resolve_load_paths
+ # special case: if we are running in opal root, then we dont want
+ # setup.rb to load the opal lib itself, so we do some "magic"
+ if @root_dir == OPAL_DIR
+ def self.setup_load_paths
+ return if @loaded_paths
+ Dir['packages/*/package.yml'].map do |package|
+ path = File.expand_path File.join(File.dirname(package), 'lib')
+ @v8.eval "opal.loader.paths.push('#{path}')"
+ end
+ end
+ end
+
+ setup_v8
end
+ ##
# Looks through vendor/ directory and adds all relevant load paths
- def resolve_load_paths
- Dir['vendor/*/package.yml'].map do |package|
- File.expand_path File.join(File.dirname(package), 'lib')
- end
- end
- # Setup the context. This basically loads opal.js into our context, and
- # replace the loader etc with our custom loader for a Ruby environment. The
- # default "browser" loader cannot access files from disk.
- def setup_v8
- return if @v8
+ def setup_load_paths
+ return if @loaded_paths
- begin
- require 'v8'
- rescue LoadError => e
- abort "therubyracer is required for running javascript. Install it with `gem install therubyracer`"
- end
+ setup = File.join @root_dir, 'packages', 'init.rb'
+ return [] unless File.exists? setup
- @v8 = V8::Context.new
- @v8['console'] = Console.new
-
- eval @builder.build_core, '(opal)'
- opal = @v8['opal']
- opal['fs'] = FileSystem.new self
-
- # FIXME: we cant use a ruby array as a js array :(
- opal['loader'] = Loader.new self, eval("[]")
-
- @load_paths.each do |path|
- eval "opal.loader.paths.push('#{path}')"
- end
-
+ @v8.eval "opal.run(function() {opal.require('#{setup}');});", setup
end
- def eval(code, file = nil)
- @v8.eval code, file
- end
-
+ ##
# Require the given id as if it was required in the context. This simply
# passes the require through to the underlying context.
+
def require_file(path)
setup_v8
- eval "opal.run(function() {opal.require('#{path}');});", path
+ @v8.eval "opal.run(function() {opal.require('#{path}');});", path
finish
end
+ ##
# Set ARGV for the context
+
def argv=(args)
puts "setting argv to #{args.inspect}"
- eval "opal.runtime.cs(opal.runtime.Object, 'ARGV', #{args.inspect});"
+ @v8.eval "opal.runtime.cs(opal.runtime.Object, 'ARGV', #{args.inspect});"
end
+ ##
# Start normal js repl
+
def start_repl
require 'readline'
setup_v8
loop do
@@ -74,52 +66,84 @@
# if we type exit, then we need to close down context
if line == "exit"
break
end
- puts "=> #{eval_ruby line, '(opal)'}"
+ puts "=> #{eval line, '(opal)'}"
end
finish
end
- def eval_ruby(content, line = "")
+ def eval(content, file = nil, line = "")
begin
- code = Opal::Parser.new(content).parse!.generate_top
- code = "opal.run(function() {var $rb = opal.runtime, self = $rb.top, __FILE__ = '(opal)';" + code + "});"
+ js = @builder.parse content
+ code = "opal.run(function() { var $rb = opal.runtime, self = $rb.top"
+ code += ", __FILE__ = '(opal)'; return (#{js})($rb, self, __FILE__); })"
# puts code
- @v8['$opal_irb_result'] = eval code, line
- eval "!($opal_irb_result == null || !$opal_irb_result.m$inspect) ? $opal_irb_result.m$inspect() : '(Object does not support #inspect)'"
+ @v8['$opal_irb_result'] = @v8.eval(code, file)
+ @v8.eval "!($opal_irb_result == null || !$opal_irb_result.m$inspect) ? $opal_irb_result.m$inspect() : '(Object does not support #inspect)'"
rescue => e
puts e
puts("\t" + e.backtrace.join("\n\t"))
end
end
+ ##
# Finishes the context, i.e. tidy everything up. This will cause
# the opal runtime to do it's at_exit() calls (if applicable) and
# then the v8 context will de removed. It can be reset by calling
# #setup_v8
+
def finish
return unless @v8
- eval "opal.runtime.do_at_exit()", "(opal)"
+ @v8.eval "opal.runtime.do_at_exit()", "(opal)"
@v8 = nil
end
+ # Setup the context. This basically loads opal.js into our context, and
+ # replace the loader etc with our custom loader for a Ruby environment. The
+ # default "browser" loader cannot access files from disk.
+ def setup_v8
+ return if @v8
+
+ begin
+ require 'v8'
+ rescue LoadError => e
+ abort "therubyracer is required for running javascript. Install it with `gem install therubyracer`"
+ end
+
+ @v8 = V8::Context.new
+ @v8['console'] = Console.new
+
+ @v8.eval @builder.build_core, '(opal)'
+ opal = @v8['opal']
+ opal['fs'] = FileSystem.new self
+
+ # FIXME: we cant use a ruby array as a js array :(
+ opal['loader'] = Loader.new self, @v8.eval("[]")
+
+ setup_load_paths
+ end
+
+ ##
# Console class is used to mimic the console object in web browsers
# to allow simple debugging to the stdout.
+
class Console
def log(*str)
puts str.join("\n")
nil
end
end
+ ##
# FileSystem is used to interact with the file system from the ruby
# version of opal. The methods on this class replace the default ones
# made available in the web browser.
+
class FileSystem
def initialize(context)
@context = context
end
@@ -180,10 +204,10 @@
nil
end
def ruby_file_contents(filename)
- Opal::Parser.new(File.read(filename)).parse!.generate_top
+ Opal::Parser.new.parse File.read(filename)
end
def wrap(content, filename)
code = "(function($rb, self, __FILE__) { #{content} });"
@context.eval code, filename