opal-native 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,10 +2,10 @@ Opal support for automagical native bridging
2
2
  ============================================
3
3
 
4
4
  This gem gives to Opal a standard API to implement bridges to native objects and glue-less native
5
- access and usage with the 'Object()` helper function.
5
+ access and usage with the `Native()` helper function.
6
6
 
7
7
  ```ruby
8
- o = Object(`$opal`)
8
+ o = Native(`$opal`)
9
9
 
10
10
  o.global.console # this will access the global console object and return it
11
11
  o.global.console.log('wut') # this will call the log function on the console object
data/Rakefile CHANGED
@@ -10,9 +10,9 @@ task :build => :dependencies do
10
10
  Opal::Builder.new(files: 'lib', out: 'build/opal-native.js').build
11
11
  end
12
12
 
13
- desc 'Build latest opal-native ready for testing to build dir'
14
- task :test => :dependencies do
15
- Opal::Builder.new(files: %w[lib spec], debug: true, out: 'build/opal-native.test.js').build
13
+ desc 'Run specs in spec/'
14
+ task :test => :build do
15
+ Opal::Context.runner 'spec/**/*.rb'
16
16
  end
17
17
 
18
18
  task :default => :build
@@ -8,113 +8,21 @@
8
8
  # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
9
  #++
10
10
 
11
- class Module
12
- %x{
13
- function define_attr_bridge (klass, target, name, getter, setter) {
14
- if (getter) {
15
- $opal.defn(klass, $opal.mid_to_jsid(name), function() {
16
- var real = target;
17
-
18
- if (#{Symbol == `target`}) {
19
- real = target[0] == '@' ? this[target.substr(1)] : this[$opal.mid_to_jsid(target)].apply(this);
20
- }
21
-
22
- var result = real[name];
23
-
24
- return result == null ? nil : result;
25
- });
26
- }
27
-
28
- if (setter) {
29
- $opal.defn(klass, $opal.mid_to_jsid(name + '='), function (block, val) {
30
- var real = target;
31
-
32
- if (#{Symbol === `target`}) {
33
- real = target[0] == '@' ? this[target.substr(1)] : this[$opal.mid_to_jsid(target)].apply(this);
34
- }
35
-
36
- return real[name] = val;
37
- });
38
- }
39
- }
40
- }
41
-
42
- def attr_accessor_bridge (target, *attrs)
43
- %x{
44
- for (var i = 0, length = attrs.length; i < length; i++) {
45
- define_attr_bridge(this, target, attrs[i], true, true);
46
- }
47
- }
48
-
49
- self
50
- end
51
-
52
- def attr_reader_bridge (target, *attrs)
53
- %x{
54
- for (var i = 0, length = attrs.length; i < length; i++) {
55
- define_attr_bridge(this, target, attrs[i], true, false);
56
- }
57
- }
58
-
59
- self
60
- end
61
-
62
- def attr_writer_bridge (target, *attrs)
63
- %x{
64
- for (var i = 0, length = attrs.length; i < length; i++) {
65
- define_attr_bridge(this, target, attrs[i], false, true);
66
- }
67
- }
68
-
69
- self
70
- end
71
-
72
- def attr_bridge (target, name, setter = false)
73
- `define_attr_bridge(this, target, name, true, setter)`
74
-
75
- self
76
- end
77
-
78
- def define_method_bridge (object, name, ali = nil)
79
- %x{
80
- var self = this;
81
-
82
- $opal.defn(self, $opal.mid_to_jsid(#{ali || name}), function () {
83
- var real = object;
84
-
85
- if (#{Symbol === object}) {
86
- real = object[0] == '@' ? self[object.substr(1)] : self[$opal.mid_to_jsid(object)].apply(self);
87
- }
88
-
89
- return real[name].apply(real, arguments);
90
- });
91
- }
92
-
93
- nil
11
+ module Native
12
+ def self.=== (other)
13
+ `#{other} == null || !#{other}.o$klass`
94
14
  end
95
- end
96
-
97
- module Kernel
98
- def define_singleton_method_bridge (object, name, ali = nil)
99
- %x{
100
- var self = this;
101
15
 
102
- $opal.defs(this, $opal.mid_to_jsid(#{ali || name}), function () {
103
- var real = object;
104
-
105
- if (#{Symbol === object}) {
106
- real = object[0] == '@' ? self[object.substr(1)] : self[$opal.mid_to_jsid(object)].apply(self);
107
- }
16
+ def self.send (object, name, *args, &block)
17
+ args << block if block
108
18
 
109
- return real[name].apply(real, arguments);
110
- });
19
+ args = args.map {|obj|
20
+ Native === obj ? obj : obj.to_native
111
21
  }
112
22
 
113
- nil
23
+ Kernel.Native(`object[name].apply(object, args)`)
114
24
  end
115
- end
116
25
 
117
- module Native
118
26
  def self.included (klass)
119
27
  class << klass
120
28
  def from_native (object)
@@ -134,10 +42,12 @@ module Native
134
42
  @native
135
43
  end
136
44
 
137
- def native_send (name, *args)
138
- return method_missing(name, *args) unless Opal.function? `#@native[name]`
45
+ def native_send (name, *args, &block)
46
+ unless Proc === `#@native[name]`
47
+ raise NoMethodError, "undefined method `#{name}` for #{`#@native.toString()`}"
48
+ end
139
49
 
140
- `#@native[name].apply(#@native, args)`
50
+ Native.send(@native, name, *args, &block)
141
51
  end
142
52
 
143
53
  alias __native_send__ native_send
@@ -153,32 +63,18 @@ class Native::Object
153
63
  update!
154
64
  end
155
65
 
156
- def update! (name = nil)
157
- unless name
158
- %x{
159
- for (var name in #@native) {
160
- #{update!(`name`)}
161
- }
162
- }
66
+ def [] (name)
67
+ Kernel.Native(`#@native[name]`)
68
+ end
163
69
 
164
- return
165
- end
70
+ def []= (name, value)
71
+ value = value.to_native unless Native === value
166
72
 
167
- if Opal.function? `#@native[name]`
168
- define_singleton_method_bridge @native, name
73
+ `#@native[name] = #{value}`
169
74
 
170
- if respond_to? "#{name}="
171
- singleton_class.undef_method "#{name}="
172
- end
173
- else
174
- define_singleton_method name do
175
- self[name]
176
- end
75
+ update!(name)
177
76
 
178
- define_singleton_method "#{name}=" do |value|
179
- self[name] = value
180
- end
181
- end
77
+ value
182
78
  end
183
79
 
184
80
  def each
@@ -186,7 +82,7 @@ class Native::Object
186
82
 
187
83
  %x{
188
84
  for (var name in #@native) {
189
- #{yield Kernel.Object(`name`), Kernel.Object(`#@native[name]`)}
85
+ #{yield Kernel.Native(`name`), Kernel.Native(`#@native[name]`)}
190
86
  }
191
87
  }
192
88
 
@@ -198,7 +94,7 @@ class Native::Object
198
94
 
199
95
  %x{
200
96
  for (var name in #@native) {
201
- #{yield Kernel.Object(`name`)}
97
+ #{yield Kernel.Native(`name`)}
202
98
  }
203
99
  }
204
100
 
@@ -210,33 +106,23 @@ class Native::Object
210
106
 
211
107
  %x{
212
108
  for (var name in #@native) {
213
- #{yield Kernel.Object(`#@native[name]`)}
109
+ #{yield Kernel.Native(`#@native[name]`)}
214
110
  }
215
111
  }
216
112
  end
217
113
 
218
- def [] (name)
219
- Kernel.Object(`#@native[name] || nil`)
114
+ def inspect
115
+ "#<Native: #{`#@native.toString()`}>"
220
116
  end
221
117
 
222
- def []= (name, value)
223
- value = value.to_native unless Opal.native?(value)
224
-
225
- `#@native[name] = #{value}`
226
-
227
- update!(name)
228
-
229
- value
118
+ def keys
119
+ each_key.to_a
230
120
  end
231
121
 
232
122
  def nil?
233
123
  `#@native === null || #@native === undefined`
234
124
  end
235
125
 
236
- def inspect
237
- "#<Native: #{`#@native.toString()`}>"
238
- end
239
-
240
126
  def to_s
241
127
  `#@native.toString()`
242
128
  end
@@ -244,11 +130,47 @@ class Native::Object
244
130
  def to_hash
245
131
  Hash[to_a]
246
132
  end
133
+
134
+ def values
135
+ each_value.to_a
136
+ end
137
+
138
+ def update! (name = nil)
139
+ unless name
140
+ %x{
141
+ for (var name in #@native) {
142
+ #{update!(`name`)}
143
+ }
144
+ }
145
+
146
+ return
147
+ end
148
+
149
+ if Proc === `#@native[name]`
150
+ define_singleton_method name do |*args, &block|
151
+ __native_send__(name, *args, &block)
152
+ end
153
+
154
+ if respond_to? "#{name}="
155
+ singleton_class.undef_method "#{name}="
156
+ end
157
+ else
158
+ define_singleton_method name do
159
+ self[name]
160
+ end
161
+
162
+ define_singleton_method "#{name}=" do |value|
163
+ self[name] = value
164
+ end
165
+ end
166
+ end
247
167
  end
248
168
 
249
169
  module Kernel
250
- def Object (object)
251
- Opal.native?(object) ? Native::Object.new(object) : object
170
+ def Native (object)
171
+ return if `object == null`
172
+
173
+ Native === object ? Native::Object.new(object) : object
252
174
  end
253
175
  end
254
176
 
@@ -266,7 +188,7 @@ end
266
188
 
267
189
  class Array
268
190
  def to_native
269
- map { |obj| Opal.object?(obj) ? obj.to_native : obj }
191
+ map { |obj| Native === obj ? obj : obj.to_native }
270
192
  end
271
193
  end
272
194
 
@@ -280,7 +202,7 @@ class Hash
280
202
  var key = map[assoc][0],
281
203
  value = map[assoc][1];
282
204
 
283
- result[key] = #{Opal.native?(`value`)} ? value : #{`value`.to_native};
205
+ result[key] = #{Native === `value` ? `value` : `value`.to_native};
284
206
  }
285
207
 
286
208
  return result;
@@ -310,7 +232,9 @@ class Proc
310
232
  var self = this;
311
233
 
312
234
  return (function () {
313
- return self.apply(self.$S, arguments);
235
+ return self.apply(self.$S, [null].concat(#{
236
+ `$slice.call(arguments)`.map { |o| Kernel.Native(o) }
237
+ }));
314
238
  });
315
239
  }
316
240
  end
@@ -327,3 +251,5 @@ class String
327
251
  `this.valueOf()`
328
252
  end
329
253
  end
254
+
255
+ require 'native/bridge'
@@ -0,0 +1,123 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ class Module
12
+ def define_attr_bridge (target, name, getter, setter)
13
+ if getter
14
+ if Symbol === target
15
+ if target.start_with? '@'
16
+ define_method name do
17
+ object = instance_variable_get(target)
18
+
19
+ Kernel.Native(`#{Native === object ? object : object.to_native}[name]`)
20
+ end
21
+ else
22
+ define_method name do
23
+ object = __send__(target)
24
+
25
+ Kernel.Native(`#{Native === object ? object : object.to_native}[name]`)
26
+ end
27
+ end
28
+ else
29
+ define_method name do |*args, &block|
30
+ Kernel.Native(`target[name]`)
31
+ end
32
+ end
33
+ end
34
+
35
+ if setter
36
+ if Symbol === target
37
+ if target.start_with? '@'
38
+ define_method "#{name}=" do |value|
39
+ object = instance_variable_get(target)
40
+ value = value.to_native unless Native === value
41
+
42
+ Kernel.Native(`#{Native === object ? object : object.to_native}[name] = value`)
43
+ end
44
+ else
45
+ define_method "#{name}=" do |value|
46
+ object = __send__(target)
47
+ value = value.to_native unless Native === value
48
+
49
+ Kernel.Native(`#{Native === object ? object : object.to_native}[name] = value`)
50
+ end
51
+ end
52
+ else
53
+ define_method "#{name}=" do |value|
54
+ value = value.to_native unless Native === value
55
+
56
+ Kernel.Native(`target[name] = value`)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def attr_accessor_bridge (target, *attrs)
63
+ attrs.each {|attr|
64
+ define_attr_bridge(target, attr, true, true)
65
+ }
66
+
67
+ self
68
+ end
69
+
70
+ def attr_reader_bridge (target, *attrs)
71
+ attrs.each {|attr|
72
+ define_attr_bridge(target, attr, true, false)
73
+ }
74
+
75
+ self
76
+ end
77
+
78
+ def attr_writer_bridge (target, *attrs)
79
+ attrs.each { |attr|
80
+ define_attr_bridge(target, attr, false, true)
81
+ }
82
+
83
+ self
84
+ end
85
+
86
+ def attr_bridge (target, name, setter = false)
87
+ define_attr_bridge(target, name, true, setter)
88
+
89
+ self
90
+ end
91
+
92
+ def define_method_bridge (target, name, ali = nil)
93
+ if Symbol === target
94
+ if target.start_with? '@'
95
+ define_method ali || name do |*args, &block|
96
+ object = instance_variable_get(target)
97
+
98
+ Native.send(Native === object ? object : object.to_native, name, *args, &block)
99
+ end
100
+ else
101
+ define_method ali || name do |*args, &block|
102
+ object = __send__(target)
103
+
104
+ Native.send(Native === object ? object : object.to_native, name, *args, &block)
105
+ end
106
+ end
107
+ else
108
+ define_method ali || name do |*args, &block|
109
+ Native.send(target, name, *args, &block)
110
+ end
111
+ end
112
+
113
+ nil
114
+ end
115
+ end
116
+
117
+ module Kernel
118
+ def define_singleton_method_bridge (target, name, ali = nil)
119
+ define_singleton_method ali || name do |*args, &block|
120
+ Native.send(target, name, *args, &block)
121
+ end
122
+ end
123
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new {|s|
2
2
  s.name = 'opal-native'
3
- s.version = '0.0.2'
3
+ s.version = '0.0.3'
4
4
  s.author = 'meh.'
5
5
  s.email = 'meh@paranoici.org'
6
6
  s.homepage = 'http://github.com/opal/opal-native'
@@ -12,5 +12,5 @@ Gem::Specification.new {|s|
12
12
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
13
  s.require_paths = ['lib']
14
14
 
15
- s.add_development_dependency 'opal-spec'
15
+ # s.add_dependency 'opal-spec'
16
16
  }
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Native do
4
+ before do
5
+ @object = object = `{
6
+ a: 23,
7
+
8
+ b: function () {
9
+ return 1337;
10
+ }
11
+ }`
12
+
13
+ @test = Class.new {
14
+ attr_accessor_bridge object, :a
15
+
16
+ define_method_bridge object, :b
17
+
18
+ define_singleton_method_bridge object, :b, :c
19
+ }
20
+ end
21
+
22
+ it 'bridges correctly accessors' do
23
+ test = @test.new
24
+
25
+ `#@object.a`.should == 23
26
+ `#@object.a = 42`
27
+ `#@object.a`.should == 42
28
+
29
+ test.a.should == 42
30
+
31
+ test.a = 23
32
+ test.a.should == 23
33
+ `#@object.a`.should == 23
34
+ end
35
+
36
+ it 'bridges correctly methods' do
37
+ @test.new.b.should == 1337
38
+ end
39
+
40
+ it 'bridges correctly singleton methods' do
41
+ @test.c.should == 1337
42
+ end
43
+ end
@@ -1,11 +1,17 @@
1
1
  require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
- class Test
4
- include Native
5
- end
6
-
7
3
  describe Native do
4
+ before do
5
+ @test = Class.new {
6
+ include Native
7
+ }
8
+ end
9
+
8
10
  it 'creates a working object' do
9
- Test.new(42).to_native.should == 42
11
+ @test.new(42).to_native.should == 42
12
+ end
13
+
14
+ it 'sends calls properly' do
15
+ @test.new(42).native_send(:toString, 16).should == '2a'
10
16
  end
11
17
  end
@@ -0,0 +1,46 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Native::Object do
4
+ before do
5
+ @object = `{
6
+ a: 42,
7
+
8
+ b: function () {
9
+ return 42;
10
+ },
11
+
12
+ c: function () {
13
+ return { a: 23 };
14
+ },
15
+
16
+ d: function (a, h) {
17
+ return h({a: a});
18
+ }
19
+ }`
20
+
21
+ @test = Kernel.Native(@object)
22
+ end
23
+
24
+ it 'wraps an object properly' do
25
+ `#{@test.to_native} == #{@object}`.should be_true
26
+ end
27
+
28
+ it 'makes an accessor properly' do
29
+ @test.a.should == 42
30
+ @test.a = 23
31
+ @test.a.should == 23
32
+ `#@object.a`.should == 23
33
+ end
34
+
35
+ it 'calls a function as a method when present' do
36
+ @test.b.should == 42
37
+ end
38
+
39
+ it 'calls a function as a method when present and returns a Native' do
40
+ @test.c.a.should == 23
41
+ end
42
+
43
+ it 'calls handlers with proper wrapping' do
44
+ @test.d(23) { |o| o.a }.should == 23
45
+ end
46
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-native
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,19 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-18 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: opal-spec
16
- requirement: &15880980 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: *15880980
12
+ date: 2012-01-21 00:00:00.000000000 Z
13
+ dependencies: []
25
14
  description:
26
15
  email: meh@paranoici.org
27
16
  executables: []
@@ -32,8 +21,11 @@ files:
32
21
  - README.md
33
22
  - Rakefile
34
23
  - lib/opal/native.rb
24
+ - lib/opal/native/bridge.rb
35
25
  - opal-native.gemspec
26
+ - spec/bridge_spec.rb
36
27
  - spec/native_spec.rb
28
+ - spec/object_spec.rb
37
29
  - spec/spec_helper.rb
38
30
  - spec/spec_runner.html
39
31
  homepage: http://github.com/opal/opal-native
@@ -61,6 +53,8 @@ signing_key:
61
53
  specification_version: 3
62
54
  summary: Easy support for native objects in Opal
63
55
  test_files:
56
+ - spec/bridge_spec.rb
64
57
  - spec/native_spec.rb
58
+ - spec/object_spec.rb
65
59
  - spec/spec_helper.rb
66
60
  - spec/spec_runner.html