node_module 0.1.4 → 0.2.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3733f5f0dd05b4473cb33699578a943e1c69079b
4
+ data.tar.gz: 398599f46b2ca163d65dc4d82c56cb37e9b12530
5
+ SHA512:
6
+ metadata.gz: 6fafb546557516ff3419fb84d2aa81de3f3d5e673ac1196e9e9cc313904f57497b242ceba9cd536eff90023f3f8bd034eeba0925b9f13e68b89463db6e4b9bac
7
+ data.tar.gz: adf184d471553503ff448413479119783108277f09060adb13d48e6ea32398c55cd8ada72abc61f838e2d58414a4fb94c1fed5fdc6a7cf00ebe1fd85805afbe3
@@ -1 +1 @@
1
- 1.9.3
1
+ 2.1.0
data/README.md CHANGED
@@ -15,12 +15,10 @@ On the other hand, it has a couple of major advantages over every other language
15
15
  1. It's web-scale
16
16
  2. It's *web-scale*!
17
17
 
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.
18
+ Wouldn't it be nice if you could drop down to Node... *implicitly*? You wouldn't need to significantly change anything to fine-tune portions of your app, right down to the individual method level.
21
19
 
22
20
  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.
21
+ tell it which methods or classes you want to run as JavaScript instead of Ruby.
24
22
 
25
23
  ## How to install
26
24
 
@@ -38,6 +36,7 @@ gem install node_module
38
36
 
39
37
  ## How to use
40
38
 
39
+ ### Turn certain methods into JavaScript
41
40
  ```ruby
42
41
  require 'node_module'
43
42
 
@@ -57,10 +56,10 @@ class AbstractConcepts
57
56
  42
58
57
  end
59
58
 
60
- # run a specific method as javascript
59
+ # run a specific method as JavaScript
61
60
  node_module :meaning_of_life
62
61
 
63
- # run everything after this point as javascript
62
+ # run everything after this point as JavaScript
64
63
  node_module
65
64
 
66
65
  def pythagorean_triplet?(a, b, c)
@@ -69,23 +68,57 @@ class AbstractConcepts
69
68
  end
70
69
  ```
71
70
 
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.
71
+ `node_module` behaves like the `public`, `private`, and `protected` methods Ruby gives you. You can pass in specific methods as symbols, or call it without any arguments to change every subsequently defined method.
72
+
73
+ If you're using Ruby 2.1 you can also turn a single method into JS like this:
74
+
75
+ ```ruby
76
+ node_module def method
77
+ # stuff
78
+ end
79
+ ```
80
+
81
+ ### Turn an *entire class* into JavaScript
82
+
83
+ Your mileage may vary with this one. Use it at your own risk.
84
+
85
+ ```ruby
86
+ require 'node_module'
87
+
88
+ class MentalState < NodeModule::Compiled
89
+
90
+ def initialize(mental_state)
91
+ @mental_state = mental_state
92
+ end
93
+
94
+ def happy?
95
+ @mental_state == "happy"
96
+ end
97
+
98
+ def sad?
99
+ @mental_state == "sad"
100
+ end
101
+
102
+ def utterly_fucking_bonkers?
103
+ true
104
+ end
105
+
106
+ end
107
+ ```
108
+
109
+ Note that you might have a lot of difficulty getting classes to talk to each
110
+ other, because of the way objects are scoped when executing methods.
76
111
 
77
- This is a ridiculous proof of concept, so there are a few issues...
78
112
 
79
113
  ## Current limitations
80
114
 
81
- - Sharing state between methods or across a class is unpredictable,
82
- and will probably cause bad things to happen.
115
+ This is a ridiculous proof of concept, so there are a few issues...
116
+
117
+ - Calling one compiled method/class in the context of another will blow up, so no dependency injection or any of that.
83
118
 
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.
119
+ - It's destructive, so you'll lose the body of the original method.
87
120
 
88
- - It doesn't actually use Node yet
121
+ - It doesn't actually use Node yet, just V8.
89
122
 
90
123
  - It probably can't handle anything too clever.
91
124
 
@@ -1,13 +1,15 @@
1
- require 'node_module/version'
2
1
  require 'live_ast/to_ruby'
3
2
  require 'live_ast/irb_spy' if defined?(IRB)
4
3
 
4
+ require 'node_module/version'
5
+
5
6
  module NodeModule
6
7
 
7
8
  autoload :OpalJsContext, 'node_module/opal_js_context'
9
+ autoload :Compiled, 'node_module/compiled'
8
10
 
9
- def self.included(base)
10
- base.extend ClassMethods
11
+ def self.included(receiver)
12
+ receiver.extend ClassMethods
11
13
  end
12
14
 
13
15
  def self.opal_js_context
@@ -17,35 +19,35 @@ module NodeModule
17
19
  module ClassMethods
18
20
  def node_module(*methods)
19
21
  if methods.empty?
20
- NodeModule.execute_following_methods_as_javascript!(self)
22
+ NodeModule.compile_on_callback(self)
21
23
  else
22
- NodeModule.execute_methods_as_javascript!(methods, self)
24
+ NodeModule.compile_and_replace!(self, methods)
23
25
  end
24
26
  end
25
27
  end
26
28
 
27
- module_function
28
-
29
- def self.execute_methods_as_javascript!(methods, receiver)
29
+ def self.compile_and_replace!(receiver, methods)
30
30
  methods.each do |name|
31
31
  meth = receiver.instance_method(name).to_ruby
32
-
33
- NodeModule.opal_js_context.compile(meth)
34
-
35
- receiver.send :define_method, name do |*args|
36
- NodeModule.opal_js_context.run(__method__, args)
37
- end
32
+ self.opal_js_context.compile(meth)
33
+ self.replace_method!(receiver, name)
38
34
  end
39
35
  end
40
36
 
41
- def self.execute_following_methods_as_javascript!(receiver)
37
+ def self.compile_on_callback(receiver)
42
38
  active = nil
43
- receiver.define_singleton_method(:method_added) do |meth_name|
39
+ receiver.define_singleton_method(:method_added) do |name|
44
40
  return if active
45
41
  active = true
46
- receiver.node_module(meth_name)
42
+ receiver.node_module(name)
47
43
  active = false
48
44
  end
49
45
  end
50
46
 
47
+ def self.replace_method!(receiver, name)
48
+ receiver.send :define_method, name do |*args|
49
+ NodeModule.opal_js_context.run(__method__, args)
50
+ end
51
+ end
52
+
51
53
  end
@@ -0,0 +1,37 @@
1
+ require 'strscan'
2
+
3
+ module NodeModule
4
+ class Compiled
5
+
6
+ def self.inherited(receiver)
7
+ source = File.read(caller.first[/^[^:]+/])
8
+
9
+ extract_class_definition(source) do |class_def|
10
+ NodeModule.opal_js_context.compile(class_def)
11
+ end
12
+
13
+ receiver.extend NodeModule::ClassMethods
14
+
15
+ NodeModule.compile_on_callback(receiver)
16
+ end
17
+
18
+ private
19
+
20
+ def self.extract_class_definition(source)
21
+ scanner = StringScanner.new(source)
22
+ scanner.scan_until(/^\s+class/)
23
+
24
+ indent = scanner.matched[/[^\n]\s+/].length
25
+ scanner.pos = scanner.pos - scanner.matched_size
26
+
27
+ definition = scanner.scan_until(/^\s{#{indent}}end/)
28
+ .sub('< NodeModule::Compiled', '')
29
+
30
+ yield definition
31
+
32
+ ensure
33
+ scanner.terminate
34
+ end
35
+
36
+ end
37
+ end
@@ -11,7 +11,7 @@ class NodeModule::OpalJsContext < V8::Context
11
11
  end
12
12
 
13
13
  def compile(code)
14
- eval Opal.parse(code)
14
+ eval Opal.compile(code)
15
15
  end
16
16
 
17
17
  def run(name, args=[])
@@ -1,3 +1,3 @@
1
1
  module NodeModule
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "live_ast"
22
22
  spec.add_dependency "therubyracer"
23
- spec.add_dependency "opal"
23
+ spec.add_dependency "opal", "~> 0.5"
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
- spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "minitest", "~> 5.2.3"
27
27
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe NodeModule::Compiled, "run entire class against V8" do
4
+
5
+ class Greeter < NodeModule::Compiled
6
+
7
+ def initialize(*names)
8
+ @names = names
9
+ end
10
+
11
+ def hello!
12
+ @names.map {|name| "hello #{name}!" }.join(" ")
13
+ end
14
+
15
+ def goodbye!
16
+ hello!.gsub('hello', 'goodbye')
17
+ end
18
+
19
+ end
20
+
21
+ describe "integration with the subclass" do
22
+
23
+ let(:greeter) { Greeter.new("Sarah", "Jess") }
24
+
25
+ it "says 'hello' to all the people" do
26
+ greeter.hello!.must_equal "hello Sarah! hello Jess!"
27
+ end
28
+
29
+ it "says 'goodbye' to all the people" do
30
+ greeter.goodbye!.must_equal "goodbye Sarah! goodbye Jess!"
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -8,13 +8,6 @@ describe NodeModule::OpalJsContext do
8
8
  let(:bang_method) { "def boom!; 'BOOM!'; end;" }
9
9
  let(:mixed_method) { "def boom?(a, b); boom! if a == b; end;" }
10
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
11
  describe "#run" do
19
12
  before do
20
13
  subject.compile(predicate_method)
metadata CHANGED
@@ -1,112 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: node_module
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
5
- prerelease:
4
+ version: 0.2.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Lee Machin
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-19 00:00:00.000000000 Z
11
+ date: 2014-02-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: live_ast
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: therubyracer
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: opal
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
- version: '0'
47
+ version: '0.5'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - "~>"
60
53
  - !ruby/object:Gem::Version
61
- version: '0'
54
+ version: '0.5'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bundler
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ~>
59
+ - - "~>"
68
60
  - !ruby/object:Gem::Version
69
61
  version: '1.3'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ~>
66
+ - - "~>"
76
67
  - !ruby/object:Gem::Version
77
68
  version: '1.3'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: minitest
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - "~>"
100
88
  - !ruby/object:Gem::Version
101
- version: '0'
89
+ version: 5.2.3
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - "~>"
108
95
  - !ruby/object:Gem::Version
109
- version: '0'
96
+ version: 5.2.3
110
97
  description: Evaluate methods in Ruby as Javascript instead
111
98
  email:
112
99
  - lee@new-bamboo.co.uk
@@ -114,51 +101,47 @@ executables: []
114
101
  extensions: []
115
102
  extra_rdoc_files: []
116
103
  files:
117
- - .gitignore
118
- - .ruby-version
104
+ - ".gitignore"
105
+ - ".ruby-version"
119
106
  - Gemfile
120
107
  - LICENSE
121
108
  - README.md
122
109
  - Rakefile
123
110
  - lib/node_module.rb
111
+ - lib/node_module/compiled.rb
124
112
  - lib/node_module/opal_js_context.rb
125
113
  - lib/node_module/version.rb
126
114
  - node_module.gemspec
115
+ - spec/lib/node_module/compiled_spec.rb
127
116
  - spec/lib/node_module/opal_js_context_spec.rb
128
117
  - spec/lib/node_module_spec.rb
129
118
  - spec/spec_helper.rb
130
119
  homepage: http://github.com/leemachin/node_module
131
120
  licenses:
132
121
  - MIT
122
+ metadata: {}
133
123
  post_install_message:
134
124
  rdoc_options: []
135
125
  require_paths:
136
126
  - lib
137
127
  required_ruby_version: !ruby/object:Gem::Requirement
138
- none: false
139
128
  requirements:
140
- - - ! '>='
129
+ - - ">="
141
130
  - !ruby/object:Gem::Version
142
131
  version: '0'
143
- segments:
144
- - 0
145
- hash: -2723743550254407902
146
132
  required_rubygems_version: !ruby/object:Gem::Requirement
147
- none: false
148
133
  requirements:
149
- - - ! '>='
134
+ - - ">="
150
135
  - !ruby/object:Gem::Version
151
136
  version: '0'
152
- segments:
153
- - 0
154
- hash: -2723743550254407902
155
137
  requirements: []
156
138
  rubyforge_project:
157
- rubygems_version: 1.8.23
139
+ rubygems_version: 2.2.0
158
140
  signing_key:
159
- specification_version: 3
141
+ specification_version: 4
160
142
  summary: Get really close to the metal in Ruby
161
143
  test_files:
144
+ - spec/lib/node_module/compiled_spec.rb
162
145
  - spec/lib/node_module/opal_js_context_spec.rb
163
146
  - spec/lib/node_module_spec.rb
164
147
  - spec/spec_helper.rb