# # env.rb # vienna # # Created by Adam Beynon. # Copyright 2010 Adam Beynon. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # module Opal # Env is an opal environment. An instance of the ruby "virtual machine" that # holds the context for running ruby (through javascript). An ENV loads the # correct context, boots the runtime, and ties everything together conecting # the opal runtime and ruby classes that provide a layer for communicating # back and forth between the two. Any time opal is used to run ruby code # "server side", it will be through an instance of this class. class Environment # Path to system opals OPALS_PATH = File.join Vienna::PATH, 'opals' def initialize(args) begin require 'rubygems' require 'v8' rescue Exception abort "therubyracer not available. Install it with: sudo gem install therubyracer" end # puts "making new environment" @context = V8::Context.new load_runtime # puts "args are: #{args.inspect}" if args.length == 1 file = args[0] # puts "need to run #{file}" # puts File.read(file) if File.exist? file load_required_file file args.clear else abort "Cannot find opal file #{args[0]}" end else start end end def load_runtime @context['console'] = Opal::Environment::Console.new self @context['__opal_fs_access'] = Opal::Environment::FS.new self runtime_files = %w(pre_opal opal server_side debug post_opal) js_str = [] runtime_files.each do |file| str= File.read File.join(OPALS_PATH, 'runtime', 'runtime', "#{file}.js") js_str << str end js_eval js_str.join # need to load libs (kernel, module first, then all others) rb_sources = Dir.glob(File.join(OPALS_PATH, 'runtime', 'lib', '**', '*.rb')) # we want kernel first, then module %w(kernel module).reverse.each do |order| rb_sources.unshift rb_sources.select { |item| /#{Regexp.escape order}\.rb$/.match item }.first end rb_sources.uniq! rb_sources.each do |src| # puts src res = Vienna::RubyParser.new(src, File.read(src)).build! eval_str = "opal.load_raw_file('#{src}', #{res});" js_eval eval_str # break end end # Start accepting user input and compiling it def start while true '>> '.display gets.each do |e| puts("=> " + ruby_eval(e.to_s)) end end end # Evaluate the given javascript normally in context def js_eval(str) @context.eval(str).to_s end def load_required_file(path) # puts "loading require file! #{path}" parser = Vienna::RubyParser.new(path, File.read(path)) res = parser.build! # puts "a" # puts res @context.eval("opal.entry_point((function() {return (#{res}).apply(opal.top_self, ['#{path}'])}));").to_s # puts "b" true end # Evaluate the given string in the context def ruby_eval(str) parser = Vienna::RubyParser.new("(opal)", str, :iseq_type => :main) res = parser.build! @context.eval("opal.entry_point((function() {return (#{res}).apply(opal.top_self, ['(opal)']).$inspect()}));").to_s end end end