opal 0.5.0 → 0.5.2

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/README.md +1 -1
  4. data/Rakefile +11 -8
  5. data/lib/opal.rb +1 -1
  6. data/lib/opal/version.rb +1 -1
  7. data/opal.gemspec +1 -1
  8. data/{corelib → opal/core}/array.rb +47 -40
  9. data/{corelib → opal/core}/basic_object.rb +4 -0
  10. data/{corelib → opal/core}/boolean.rb +2 -6
  11. data/{corelib → opal/core}/class.rb +0 -0
  12. data/{corelib → opal/core}/comparable.rb +0 -0
  13. data/{corelib → opal/core}/encoding.rb +0 -0
  14. data/{corelib → opal/core}/enumerable.rb +160 -38
  15. data/opal/core/enumerator.rb +416 -0
  16. data/{corelib → opal/core}/error.rb +0 -0
  17. data/{corelib → opal/core}/hash.rb +38 -48
  18. data/{corelib → opal/core}/io.rb +13 -9
  19. data/{corelib → opal/core}/kernel.rb +75 -49
  20. data/{corelib → opal/core}/main.rb +0 -0
  21. data/{corelib → opal/core}/match_data.rb +0 -4
  22. data/{corelib → opal/core}/method.rb +0 -0
  23. data/{corelib → opal/core}/module.rb +24 -3
  24. data/{corelib → opal/core}/nil_class.rb +0 -4
  25. data/{corelib → opal/core}/numeric.rb +3 -4
  26. data/{corelib → opal/core}/proc.rb +0 -4
  27. data/{corelib → opal/core}/range.rb +0 -0
  28. data/{corelib → opal/core}/regexp.rb +0 -4
  29. data/{corelib → opal/core}/runtime.js +0 -0
  30. data/{corelib → opal/core}/string.rb +4 -6
  31. data/{corelib → opal/core}/struct.rb +3 -21
  32. data/{corelib → opal/core}/time.rb +0 -4
  33. data/opal/opal.rb +121 -0
  34. data/spec/corelib/array/select_spec.rb +14 -0
  35. data/spec/filters/20.rb +4 -0
  36. data/spec/filters/bugs/enumerable.rb +1 -48
  37. data/spec/filters/unsupported/enumerator.rb +13 -0
  38. data/spec/opal/compiler/irb_spec.rb +1 -0
  39. data/spec/rubyspecs +1 -0
  40. data/spec/{corelib → stdlib}/native/alias_native_spec.rb +6 -4
  41. data/spec/{corelib → stdlib}/native/each_spec.rb +3 -1
  42. data/spec/{corelib → stdlib}/native/element_reference_spec.rb +3 -1
  43. data/spec/stdlib/native/ext_spec.rb +19 -0
  44. data/spec/{corelib → stdlib}/native/initialize_spec.rb +4 -4
  45. data/spec/{corelib → stdlib}/native/method_missing_spec.rb +13 -1
  46. data/spec/{corelib → stdlib}/native/new_spec.rb +3 -1
  47. data/stdlib/enumerator.rb +1 -0
  48. data/stdlib/json.rb +1 -1
  49. data/stdlib/native.rb +483 -0
  50. metadata +52 -47
  51. data/corelib/enumerator.rb +0 -55
  52. data/corelib/native.rb +0 -270
  53. data/corelib/opal.rb +0 -88
  54. data/spec/corelib/native/ext_spec.rb +0 -5
  55. data/spec/filters/bugs/enumerator.rb +0 -6
data/opal/opal.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'core/runtime'
2
+ require 'core/module'
3
+ require 'core/class'
4
+ require 'core/basic_object'
5
+ require 'core/kernel'
6
+ require 'core/nil_class'
7
+ require 'core/boolean'
8
+ require 'core/error'
9
+ require 'core/regexp'
10
+ require 'core/comparable'
11
+ require 'core/enumerable'
12
+ require 'core/enumerator'
13
+ require 'core/array'
14
+ require 'core/hash'
15
+ require 'core/string'
16
+ require 'core/match_data'
17
+ require 'core/encoding'
18
+ require 'core/numeric'
19
+ require 'core/proc'
20
+ require 'core/method'
21
+ require 'core/range'
22
+ require 'core/time'
23
+ require 'core/struct'
24
+ require 'core/io'
25
+ require 'core/main'
26
+ require 'native'
27
+
28
+ # regexp matches
29
+ $& = $~ = $` = $' = nil
30
+
31
+ # stub library path
32
+ $: = []
33
+ $" = []
34
+
35
+ # split lines
36
+ $/ = "\n"
37
+ $, = " "
38
+
39
+ ARGV = []
40
+ ARGF = Object.new
41
+ ENV = {}
42
+
43
+ $VERBOSE = false
44
+ $DEBUG = false
45
+ $SAFE = 0
46
+
47
+ RUBY_PLATFORM = 'opal'
48
+ RUBY_ENGINE = 'opal'
49
+ RUBY_VERSION = '1.9.3'
50
+ RUBY_ENGINE_VERSION = '0.5.2'
51
+ RUBY_RELEASE_DATE = '2013-11-11'
52
+
53
+ module Opal
54
+ def self.coerce_to(object, type, method)
55
+ return object if type === object
56
+
57
+ unless object.respond_to? method
58
+ raise TypeError, "no implicit conversion of #{object.class} into #{type}"
59
+ end
60
+
61
+ object.__send__ method
62
+ end
63
+
64
+ def self.coerce_to!(object, type, method)
65
+ coerced = coerce_to(object, type, method)
66
+
67
+ unless type === coerced
68
+ raise TypeError, "can't convert #{object.class} into #{type} (#{object.class}##{method} gives #{coerced.class}"
69
+ end
70
+
71
+ coerced
72
+ end
73
+
74
+ def self.try_convert(object, type, method)
75
+ return object if type === object
76
+
77
+ if object.respond_to? method
78
+ object.__send__ method
79
+ end
80
+ end
81
+
82
+ def self.compare(a, b)
83
+ compare = a <=> b
84
+
85
+ if `compare === nil`
86
+ raise ArgumentError, "comparison of #{a.class.name} with #{b.class.name} failed"
87
+ end
88
+
89
+ compare
90
+ end
91
+
92
+ def self.truthy?(value)
93
+ if value
94
+ true
95
+ else
96
+ false
97
+ end
98
+ end
99
+
100
+ def self.falsy?(value)
101
+ if value
102
+ false
103
+ else
104
+ true
105
+ end
106
+ end
107
+
108
+ def self.destructure(args)
109
+ %x{
110
+ if (args.length == 1) {
111
+ return args[0];
112
+ }
113
+ else if (args._isArray) {
114
+ return args;
115
+ }
116
+ else {
117
+ return $slice.call(args);
118
+ }
119
+ }
120
+ end
121
+ end
@@ -0,0 +1,14 @@
1
+ describe "Array#select" do
2
+ it "passes an array item into a single default-block parameter" do
3
+ [["ABC", "DEF"]].select do |x|
4
+ x.should == ["ABC", "DEF"]
5
+ end
6
+ end
7
+
8
+ it "splits an array item into a list of default block parameters" do
9
+ [["ABC", "DEF"]].select do |x,y|
10
+ x.should == "ABC"
11
+ y.should == "DEF"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ opal_filter "2.0 behaviour" do
2
+ fails "Enumerator.new ignores block if arg given"
3
+ fails "String#end_with? ignores arguments not convertible to string"
4
+ end
@@ -1,58 +1,11 @@
1
1
  opal_filter "Enumerable" do
2
- fails "Enumerable#drop passed a number n as an argument tries to convert n to an Integer using #to_int"
3
-
4
- fails "Enumerable#drop_while passes elements to the block until the first false"
5
-
6
- fails "Enumerable#each_slice raises an Argument Error if there is not a single parameter > 0"
7
-
8
- fails "Enumerable#each_with_index provides each element to the block"
9
- fails "Enumerable#each_with_index provides each element to the block and its index"
10
- fails "Enumerable#each_with_index binds splat arguments properly"
11
- fails "Enumerable#each_with_index passes extra parameters to each"
12
-
13
- fails "Enumerable#entries passes arguments to each"
14
-
15
- fails "Enumerable#first when passed an argument consumes only what is needed"
16
- fails "Enumerable#first when passed an argument raises a TypeError if the passed argument is not numeric"
17
- fails "Enumerable#first when passed an argument tries to convert the passed argument to an Integer using #to_int"
18
- fails "Enumerable#first when passed an argument raises an ArgumentError when count is negative"
2
+ fails "Enumerable#cycle passed a number n as an argument raises an ArgumentError if more arguments are passed"
19
3
 
20
4
  fails "Enumerable#grep can use $~ in the block when used with a Regexp"
21
5
 
22
- fails "Enumerable#group_by returns a hash without default_proc"
23
- fails "Enumerable#group_by gathers whole arrays as elements when each yields multiple"
24
-
25
- fails "Enumerable#include? returns true if any element == argument for numbers"
26
- fails "Enumerable#include? gathers whole arrays as elements when each yields multiple"
27
-
28
6
  fails "Enumerable#inject returns nil when fails(legacy rubycon)"
29
7
  fails "Enumerable#inject without inject arguments(legacy rubycon)"
30
- fails "Enumerable#inject can take a symbol argument"
31
- fails "Enumerable#inject ignores the block if two arguments"
32
- fails "Enumerable#inject can take two argument"
33
-
34
- fails "Enumerable#max raises an ArgumentError for incomparable elements"
35
- fails "Enumerable#max gathers whole arrays as elements when each yields multiple"
36
-
37
- fails "Enumerable#member? returns true if any element == argument for numbers"
38
- fails "Enumerable#member? gathers whole arrays as elements when each yields multiple"
39
-
40
- fails "Enumerable#min raises an ArgumentError for incomparable elements"
41
- fails "Enumerable#min gathers whole arrays as elements when each yields multiple"
42
8
 
43
9
  fails "Enumerable#reduce returns nil when fails(legacy rubycon)"
44
10
  fails "Enumerable#reduce without inject arguments(legacy rubycon)"
45
- fails "Enumerable#reduce can take a symbol argument"
46
- fails "Enumerable#reduce ignores the block if two arguments"
47
- fails "Enumerable#reduce can take two argument"
48
-
49
- fails "Enumerable#select passes through the values yielded by #each_with_index"
50
- fails "Enumerable#select returns an enumerator when no block given"
51
-
52
- fails "Enumerable#take when passed an argument consumes only what is needed"
53
- fails "Enumerable#take when passed an argument raises a TypeError if the passed argument is not numeric"
54
- fails "Enumerable#take when passed an argument tries to convert the passed argument to an Integer using #to_int"
55
- fails "Enumerable#take when passed an argument raises an ArgumentError when count is negative"
56
-
57
- fails "Enumerable#to_a passes arguments to each"
58
11
  end
@@ -0,0 +1,13 @@
1
+ opal_filter "Enumerator as generator" do
2
+ fails "Enumerator#next returns the next element of the enumeration"
3
+ fails "Enumerator#next raises a StopIteration exception at the end of the stream"
4
+ fails "Enumerator#next cannot be called again until the enumerator is rewound"
5
+
6
+ fails "Enumerator#rewind resets the enumerator to its initial state"
7
+ fails "Enumerator#rewind returns self"
8
+ fails "Enumerator#rewind has no effect on a new enumerator"
9
+ fails "Enumerator#rewind has no effect if called multiple, consecutive times"
10
+ fails "Enumerator#rewind does nothing if the object doesn't have a #rewind method"
11
+ fails "Enumerator#rewind works with peek to reset the position"
12
+ fails "Enumerator#rewind calls the enclosed object's rewind method if one exists"
13
+ end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'native'
2
3
 
3
4
  describe Opal::Compiler do
4
5
  describe "irb parser option" do
data/spec/rubyspecs CHANGED
@@ -116,6 +116,7 @@ core/nil/xor_spec
116
116
 
117
117
  core/enumerable/all_spec
118
118
  core/enumerable/any_spec
119
+ core/enumerable/cycle_spec
119
120
  core/enumerable/collect_spec
120
121
  core/enumerable/count_spec
121
122
  core/enumerable/detect_spec
@@ -1,7 +1,9 @@
1
- describe "Native::Base.alias_native" do
1
+ require 'native'
2
+
3
+ describe "Native.alias_native" do
2
4
  it "refers to an attribute on @native" do
3
5
  Class.new {
4
- include Native::Base
6
+ include Native
5
7
 
6
8
  alias_native :a, :a
7
9
  }.new(`{ a: 2 }`).a.should == 2
@@ -9,7 +11,7 @@ describe "Native::Base.alias_native" do
9
11
 
10
12
  it "refers to an attribute on @native and calls it if it's a function" do
11
13
  Class.new {
12
- include Native::Base
14
+ include Native
13
15
 
14
16
  alias_native :a, :a
15
17
  }.new(`{ a: function() { return 42; } }`).a.should == 42
@@ -17,7 +19,7 @@ describe "Native::Base.alias_native" do
17
19
 
18
20
  it "defaults old to new" do
19
21
  Class.new {
20
- include Native::Base
22
+ include Native
21
23
 
22
24
  alias_native :a
23
25
  }.new(`{ a: 42 }`).a.should == 42
@@ -1,4 +1,6 @@
1
- describe "Native#each" do
1
+ require 'native'
2
+
3
+ describe "Native::Object#each" do
2
4
  it "enumerates on object properties" do
3
5
  Native(`{ a: 2, b: 3 }`).each {|name, value|
4
6
  ((name == :a && value == 2) || (name == :b && value == 3)).should be_true
@@ -1,4 +1,6 @@
1
- describe "Native#[]" do
1
+ require 'native'
2
+
3
+ describe "Native::Object#[]" do
2
4
  it "should return the same value for bridged classes" do
3
5
  Native(`2`).should === 2
4
6
  Native(`"lol"`).should === "lol"
@@ -0,0 +1,19 @@
1
+ require 'native'
2
+
3
+ describe Hash do
4
+ describe '#initialize' do
5
+ it "returns a hash with a nil value" do
6
+ h = Hash.new(`{a: null}`)
7
+ h[:a].should == nil
8
+ end
9
+ end
10
+
11
+ describe '#to_n' do
12
+ it "should return a js object representing hash" do
13
+ Hash.new({:a => 100, :b => 200}.to_n).should == {:a => 100, :b => 200}
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "Hash#to_n" do
19
+ end
@@ -1,17 +1,17 @@
1
1
  require 'native'
2
2
 
3
- describe "Native::Base#initialize" do
4
- it "works when Native::Base is included in a BasicObject" do
3
+ describe "Native#initialize" do
4
+ it "works when Native is included in a BasicObject" do
5
5
  basic_class = Class.new(BasicObject)
6
6
  basic_object = basic_class.new
7
7
  lambda { basic_object.native? }.should raise_error(NoMethodError)
8
8
 
9
- basic_class.send :include, Native::Base
9
+ basic_class.send :include, Native
10
10
  lambda { basic_class.new(`{}`) }.should_not raise_error
11
11
  end
12
12
 
13
13
  it "detects a non native object" do
14
14
  object = Object.new
15
- lambda { Native.new(object) }.should raise_error(ArgumentError)
15
+ lambda { Native::Object.new(object) }.should raise_error(ArgumentError)
16
16
  end
17
17
  end
@@ -1,4 +1,6 @@
1
- describe "Native#method_missing" do
1
+ require 'native'
2
+
3
+ describe "Native::Object#method_missing" do
2
4
  it "should return values" do
3
5
  Native(`{ a: 23 }`).a.should == 23
4
6
  Native(`{ a: { b: 42 } }`).a.b.should == 42
@@ -36,4 +38,14 @@ describe "Native#method_missing" do
36
38
  it "should pass the block as function" do
37
39
  Native(`{ a: function(func) { return func(); } }`).a { 42 }.should == 42
38
40
  end
41
+
42
+ it "should unwrap arguments" do
43
+ x = `{}`
44
+
45
+ Native(`{ a: function(a, b) { return a === b } }`).a(Native(x), x).should == true
46
+ end
47
+
48
+ it "should wrap result" do
49
+ Native(`{ a: function() { return {}; } }`).a.class.should == Native::Object
50
+ end
39
51
  end
@@ -1,4 +1,6 @@
1
- describe "Native.new" do
1
+ require 'native'
2
+
3
+ describe "Native()" do
2
4
  it "should return nil for null or undefined" do
3
5
  Native(`null`).should be_nil
4
6
  Native(`undefined`).should be_nil
@@ -0,0 +1 @@
1
+ # stub
data/stdlib/json.rb CHANGED
@@ -78,7 +78,7 @@ module JSON
78
78
  options[:object_class] ||= Hash
79
79
  options[:array_class] ||= Array
80
80
 
81
- `to_opal(js_object, #{options.to_n})`
81
+ `to_opal(js_object, options.map)`
82
82
  end
83
83
 
84
84
  def self.generate(obj, options = {})
data/stdlib/native.rb ADDED
@@ -0,0 +1,483 @@
1
+ module Kernel
2
+ def native?(value)
3
+ `value == null || !value._klass`
4
+ end
5
+
6
+ def Native(obj)
7
+ if `#{obj} == null`
8
+ nil
9
+ elsif native?(obj)
10
+ Native::Object.new(obj)
11
+ else
12
+ obj
13
+ end
14
+ end
15
+
16
+ def Array(object, *args, &block)
17
+ %x{
18
+ if (object == null || object === nil) {
19
+ return [];
20
+ }
21
+ else if (#{native?(object)}) {
22
+ return #{Native::Array.new(object, *args, &block).to_a};
23
+ }
24
+ else if (#{object.respond_to? :to_ary}) {
25
+ return #{object.to_ary};
26
+ }
27
+ else if (#{object.respond_to? :to_a}) {
28
+ return #{object.to_a};
29
+ }
30
+ else {
31
+ return [object];
32
+ }
33
+ }
34
+ end
35
+ end
36
+
37
+ module Native
38
+ def self.is_a?(object, klass)
39
+ %x{
40
+ try {
41
+ return #{object} instanceof #{Native.try_convert(klass)};
42
+ }
43
+ catch (e) {
44
+ return false;
45
+ }
46
+ }
47
+ end
48
+
49
+ def self.try_convert(value)
50
+ %x{
51
+ if (#{native?(value)}) {
52
+ return #{value};
53
+ }
54
+ else if (#{value.respond_to? :to_n}) {
55
+ return #{value.to_n};
56
+ }
57
+ else {
58
+ return nil;
59
+ }
60
+ }
61
+ end
62
+
63
+ def self.convert(value)
64
+ native = try_convert(value)
65
+
66
+ if `#{native} === nil`
67
+ raise ArgumentError, "the passed value isn't a native"
68
+ end
69
+
70
+ native
71
+ end
72
+
73
+ def self.call(obj, key, *args, &block)
74
+ %x{
75
+ var prop = #{obj}[#{key}];
76
+
77
+ if (prop == null) {
78
+ return nil;
79
+ }
80
+ else if (prop instanceof Function) {
81
+ if (block !== nil) {
82
+ args.push(block);
83
+ }
84
+
85
+ args = #{args.map {|value|
86
+ native = try_convert(value)
87
+
88
+ if nil === native
89
+ value
90
+ else
91
+ native
92
+ end
93
+ }};
94
+
95
+ return #{Native(`prop.apply(#{obj}, #{args})`)};
96
+ }
97
+ else if (#{native?(`prop`)}) {
98
+ return #{Native(`prop`)};
99
+ }
100
+ else {
101
+ return prop;
102
+ }
103
+ }
104
+ end
105
+
106
+ module Helpers
107
+ def alias_native(new, old = new, options = {})
108
+ if old.end_with? ?=
109
+ define_method new do |value|
110
+ `#@native[#{old[0 .. -2]}] = #{Native.convert(value)}`
111
+
112
+ value
113
+ end
114
+ else
115
+ if as = options[:as]
116
+ define_method new do |*args, &block|
117
+ if value = Native.call(@native, old, *args, &block)
118
+ as.new(value.to_n)
119
+ end
120
+ end
121
+ else
122
+ define_method new do |*args, &block|
123
+ Native.call(@native, old, *args, &block)
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ def self.included(klass)
131
+ klass.extend Helpers
132
+ end
133
+
134
+ def initialize(native)
135
+ unless Kernel.native?(native)
136
+ Kernel.raise ArgumentError, "the passed value isn't native"
137
+ end
138
+
139
+ @native = native
140
+ end
141
+
142
+ def to_n
143
+ @native
144
+ end
145
+
146
+ class Object < BasicObject
147
+ include Native
148
+
149
+ def ==(other)
150
+ `#@native === #{Native.try_convert(other)}`
151
+ end
152
+
153
+ def has_key?(name)
154
+ `#@native.hasOwnProperty(#{name})`
155
+ end
156
+
157
+ alias key? has_key?
158
+ alias include? has_key?
159
+ alias member? has_key?
160
+
161
+ def each(*args)
162
+ if block_given?
163
+ %x{
164
+ for (var key in #@native) {
165
+ #{yield `key`, `#@native[key]`}
166
+ }
167
+ }
168
+
169
+ self
170
+ else
171
+ method_missing(:each, *args)
172
+ end
173
+ end
174
+
175
+ def [](key)
176
+ %x{
177
+ var prop = #@native[key];
178
+
179
+ if (prop instanceof Function) {
180
+ return prop;
181
+ }
182
+ else {
183
+ return #{::Native.call(@native, key)}
184
+ }
185
+ }
186
+ end
187
+
188
+ def []=(key, value)
189
+ native = Native.try_convert(value)
190
+
191
+ if `#{native} === nil`
192
+ `#@native[key] = #{value}`
193
+ else
194
+ `#@native[key] = #{native}`
195
+ end
196
+ end
197
+
198
+ def method_missing(mid, *args, &block)
199
+ %x{
200
+ if (mid.charAt(mid.length - 1) === '=') {
201
+ return #{self[mid.slice(0, mid.length - 1)] = args[0]};
202
+ }
203
+ else {
204
+ return #{::Native.call(@native, mid, *args, &block)};
205
+ }
206
+ }
207
+ end
208
+
209
+ def nil?
210
+ false
211
+ end
212
+
213
+ def is_a?(klass)
214
+ klass == Native
215
+ end
216
+
217
+ alias kind_of? is_a?
218
+
219
+ def instance_of?(klass)
220
+ klass == Native
221
+ end
222
+
223
+ def class
224
+ `self._klass`
225
+ end
226
+
227
+ def to_a(options = {}, &block)
228
+ Native::Array.new(@native, options, &block).to_a
229
+ end
230
+
231
+ def to_ary(options = {}, &block)
232
+ Native::Array.new(@native, options, &block)
233
+ end
234
+
235
+ def inspect
236
+ "#<Native:#{`String(#@native)`}>"
237
+ end
238
+ end
239
+
240
+ class Array
241
+ include Native
242
+ include Enumerable
243
+
244
+ def initialize(native, options = {}, &block)
245
+ super(native)
246
+
247
+ @get = options[:get] || options[:access]
248
+ @named = options[:named]
249
+ @set = options[:set] || options[:access]
250
+ @length = options[:length] || :length
251
+ @block = block
252
+
253
+ if `#{length} == null`
254
+ raise ArgumentError, "no length found on the array-like object"
255
+ end
256
+ end
257
+
258
+ def each(&block)
259
+ return enum_for :each unless block
260
+
261
+ index = 0
262
+ length = self.length
263
+
264
+ while index < length
265
+ block.call(self[index])
266
+
267
+ index += 1
268
+ end
269
+
270
+ self
271
+ end
272
+
273
+ def [](index)
274
+ result = case index
275
+ when String, Symbol
276
+ @named ? `#@native[#@named](#{index})` : `#@native[#{index}]`
277
+
278
+ when Integer
279
+ @get ? `#@native[#@get](#{index})` : `#@native[#{index}]`
280
+ end
281
+
282
+ if result
283
+ if @block
284
+ @block.call(result)
285
+ else
286
+ Native(result)
287
+ end
288
+ end
289
+ end
290
+
291
+ def []=(index, value)
292
+ if @set
293
+ `#@native[#@set](#{index}, #{value})`
294
+ else
295
+ `#@native[#{index}] = #{value}`
296
+ end
297
+ end
298
+
299
+ def last(count = nil)
300
+ if count
301
+ index = length - 1
302
+ result = []
303
+
304
+ while index >= 0
305
+ result << self[index]
306
+ index -= 1
307
+ end
308
+
309
+ result
310
+ else
311
+ self[length - 1]
312
+ end
313
+ end
314
+
315
+ def length
316
+ `#@native[#@length]`
317
+ end
318
+
319
+ def to_ary
320
+ self
321
+ end
322
+
323
+ def inspect
324
+ to_a.inspect
325
+ end
326
+ end
327
+ end
328
+
329
+ class Numeric
330
+ def to_n
331
+ `self.valueOf()`
332
+ end
333
+ end
334
+
335
+ class Proc
336
+ def to_n
337
+ self
338
+ end
339
+ end
340
+
341
+ class String
342
+ def to_n
343
+ `self.valueOf()`
344
+ end
345
+ end
346
+
347
+ class Regexp
348
+ def to_n
349
+ `self.valueOf()`
350
+ end
351
+ end
352
+
353
+ class MatchData
354
+ def to_n
355
+ @matches
356
+ end
357
+ end
358
+
359
+ class Struct
360
+ def initialize(*args)
361
+ if args.length == 1 && native?(args[0])
362
+ object = args[0]
363
+
364
+ members.each {|name|
365
+ instance_variable_set "@#{name}", Native(`#{object}[#{name}]`)
366
+ }
367
+ else
368
+ members.each_with_index {|name, index|
369
+ instance_variable_set "@#{name}", args[index]
370
+ }
371
+ end
372
+ end
373
+
374
+ def to_n
375
+ result = `{}`
376
+
377
+ each_pair {|name, value|
378
+ `#{result}[#{name}] = #{value.to_n}`
379
+ }
380
+
381
+ result
382
+ end
383
+ end
384
+
385
+ class Array
386
+ def to_n
387
+ %x{
388
+ var result = [];
389
+
390
+ for (var i = 0, length = self.length; i < length; i++) {
391
+ var obj = self[i];
392
+
393
+ if (#{`obj`.respond_to? :to_n}) {
394
+ result.push(#{`obj`.to_n});
395
+ }
396
+ else {
397
+ result.push(obj);
398
+ }
399
+ }
400
+
401
+ return result;
402
+ }
403
+ end
404
+ end
405
+
406
+ class Boolean
407
+ def to_n
408
+ `self.valueOf()`
409
+ end
410
+ end
411
+
412
+ class Time
413
+ def to_n
414
+ self
415
+ end
416
+ end
417
+
418
+ class NilClass
419
+ def to_n
420
+ `null`
421
+ end
422
+ end
423
+
424
+ class Hash
425
+ def initialize(defaults = undefined, &block)
426
+ %x{
427
+ if (defaults != null) {
428
+ if (defaults.constructor === Object) {
429
+ var map = self.map,
430
+ keys = self.keys;
431
+
432
+ for (var key in defaults) {
433
+ var value = defaults[key];
434
+
435
+ if (value && value.constructor === Object) {
436
+ map[key] = #{Hash.new(`value`)};
437
+ }
438
+ else {
439
+ map[key] = #{Native(`defaults[key]`)};
440
+ }
441
+
442
+ keys.push(key);
443
+ }
444
+ }
445
+ else {
446
+ self.none = defaults;
447
+ }
448
+ }
449
+ else if (block !== nil) {
450
+ self.proc = block;
451
+ }
452
+
453
+ return self;
454
+ }
455
+ end
456
+
457
+ def to_n
458
+ %x{
459
+ var result = {},
460
+ keys = self.keys,
461
+ map = self.map,
462
+ bucket,
463
+ value;
464
+
465
+ for (var i = 0, length = keys.length; i < length; i++) {
466
+ var key = keys[i],
467
+ obj = map[key];
468
+
469
+ if (#{`obj`.respond_to? :to_n}) {
470
+ result[key] = #{`obj`.to_n};
471
+ }
472
+ else {
473
+ result[key] = obj;
474
+ }
475
+ }
476
+
477
+ return result;
478
+ }
479
+ end
480
+ end
481
+
482
+ # native global
483
+ $$ = $global = Native(`Opal.global`)