execjs-xtrn 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4abcfd3f47329826a53b863835a51592f1dc1030
4
- data.tar.gz: e96571ef15e4fe0b91a86a2e461cbdef62e42f29
3
+ metadata.gz: 8754e3aa4bbca96de99f7b970259186ab5791bd0
4
+ data.tar.gz: 3cbcbdba3d22e45da939f7d52b94c449bd77a2d1
5
5
  SHA512:
6
- metadata.gz: 2842042b3e8091e0caa59f5943635579c673c291d11cd831afb42e08797b26b8a55045c79c72a5e7b886a8ba3037fcf10b42b92c5a37b1faaadcbea8d08cb672
7
- data.tar.gz: 6328d3e668706b3282a4050ff614050254a0c20f9923219a8d56ff53631f17fdf6776bb4f7496b0e9585f5c819848a234087344353cf99b071ba6cac8f404f4c
6
+ metadata.gz: 0d29c2822c4e601d959ab6330d605bfbd2af5633c75dd4af16c31ecb894e40b4231fdf9ff51f15ec80d270175fb70e916a1fff86259711e772b9cfe0b49ddc89
7
+ data.tar.gz: 2b08bbcb400b3da6a9376351ce54b5c04f9dd4ceb5b464df03e93d7bebbe4eaf34d5c75016791bdaeac7212b67b83c9f0303ca731d370e5d70617ee85fa0842f
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.1
4
- - 2.0.0
3
+ - '2.2'
4
+ - '2.1'
5
+ - '2.0'
5
6
  - 1.9.3
6
7
  - 1.9.2
7
8
  before_install:
data/FarMenu.ini CHANGED
@@ -1,10 +1,11 @@
1
- i: Bundle install
2
- bundle install -new_console:c
3
- n: Npm install
4
- bundle exec rake npm -new_console:c
5
- --:
6
- t: Run tests
7
- bundle exec rake -new_console:c
8
- --:
9
- b: Build
10
- bundle exec rake build -new_console:c
1
+ I: Install dependencies
2
+ bundle install
3
+ bundle exec rake npm
4
+ --:
5
+ T: Run tests
6
+ bundle exec rake -new_console:c
7
+ C: Console
8
+ bundle console -new_console
9
+ --:
10
+ B: Build
11
+ bundle exec rake build -new_console:c
data/README.md CHANGED
@@ -39,6 +39,8 @@ ExecJS::Xtrn uses two external JavaScript runners:
39
39
  - Simple (1 execution context = 1 external process)
40
40
  - Nvm (all execution contexts share single external process using [vm API](http://nodejs.org/api/vm.html))
41
41
 
42
+ Nvm engine has nothing common with [nvm](https://github.com/creationix/nvm).
43
+
42
44
  So, there exist *four* engines:
43
45
 
44
46
  * Engine - absctract engine (smart enough to execute blank lines)
@@ -71,28 +73,66 @@ In general one should create instance of an Engine and then feed it with JavaScr
71
73
  ```ruby
72
74
  ctx=ExecJS::Xtrn::Wsh.new
73
75
  ctx.exec 'fact = function(n){return n>1 ? n*fact(n-1) : 1}'
74
- puts "10!=#{ctx.call 'fact', 10}"
76
+ puts "10! = #{ctx.call 'fact', 10}"
75
77
  ```
76
- Every execution context has three methods:
77
- * exec('`code`') - executes arbitrary JavaScript code. To get result `return` must be called.
78
- * eval('`expression`') - evaluate JavaScript expression. `return` is not needed
78
+ Every execution context has four methods:
79
+ * exec(`code`) - executes arbitrary JavaScript code. To get result `return` must be called
80
+ * load(`code`) or load(`path`) - exec that can load its code from file
81
+ * eval(`expression`) - evaluate JavaScript expression. `return` is not needed
79
82
  * call(`function`, arguments...) - special form of eval for function call
80
83
 
81
- Engine class also has exec and eval methods, they just create brand new execution context,
82
- pass argument to it, destroy that context and return its result. Using these class methods
83
- is not recommended, since it's just what ExecJS does (except for Nvm engine).
84
+ There are `exec` and `eval` methods in Engine class,
85
+ they just create brand new execution context,
86
+ pass argument to it, destroy that context and return its result.
87
+ Using these class methods is not recommended, since it's just what ExecJS does
88
+ (except for Nvm engine).
84
89
 
85
- Engine class also has compile method that combines `new` and `exec` and returns execution context.
90
+ Engine class also has `compile` method that combines `new` and `exec`
91
+ and returns execution context.
86
92
  This is how ExecJS is used in most cases.
87
93
 
88
94
  ```ruby
89
95
  ctx=ExecJS::Xtrn::Wsh.compile 'fact = function(n){return n>1 ? n*fact(n-1) : 1}'
90
- puts "10!=#{ctx.call 'fact', 10}"
96
+ puts "10! = #{ctx.call 'fact', 10}"
91
97
  ```
98
+ And `load` methods is likewise combination of `new`+`load`,
99
+ it is `compile` that can load its code from file.
100
+
101
+ `load` method (class' or instance's) detects whether its argument
102
+ is code or path by first symbols of it. So, start path with `/`, `./`
103
+ or `../` (but not from `//`). On Windows `\` and `C:` can be also used.
92
104
 
93
- And finally ExecJS::Xtrn patches ExecJS and installs those 3 class methods (exec, eval, compile) in it.
105
+ Finally ExecJS::Xtrn patches ExecJS and installs those 4 class methods
106
+ (`exec`, `eval`, `compile` and `load`) in it.
94
107
  So, `ExecJS.compile` is `ExecJS::Xtrn::Nvm.compile` if Nvm engine is available.
95
108
 
109
+ ## Preloading
110
+
111
+ Sometimes it's neccesary to initialize all execution contexts before passing
112
+ code to them.
113
+ For instance, add some standard JavaScript methods missing in Wsh engine.
114
+
115
+ It can be done by setting Preload constant on engine class.
116
+
117
+ ```ruby
118
+ ExecJS::Xtrn::Wsh::Preload='./lib/js/map.js'
119
+ ```
120
+ or maybe
121
+
122
+ ```ruby
123
+ ExecJS::Xtrn::Wsh::Preload=[
124
+ './lib/js/map.js',
125
+ './lib/js/keys.js',
126
+ 'console={log: function(){WScript.Echo([].slice.call(arguments).join(" "))}}'
127
+ ]
128
+ # Yes, console.log is avaialable in Wsh now!
129
+ # And yes, console.log can be used in ExecJS::Xtrn!
130
+ ```
131
+ You can add preload scripts to any engine or to Engine base class.
132
+ They will be loaded according to inheritance:
133
+ Engine::Preload will be used by all engines,
134
+ Node::Preload is for Node and Nvm, while Nvm::Preload is for Nvm only.
135
+
96
136
  ## Overriding ExecJS
97
137
 
98
138
  Sometimes ExecJS is required after ExecJS::Xtrn. In that case you can call ExecJS::Xtrn.init and
@@ -130,6 +170,15 @@ s.stats
130
170
  ```
131
171
  but c (and m, x) fields are omitted there.
132
172
 
173
+ If ExecJS::Xtrn detects it is run under Ruby on Rails,
174
+ it installs additional path `/rails/jsx' to display its statistics
175
+ (you can see that route in sextant, for example).
176
+
177
+ It is one more reason not to use ExecJS::Xtrn in production mode ;-)
178
+
179
+ By default statistics is output in YAML format, but you can
180
+ get `/rails/jsx.json` or `/rails/jsx.html`.
181
+
133
182
  ## Compatibilty
134
183
 
135
184
  Not every JavaScript code behaves identically in ExecJS and ExecJS::Xtrn. In most cases it depends on how
@@ -148,7 +197,8 @@ The following packages have been tested to run under ExecJS::Xtrn out-of-box:
148
197
 
149
198
  CoffeeScript since v1.9.0 introduces new incompatibility:
150
199
  it uses `Object.create` that is missing from WSH.
151
- To fix it, `Object.create` was manually defined in ExecJS::Xtrn::Wsh.
200
+ To fix it, `Object.create` was manually defined in ExecJS::Xtrn::Wsh
201
+ (sort of [ExecJS::Xtrn::Wsh::Preload](#preloading))
152
202
 
153
203
  ## Testing
154
204
 
@@ -48,7 +48,7 @@ function oCreate()
48
48
  if(Object.create) return
49
49
  Object.create=function(proto)
50
50
  {
51
- f=function(){}
51
+ function f(){}
52
52
  f.prototype=proto
53
53
  return new f
54
54
  }
data/lib/execjs/xtrn.rb CHANGED
@@ -1,4 +1,4 @@
1
- %w(wsh nvm).each{|x| require_relative "xtrn/#{x}"}
1
+ require_relative "xtrn/rails"
2
2
 
3
3
  module ExecJS::Xtrn
4
4
 
@@ -19,6 +19,13 @@ class ExecJS::Xtrn::Engine
19
19
  result['ok']
20
20
  end
21
21
 
22
+ PathX=[/^[.]{1,2}\/|^\/(?![\/*])/]
23
+ PathX << /^[.]{0,2}\\|^\w:./ if Gem.win_platform?
24
+
25
+ def load code
26
+ exec PathX.find{|re| re.match code} ? File.read(code) : code
27
+ end
28
+
22
29
  def eval(code)
23
30
  return if (code=code.to_s.strip).length==0
24
31
  exec "return eval(#{JSON.generate([code])[1...-1]})"
@@ -40,6 +47,10 @@ class ExecJS::Xtrn::Engine
40
47
  new.tap{|ctx| ctx.exec code}
41
48
  end
42
49
 
50
+ def self.load code
51
+ new.tap{|ctx| ctx.load code}
52
+ end
53
+
43
54
  def self.stats
44
55
  (@stats||{}).dup
45
56
  end
@@ -60,4 +71,11 @@ class ExecJS::Xtrn::Engine
60
71
  child
61
72
  end
62
73
 
74
+ def initialize
75
+ self.class.ancestors.reverse.map do |m|
76
+ list=m.const_get 'Preload', false rescue nil
77
+ list ? Array===list ? list : [list] : []
78
+ end
79
+ .flatten.uniq.each{|code| load code}
80
+ end
63
81
  end
@@ -0,0 +1,2 @@
1
+ require_relative 'wsh'
2
+ require_relative 'routing' if defined? Rails::Application
@@ -0,0 +1,3 @@
1
+ Rails::application.routes.draw do
2
+ get "/rails/jsx" => ExecJS::Xtrn::Rack
3
+ end
@@ -0,0 +1,45 @@
1
+ module ExecJS::Xtrn::Rack
2
+ Formats=YAML.load <<-EOY
3
+ -:
4
+ mime: text/x-yaml
5
+ dump: YAML
6
+ json:
7
+ mime: appication/json
8
+ dump: JSON
9
+ html:
10
+ mime: text/html
11
+ dump: self
12
+ EOY
13
+
14
+ Formats.each {|k, v| v['dump']=instance_eval v['dump']}
15
+
16
+ def self.stats
17
+ ExecJS::Xtrn.stats.as_json
18
+ end
19
+
20
+ def self.call req
21
+ f=Formats[req['action_dispatch.request.path_parameters'][:format]] ||
22
+ Formats['-']
23
+ [
24
+ 200,
25
+ {"Content-Type"=> f['mime']},
26
+ [f['dump'].dump(stats)],
27
+ ]
28
+ end
29
+
30
+ # Dump as HTML
31
+ def self.dump s
32
+ '<ul>'+
33
+ s.map do |k, v|
34
+ "<li><b>#{k}</b>#{Hash===v ? dump(v) : ": #{v}"}</li>"
35
+ end
36
+ .join('')+'</ul>'
37
+ end
38
+ end
39
+
40
+ class Rails::Application
41
+ initializer :execjs_xtrn_stats do
42
+ Rails.application.routes_reloader.paths <<
43
+ File.expand_path('../routes.rb', __FILE__)
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  module ExecJS
2
2
  module Xtrn
3
- VERSION = "1.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- require_relative 'engine'
1
+ require_relative 'nvm'
2
2
 
3
3
  class ExecJS::Xtrn::Wsh < ExecJS::Xtrn::Engine
4
4
 
data/test/engine.rb CHANGED
@@ -6,6 +6,8 @@ class TestEngine < Minitest::Test
6
6
 
7
7
  Spawn=5
8
8
  Engines=M::Engines
9
+ Engines.each{|e| e::Preload=[]}
10
+ M::Engine::Preload=[]
9
11
 
10
12
  def shag_methods
11
13
  refute @engine.exec <<-EOJ
@@ -17,6 +19,12 @@ class TestEngine < Minitest::Test
17
19
  assert_equal 89, @engine.eval('fib(10)')
18
20
  assert_equal 8, @engine.call('fib', 5)
19
21
  assert_equal 79, @engine.call('Math.max', 44, 27, 79, 73, 42, 4, 23, 24, 36, 13)
22
+
23
+ assert_raises(M::Error){ @engine.eval '_load' }
24
+ @engine.load File.expand_path '../load.js', __FILE__
25
+ assert_equal ({}), @engine.eval('_load')
26
+ @engine.load '_load.a=108'
27
+ assert_equal ({"a"=>108}), @engine.eval('_load')
20
28
  end
21
29
 
22
30
  def shag_vars
@@ -62,6 +70,29 @@ class TestEngine < Minitest::Test
62
70
  assert_equal 6, x.call('inc', 5)
63
71
  end
64
72
 
73
+ def klas_load
74
+ z=@class.load File.expand_path '../load.js', __FILE__
75
+ assert_equal ({}), z.eval('_load')
76
+ end
77
+
78
+ def klas_preload
79
+ res=@class.name[-1]
80
+ res='em' if 'm'==res
81
+
82
+ Spawn.times do
83
+ begin
84
+ Engines.shuffle.each{|e| e::Preload << "_preload.#{e.name[-1]}=1"}
85
+ M::Engine::Preload << '!function(){this._preload={}}()'
86
+
87
+ assert_equal res, @class.eval('_preload').keys*''
88
+
89
+ ensure
90
+ Engines.each{|e| e::Preload.clear}
91
+ M::Engine::Preload.clear
92
+ end
93
+ end
94
+ end
95
+
65
96
  def engines
66
97
  (1..Spawn).map do
67
98
  Engines.map{|k| k::Valid ? k.compile : nil }
data/test/load.js ADDED
@@ -0,0 +1,5 @@
1
+ // Test .load method
2
+ !function()
3
+ {
4
+ this._load={}
5
+ }()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: execjs-xtrn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stas Ukolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-20 00:00:00.000000000 Z
11
+ date: 2015-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -96,6 +96,8 @@ files:
96
96
  - Rakefile
97
97
  - execjs-xtrn.gemspec
98
98
  - lib/execjs/node/index.js
99
+ - lib/execjs/node/node_modules/split/index.js
100
+ - lib/execjs/node/node_modules/through/index.js
99
101
  - lib/execjs/node/package.json
100
102
  - lib/execjs/wsh/json2.js
101
103
  - lib/execjs/wsh/repl.js
@@ -104,15 +106,17 @@ files:
104
106
  - lib/execjs/xtrn/engine.rb
105
107
  - lib/execjs/xtrn/node.rb
106
108
  - lib/execjs/xtrn/nvm.rb
109
+ - lib/execjs/xtrn/rails.rb
110
+ - lib/execjs/xtrn/routes.rb
111
+ - lib/execjs/xtrn/routing.rb
107
112
  - lib/execjs/xtrn/version.rb
108
113
  - lib/execjs/xtrn/wsh.rb
109
114
  - test/child.rb
110
115
  - test/engine.rb
116
+ - test/load.js
111
117
  - test/nvm.rb
112
118
  - test/shagi.rb
113
119
  - test/top.rb
114
- - lib/execjs/node/node_modules/split/index.js
115
- - lib/execjs/node/node_modules/through/index.js
116
120
  homepage: https://github.com/ukoloff/execjs-xtrn
117
121
  licenses:
118
122
  - MIT
@@ -133,13 +137,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
137
  version: '0'
134
138
  requirements: []
135
139
  rubyforge_project:
136
- rubygems_version: 2.0.14
140
+ rubygems_version: 2.4.6
137
141
  signing_key:
138
142
  specification_version: 4
139
143
  summary: 'Proof-of-concept: make ExecJS fast even without therubyracer'
140
144
  test_files:
141
145
  - test/child.rb
142
146
  - test/engine.rb
147
+ - test/load.js
143
148
  - test/nvm.rb
144
149
  - test/shagi.rb
145
150
  - test/top.rb