runjs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8dfa257866a324091b0aa01a4e628ad4adce24c9
4
+ data.tar.gz: 8ffafee810cb03f6da1738c056a9f3c78594986e
5
+ SHA512:
6
+ metadata.gz: 883f31c273ca2e28d6078eaa972bbbbab42bf47ef92a4822d4fa9f4963c4cd3a9dd7c11eb52593e1c2a9d443a8b7b7c153be96def9b85a44e55eec09caa4db68
7
+ data.tar.gz: f72abb482bdd5ebe8095c6d18184f0d866bfca7fcdc9ff4ddce358555fa216fcdc80cb28fc012011a8fe8f60ccafcfef4bfb73dbd4097f4a8cd42136c26f941b
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 AS Harbitz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,94 @@
1
+ # RunJS
2
+
3
+ With RunJS you can run JavaScript code from Ruby.
4
+
5
+ ```ruby
6
+ require 'runjs'
7
+ puts RunJS.run('return "Hello World";')
8
+ ```
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ $ gem install runjs
14
+ ```
15
+
16
+ RunJS depends on the `json` library. Starting with Ruby version 1.9 this is included, but on Ruby 1.8 you have to install the `json` gem. If this causes any problems, install the `json_pure` gem instead.
17
+
18
+ ```bash
19
+ $ gem install json || gem install json_pure
20
+ ```
21
+
22
+ ## JavaScript Runtimes
23
+
24
+ #### Supported runtimes
25
+
26
+ * [TheRubyRacer](https://github.com/cowboyd/therubyracer)
27
+ * [JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore) included with OS X
28
+ * [V8](http://code.google.com/p/v8/)
29
+ * [Node](http://nodejs.org)
30
+ * [JScript](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) on Windows
31
+
32
+ RunJS will automatically select the first available runtime from the list above.
33
+
34
+ #### Deprecated runtimes
35
+
36
+ * [TheRubyRhino](https://github.com/cowboyd/therubyrhino)
37
+ * [SpiderMonkey](http://www.mozilla.org/js/spidermonkey)
38
+
39
+ To use TheRubyRhino or SpiderMonkey you have to set the runtime manually.
40
+
41
+ #### Set the runtime
42
+
43
+ You can control which runtime RunJS uses in your Ruby code.
44
+
45
+ ```ruby
46
+ RunJS.runtime = RunJS::Node
47
+ ```
48
+
49
+ Or with the RUNJS_RUNTIME environment variable.
50
+
51
+ ```bash
52
+ $ export RUNJS_RUNTIME=Node
53
+ ```
54
+
55
+ <!-- ## API -->
56
+
57
+ ## Examples
58
+
59
+ ```ruby
60
+ require 'runjs'
61
+
62
+ RunJS.run('return 2 + 2;') # => 4
63
+ RunJS.call('Math.sqrt', 25) # => 5
64
+ RunJS.apply('Array.prototype.slice', '"cat"') # => ["c", "a", "t"]
65
+ ```
66
+
67
+ #### Compiling CoffeeScript
68
+
69
+ ```ruby
70
+ require 'runjs'
71
+ require 'open-uri'
72
+
73
+ url = 'http://jashkenas.github.com/coffee-script/extras/coffee-script.js'
74
+ compiler = open(url).read
75
+
76
+ coffee = 'alert yes'
77
+ options = { header: true, bare: true }
78
+ RunJS.context(compiler).apply('CoffeeScript.compile', 'CoffeeScript', coffee, options)
79
+
80
+ # => // Generated by CoffeeScript 1.6.3
81
+ # => alert(true);
82
+ ```
83
+
84
+ <!-- ## RunJS vs. ExecJS -->
85
+
86
+ ## Credits
87
+
88
+ Thanks to [Sam Stephenson](https://github.com/sstephenson), [Joshua Peek](https://github.com/josh) and the other contributors to [ExecJS](https://github.com/sstephenson/execjs). Although none of the code is directly copied, the API and code structure is almost identical. While coding, the ExecJS code was consulted all the time, and RunJS ended up like a rewrite of ExecJS.
89
+
90
+ ## License
91
+
92
+ Copyright (c) 2013 AS Harbitz.
93
+
94
+ RunJS is released under the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,32 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
2
+
3
+ require 'runjs'
4
+ require 'rake/testtask'
5
+
6
+ desc 'Run tests for all the runtimes'
7
+ task :test do
8
+ RunJS::RUNTIMES.each { |runtime| run_tests(runtime) }
9
+ end
10
+
11
+ RunJS::RUNTIMES.each do |runtime|
12
+ desc "Run tests for #{runtime.class_name}"
13
+ task "test:#{runtime.class_name.downcase}" do
14
+ run_tests(runtime)
15
+ end
16
+ end
17
+
18
+ Rake::TestTask.new 'test:runtime' do |test|
19
+ test.libs << 'test'
20
+ test.pattern = 'test/*_test.rb'
21
+ test.warning = true
22
+ end
23
+ Rake::Task['test:runtime'].clear_comments
24
+ Rake::Task['test:runtime'].comment = 'Run tests for the default runtime'
25
+
26
+ def run_tests(runtime)
27
+ ENV['RUNJS_RUNTIME'] = runtime.class_name
28
+ Rake::Task['test:runtime'].execute
29
+ rescue SignalException
30
+ raise unless RUBY_PLATFORM == 'java'
31
+ rescue
32
+ end
@@ -0,0 +1,62 @@
1
+ require 'runjs/encoding'
2
+ require 'runjs/error'
3
+ require 'runjs/os'
4
+ require 'runjs/runtime'
5
+ require 'runjs/system_runtime'
6
+
7
+ require 'runjs/runtimes/java_script_core'
8
+ require 'runjs/runtimes/jscript'
9
+ require 'runjs/runtimes/node'
10
+ require 'runjs/runtimes/spider_monkey'
11
+ require 'runjs/runtimes/the_ruby_racer'
12
+ require 'runjs/runtimes/the_ruby_rhino'
13
+ require 'runjs/runtimes/v8'
14
+
15
+ module RunJS
16
+
17
+ VERSION = '0.1.0'
18
+
19
+ RUNTIMES = [TheRubyRacer, JavaScriptCore, V8, D8, Node, JScript,
20
+ TheRubyRhino, SpiderMonkey]
21
+
22
+ def self.runtime=(runtime)
23
+ raise RuntimeUnavailable, runtime unless runtime.available?
24
+ @runtime = runtime
25
+ end
26
+
27
+ def self.runtime
28
+ @runtime ||= from_environment(ENV['RUNJS_RUNTIME']) ||
29
+ RUNTIMES.reject(&:deprecated?).find(&:available?) ||
30
+ raise(RuntimeUnavailable)
31
+ end
32
+
33
+ def self.context(js)
34
+ runtime.new.context(js)
35
+ end
36
+
37
+ def self.run(js)
38
+ runtime.new.run(js)
39
+ end
40
+
41
+ def self.call(function, *args)
42
+ runtime.new.call(function, *args)
43
+ end
44
+
45
+ def self.apply(function, this, *args)
46
+ runtime.new.apply(function, this, *args)
47
+ end
48
+
49
+ def self.eval(js)
50
+ runtime.new.eval(js)
51
+ end
52
+
53
+ private
54
+
55
+ def self.from_environment(name)
56
+ name = (name || '').sub(/^RunJS::/, '')
57
+ self.runtime = const_get(name) unless name.empty?
58
+ end
59
+
60
+ private_class_method(:from_environment)
61
+
62
+ end
@@ -0,0 +1,24 @@
1
+ module RunJS
2
+
3
+ module Encoding
4
+
5
+ if ''.respond_to?(:encode)
6
+
7
+ def encode(text, to, from = nil)
8
+ text.encode(to, from)
9
+ end
10
+
11
+ else
12
+
13
+ require 'iconv'
14
+
15
+ def encode(text, to, from = nil)
16
+ return text unless from
17
+ Iconv.conv(to, from, text)
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,59 @@
1
+ module RunJS
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class CompileError < Error
7
+
8
+ attr_reader :source
9
+
10
+ def initialize(message, source)
11
+ @source = source
12
+ super(message)
13
+ end
14
+
15
+ end
16
+
17
+ class JavaScriptError < Error
18
+
19
+ attr_reader :error
20
+ attr_reader :source
21
+
22
+ def initialize(error, source)
23
+ @error = error
24
+ @source = source
25
+ super(get_message)
26
+ end
27
+
28
+ def [](key)
29
+ @error[key].nil? ? @error[key.to_s] : @error[key]
30
+ rescue
31
+ nil
32
+ end
33
+
34
+ private
35
+
36
+ def get_message
37
+ return '' if @error.respond_to?(:empty?) && @error.empty?
38
+ message = [self['name'], self['message']].compact
39
+ message.delete('')
40
+ message.empty? ? @error.to_s : message.join(': ')
41
+ end
42
+
43
+ end
44
+
45
+ class RuntimeUnavailable < Error
46
+
47
+ def initialize(runtime = nil)
48
+ if runtime
49
+ super('Could not find the runtime: ' + runtime.class_name)
50
+ else
51
+ super('Could not find a JavaScript runtime. ' +
52
+ "The supported runtimes are:\n" +
53
+ RUNTIMES.reject(&:deprecated?).map(&:class_name).join(', '))
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,80 @@
1
+ require 'tempfile'
2
+ require 'rbconfig'
3
+ require 'shellwords'
4
+
5
+ module RunJS
6
+
7
+ module OS
8
+
9
+ def self.which(cmd)
10
+ cmd += extension(cmd)
11
+ return cmd if executable?(cmd)
12
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
13
+ path = File.join(path, cmd)
14
+ return path if executable?(path)
15
+ end
16
+ nil
17
+ end
18
+
19
+ def self.write_tempfile(text, &block)
20
+ file = Tempfile.new(['runjs', '.js'])
21
+ file.binmode # Required on Windows when writing UTF-16
22
+ file.write(text)
23
+ file.close
24
+ yield file.path
25
+ ensure
26
+ file.close!
27
+ end
28
+
29
+ if RUBY_VERSION < '1.9' || RUBY_PLATFORM == 'java'
30
+
31
+ extend Encoding
32
+
33
+ def self.popen(cmd, options = {})
34
+ cmd = shell_escape(cmd) << ' 2>&1'
35
+ result = IO.popen(cmd) { |io| io.read }
36
+ encode(result, 'UTF-8', options[:external_encoding])
37
+ end
38
+
39
+ else
40
+
41
+ def self.popen(cmd, options = {})
42
+ cmd = cmd.dup.push({ :err => [:child, :out] }) # Unsupported by JRuby
43
+ options[:internal_encoding] ||= 'UTF-8'
44
+ options[:external_encoding] ||= 'UTF-8'
45
+ IO.popen(cmd, options) { |io| io.read }
46
+ end
47
+
48
+ end
49
+
50
+ def self.success?
51
+ $?.success?
52
+ end
53
+
54
+ private
55
+
56
+ def self.extension(cmd)
57
+ (windows? && File.extname(cmd).empty?) ? '.exe' : ''
58
+ end
59
+
60
+ def self.windows?
61
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
62
+ end
63
+
64
+ def self.executable?(cmd)
65
+ File.file?(cmd) && File.executable?(cmd)
66
+ end
67
+
68
+ def self.shell_escape(cmd)
69
+ if windows?
70
+ cmd.map { |arg| '"' + arg.gsub('"', '""') + '"' }.join(' ')
71
+ else
72
+ Shellwords.join(cmd)
73
+ end
74
+ end
75
+
76
+ private_class_method(:extension, :windows?, :executable?, :shell_escape)
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,65 @@
1
+ begin
2
+ require 'json'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'json'
6
+ end
7
+
8
+ module RunJS
9
+
10
+ class Runtime
11
+
12
+ def self.deprecated?
13
+ @deprecated ||= false
14
+ end
15
+
16
+ def self.available?
17
+ false
18
+ end
19
+
20
+ def self.class_name
21
+ name.split('::').last
22
+ end
23
+
24
+ def context(js)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def run(js)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def call(function, *args)
33
+ apply(function, 'this', *args)
34
+ end
35
+
36
+ def apply(function, this, *args)
37
+ this = 'null' if this.nil?
38
+ args = args.to_json
39
+ run("return #{function}.apply(#{this}, #{args});")
40
+ end
41
+
42
+ def eval(js)
43
+ js = js.to_json
44
+ run("return eval(#{js});")
45
+ end
46
+
47
+ private
48
+
49
+ include Encoding
50
+
51
+ RUNNER = File.read(File.expand_path('../support/runner.js', __FILE__))
52
+
53
+ def merge_runner(js)
54
+ RUNNER % js
55
+ end
56
+
57
+ def parse_json(result, js)
58
+ result, ok = JSON.parse(result)
59
+ raise JavaScriptError.new(result, js) unless ok
60
+ result
61
+ end
62
+
63
+ end
64
+
65
+ end