node_module 0.1.3 → 0.1.4
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.
- data/README.md +30 -30
- data/lib/node_module/opal_js_context.rb +23 -0
- data/lib/node_module/version.rb +1 -1
- data/lib/node_module.rb +7 -17
- data/node_module.gemspec +1 -0
- data/spec/lib/node_module/opal_js_context_spec.rb +44 -0
- data/spec/lib/node_module_spec.rb +18 -35
- data/spec/spec_helper.rb +1 -2
- metadata +23 -4
data/README.md
CHANGED
@@ -4,33 +4,23 @@
|
|
4
4
|
>
|
5
5
|
> — <cite>https://twitter.com/shit_hn_says/status/234856345579446272</cite>
|
6
6
|
|
7
|
-
|
8
|
-
things such as:
|
7
|
+
Dropping down to node.js has a number of problems:
|
9
8
|
|
10
|
-
1.
|
11
|
-
2.
|
9
|
+
1. You introduce a new, fairly large dependency to your codebase
|
10
|
+
2. You have to maintain certain stuff in a different language
|
11
|
+
3. You open yourself up to various debates about callbacks and promises
|
12
12
|
|
13
|
-
|
14
|
-
amount of dynamism and expressivity baked into the language compels
|
15
|
-
the programmer to only think of code in terms of objects and
|
16
|
-
orientation, and Dijkstra. This is way too high level.
|
13
|
+
On the other hand, it has a couple of major advantages over every other language ever:
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
implementation. Your code no longer explains to you what you want to
|
21
|
-
happen, but how it should do it.
|
15
|
+
1. It's web-scale
|
16
|
+
2. It's *web-scale*!
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
about what exactly your hardware is doing.
|
18
|
+
Wouldn't it be nice if you could drop down to Node... *implicitly*?
|
19
|
+
You wouldn't need to significantly change anything to fine-tune
|
20
|
+
portions of your app, right down to the individual method level.
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
suited to things such as:
|
31
|
-
|
32
|
-
1. Systems programming
|
33
|
-
2. Being web-scale
|
22
|
+
Enter `node_module`, which does just that. All you need to do is add the gem, and
|
23
|
+
tell it which methods you want to run as javascript instead of Ruby.
|
34
24
|
|
35
25
|
## How to install
|
36
26
|
|
@@ -63,6 +53,14 @@ class AbstractConcepts
|
|
63
53
|
(constants - [self.class]).map(&:remove_const)
|
64
54
|
end
|
65
55
|
|
56
|
+
def meaning_of_life
|
57
|
+
42
|
58
|
+
end
|
59
|
+
|
60
|
+
# run a specific method as javascript
|
61
|
+
node_module :meaning_of_life
|
62
|
+
|
63
|
+
# run everything after this point as javascript
|
66
64
|
node_module
|
67
65
|
|
68
66
|
def pythagorean_triplet?(a, b, c)
|
@@ -71,21 +69,23 @@ class AbstractConcepts
|
|
71
69
|
end
|
72
70
|
```
|
73
71
|
|
74
|
-
|
75
|
-
|
72
|
+
`node_module` behaves like the `public`, `private`, and `protected`
|
73
|
+
methods Ruby gives you. You can pass in specific methods as symbols,
|
74
|
+
or call it without any arguments to change every subsequently
|
75
|
+
defined method.
|
76
76
|
|
77
77
|
This is a ridiculous proof of concept, so there are a few issues...
|
78
78
|
|
79
79
|
## Current limitations
|
80
80
|
|
81
|
-
-
|
82
|
-
|
83
|
-
class they were defined in. (Although there's nothing preventing an entire class
|
84
|
-
being parsed as javascript in future).
|
81
|
+
- Sharing state between methods or across a class is unpredictable,
|
82
|
+
and will probably cause bad things to happen.
|
85
83
|
|
86
|
-
- It
|
84
|
+
- It's destructive, so you'll lose the body of the original
|
85
|
+
method. This means you can't yet switch a method between its Ruby
|
86
|
+
and Javascript versions.
|
87
87
|
|
88
|
-
- It
|
88
|
+
- It doesn't actually use Node yet
|
89
89
|
|
90
90
|
- It probably can't handle anything too clever.
|
91
91
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'v8'
|
2
|
+
require 'json'
|
3
|
+
require 'opal'
|
4
|
+
|
5
|
+
class NodeModule::OpalJsContext < V8::Context
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super do |ctx|
|
9
|
+
ctx.eval Opal::Builder.build('opal')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile(code)
|
14
|
+
eval Opal.parse(code)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run(name, args=[])
|
18
|
+
eval <<-JS
|
19
|
+
Opal.Object['$#{name}'].apply(Opal.Object, #{args.to_json})
|
20
|
+
JS
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/node_module/version.rb
CHANGED
data/lib/node_module.rb
CHANGED
@@ -1,28 +1,17 @@
|
|
1
1
|
require 'node_module/version'
|
2
2
|
require 'live_ast/to_ruby'
|
3
3
|
require 'live_ast/irb_spy' if defined?(IRB)
|
4
|
-
require 'opal'
|
5
|
-
require 'json'
|
6
|
-
require 'v8'
|
7
4
|
|
8
5
|
module NodeModule
|
9
6
|
|
7
|
+
autoload :OpalJsContext, 'node_module/opal_js_context'
|
8
|
+
|
10
9
|
def self.included(base)
|
11
10
|
base.extend ClassMethods
|
12
11
|
end
|
13
12
|
|
14
|
-
def self.
|
15
|
-
@ctx ||=
|
16
|
-
ctx.eval Opal::Builder.build('opal')
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.convert_method_to_javascript(fn)
|
21
|
-
NodeModule.js_context.eval Opal.parse(fn)
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.call_javascript_function(name, args = [])
|
25
|
-
NodeModule.js_context.eval "Opal.Object['$#{name}'].apply(this, #{args.to_json})"
|
13
|
+
def self.opal_js_context
|
14
|
+
@ctx ||= OpalJsContext.new
|
26
15
|
end
|
27
16
|
|
28
17
|
module ClassMethods
|
@@ -40,10 +29,11 @@ module NodeModule
|
|
40
29
|
def self.execute_methods_as_javascript!(methods, receiver)
|
41
30
|
methods.each do |name|
|
42
31
|
meth = receiver.instance_method(name).to_ruby
|
43
|
-
|
32
|
+
|
33
|
+
NodeModule.opal_js_context.compile(meth)
|
44
34
|
|
45
35
|
receiver.send :define_method, name do |*args|
|
46
|
-
NodeModule.
|
36
|
+
NodeModule.opal_js_context.run(__method__, args)
|
47
37
|
end
|
48
38
|
end
|
49
39
|
end
|
data/node_module.gemspec
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NodeModule::OpalJsContext do
|
4
|
+
|
5
|
+
subject { NodeModule::OpalJsContext.new }
|
6
|
+
|
7
|
+
let(:predicate_method) { "def equal?(a, b); a == b; end;" }
|
8
|
+
let(:bang_method) { "def boom!; 'BOOM!'; end;" }
|
9
|
+
let(:mixed_method) { "def boom?(a, b); boom! if a == b; end;" }
|
10
|
+
|
11
|
+
describe "#load" do
|
12
|
+
it "successfully turns Ruby into Opal-style Javascript" do
|
13
|
+
js = subject.compile(predicate_method)
|
14
|
+
js.to_s.must_match /function \(a, b\) \{\s+ return a\['\$=='\]\(b\);\s+\}/
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#run" do
|
19
|
+
before do
|
20
|
+
subject.compile(predicate_method)
|
21
|
+
subject.compile(bang_method)
|
22
|
+
subject.compile(mixed_method)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "handles Ruby style predicate methods" do
|
26
|
+
result = subject.run('equal?', [1, 1])
|
27
|
+
result.must_equal true
|
28
|
+
|
29
|
+
result = subject.run('equal?', [1, 2])
|
30
|
+
result.must_equal false
|
31
|
+
end
|
32
|
+
|
33
|
+
it "handles Ruby style bang methods" do
|
34
|
+
result = subject.run('boom!')
|
35
|
+
result.must_equal 'BOOM!'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can refer to previously defined methods from within a method" do
|
39
|
+
result = subject.run('boom?', [1, 1])
|
40
|
+
result.must_equal 'BOOM!'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe NodeModule do
|
3
|
+
describe NodeModule, "integration into other classes" do
|
4
4
|
|
5
|
-
class
|
5
|
+
class ExampleClass
|
6
6
|
include NodeModule
|
7
7
|
|
8
8
|
node_module
|
@@ -10,48 +10,31 @@ describe NodeModule do
|
|
10
10
|
def hello_you(*names)
|
11
11
|
"hello #{names.join(', ')}"
|
12
12
|
end
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
describe "integration" do
|
18
|
-
let(:test_class) { TestClass.new }
|
19
13
|
|
20
|
-
|
21
|
-
|
14
|
+
def goodbye_you(*names)
|
15
|
+
"goodbye #{names.join(', ')}"
|
22
16
|
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "#convert_method_to_javascript" do
|
26
|
-
let(:test_method) { "def equal?(a, b); a == b; end;" }
|
27
17
|
|
28
|
-
|
29
|
-
|
30
|
-
js.to_s.must_match /function \(a, b\) \{\s+ return a\['\$=='\]\(b\);\s+\}/
|
18
|
+
def equal?(a, b)
|
19
|
+
a == b
|
31
20
|
end
|
32
|
-
end
|
33
21
|
|
34
|
-
|
35
|
-
|
36
|
-
let(:bang_method) { "def boom!; 'BOOM!'; end;" }
|
37
|
-
|
38
|
-
before do
|
39
|
-
NodeModule.convert_method_to_javascript(predicate_method)
|
40
|
-
NodeModule.convert_method_to_javascript(bang_method)
|
22
|
+
def not_equal?(a, b)
|
23
|
+
! equal?(a, b)
|
41
24
|
end
|
25
|
+
end
|
42
26
|
|
43
|
-
|
44
|
-
result = NodeModule.call_javascript_function('equal?', [1, 1])
|
45
|
-
result.must_equal true
|
27
|
+
let(:example_class) { ExampleClass.new }
|
46
28
|
|
47
|
-
|
48
|
-
|
49
|
-
|
29
|
+
it "says 'hello' to all the people" do
|
30
|
+
example_class.hello_you("Sarah", "Jess").must_equal "hello Sarah, Jess"
|
31
|
+
end
|
50
32
|
|
51
|
-
|
52
|
-
|
53
|
-
result.must_equal 'BOOM!'
|
54
|
-
end
|
33
|
+
it "says 'goodbye' to all the people" do
|
34
|
+
example_class.goodbye_you("Tom", "Hayley").must_equal "goodbye Tom, Hayley"
|
55
35
|
end
|
56
36
|
|
37
|
+
it "returns true if 1 is not equal to 2" do
|
38
|
+
example_class.not_equal?(1, 2).must_equal true
|
39
|
+
end
|
57
40
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: node_module
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: live_ast
|
@@ -91,6 +91,22 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: minitest
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
94
110
|
description: Evaluate methods in Ruby as Javascript instead
|
95
111
|
email:
|
96
112
|
- lee@new-bamboo.co.uk
|
@@ -105,8 +121,10 @@ files:
|
|
105
121
|
- README.md
|
106
122
|
- Rakefile
|
107
123
|
- lib/node_module.rb
|
124
|
+
- lib/node_module/opal_js_context.rb
|
108
125
|
- lib/node_module/version.rb
|
109
126
|
- node_module.gemspec
|
127
|
+
- spec/lib/node_module/opal_js_context_spec.rb
|
110
128
|
- spec/lib/node_module_spec.rb
|
111
129
|
- spec/spec_helper.rb
|
112
130
|
homepage: http://github.com/leemachin/node_module
|
@@ -124,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
124
142
|
version: '0'
|
125
143
|
segments:
|
126
144
|
- 0
|
127
|
-
hash: -
|
145
|
+
hash: -2723743550254407902
|
128
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
147
|
none: false
|
130
148
|
requirements:
|
@@ -133,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
151
|
version: '0'
|
134
152
|
segments:
|
135
153
|
- 0
|
136
|
-
hash: -
|
154
|
+
hash: -2723743550254407902
|
137
155
|
requirements: []
|
138
156
|
rubyforge_project:
|
139
157
|
rubygems_version: 1.8.23
|
@@ -141,5 +159,6 @@ signing_key:
|
|
141
159
|
specification_version: 3
|
142
160
|
summary: Get really close to the metal in Ruby
|
143
161
|
test_files:
|
162
|
+
- spec/lib/node_module/opal_js_context_spec.rb
|
144
163
|
- spec/lib/node_module_spec.rb
|
145
164
|
- spec/spec_helper.rb
|