opal 0.3.44 → 0.4.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.
- data/.travis.yml +0 -1
- data/CHANGELOG.md +52 -0
- data/README.md +3 -3
- data/Rakefile +32 -8
- data/bin/opal +69 -16
- data/config.ru +1 -1
- data/examples/native/app/app.rb +28 -9
- data/examples/rack/app/app.rb +1 -1
- data/lib/opal.rb +0 -1
- data/lib/opal/cli.rb +106 -0
- data/lib/opal/lexer.rb +4 -2
- data/lib/opal/parser.rb +603 -360
- data/lib/opal/processor.rb +20 -8
- data/lib/opal/server.rb +47 -0
- data/lib/opal/source_map.rb +63 -0
- data/lib/opal/sprockets_parser.rb +77 -0
- data/lib/opal/sprockets_source_map_header.rb +21 -0
- data/lib/opal/target_scope.rb +14 -7
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +2 -0
- data/opal/opal-browser/script_loader.rb +7 -7
- data/opal/opal-parser.js.erb +2 -2
- data/opal/opal-source-maps.js.erb +2 -0
- data/opal/opal.rb +3 -4
- data/opal/opal/array.rb +31 -28
- data/opal/opal/boolean.rb +4 -0
- data/opal/opal/class.rb +14 -5
- data/opal/opal/enumerable.rb +68 -8
- data/opal/opal/error.rb +1 -1
- data/opal/opal/hash.rb +15 -18
- data/opal/opal/kernel.rb +24 -10
- data/opal/opal/native.rb +31 -0
- data/opal/opal/nil_class.rb +7 -2
- data/opal/opal/numeric.rb +10 -1
- data/opal/opal/proc.rb +4 -0
- data/opal/opal/range.rb +1 -1
- data/opal/opal/regexp.rb +13 -3
- data/opal/opal/runtime.js +134 -51
- data/opal/opal/string.rb +45 -22
- data/opal/opal/time.rb +25 -7
- data/opal/source_map.rb +63 -0
- data/opal/source_map/generator.rb +251 -0
- data/opal/source_map/parser.rb +102 -0
- data/opal/source_map/vlq.rb +122 -0
- data/opal/strscan.rb +30 -12
- data/spec/opal/class/_inherited_spec.rb +1 -1
- data/spec/{rubyspec/core → opal}/class/bridge_class_spec.rb +5 -3
- data/spec/{rubyspec/core → opal}/class/extend_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/class/instance_methods_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/class/last_value_spec.rb +0 -1
- data/spec/{rubyspec/core → opal}/json/parse_spec.rb +0 -0
- data/spec/{rubyspec/core/kernel/block_given.rb → opal/kernel/block_given_spec.rb} +0 -0
- data/spec/{rubyspec/core → opal}/kernel/class_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/extend_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/format_spec.rb +0 -0
- data/spec/opal/kernel/freeze_spec.rb +15 -0
- data/spec/{rubyspec/core → opal}/kernel/match_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/method_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/methods_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/nil_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/p_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/printf_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/proc_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/rand_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/respond_to_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/sprintf_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/kernel/to_json_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/alias_method_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/ancestors_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/append_features_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/constants_spec.rb +0 -0
- data/spec/{rubyspec/core → opal}/module/module_function_spec.rb +0 -1
- data/spec/opal/native_spec.rb +85 -3
- data/spec/opal/numeric/equal_spec.rb +9 -0
- data/spec/opal/parser/irb_spec.rb +43 -0
- data/spec/{rubyspec/core → opal}/proc/proc_tricks_spec.rb +0 -0
- data/spec/opal/runtime/block_send_spec.rb +28 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/call_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/class_hierarchy_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/def_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/defined_spec.rb +0 -0
- data/spec/{rubyspec/core/runtime → opal/runtime2}/super_spec.rb +0 -0
- data/spec/opal/source_map_spec.rb +19 -0
- data/spec/opal/string/freeze_spec.rb +15 -0
- data/spec/{rubyspec/core → opal}/string/to_json_spec.rb +0 -0
- data/spec/ospec/runner.rb +3 -0
- data/spec/parser/str_spec.rb +4 -0
- data/spec/rubyspec/core/enumerable/fixtures/classes.rb +2 -2
- data/spec/rubyspec/core/enumerable/none_spec.rb +68 -0
- data/spec/rubyspec/core/enumerable/sort_by_spec.rb +31 -0
- data/spec/rubyspec/core/hash/size_spec.rb +1 -1
- data/spec/rubyspec/core/hash/to_native_spec.rb +3 -3
- data/spec/rubyspec/core/string/fixtures/classes.rb +49 -0
- data/spec/rubyspec/core/string/index_spec.rb +405 -0
- data/spec/rubyspec/filters/bugs/language/class.rb +0 -2
- data/spec/rubyspec/filters/bugs/language/module.rb +3 -0
- data/spec/rubyspec/language/array_spec.rb +1 -1
- data/spec/rubyspec/language/block_spec.rb +1 -1
- data/spec/rubyspec/language/module_spec.rb +5 -5
- data/spec/rubyspec/language/predefined_spec.rb +1 -2
- data/spec/rubyspec/library/stringscanner/element_reference_spec.rb +29 -0
- data/spec/rubyspec/spec_helper.rb +31 -0
- metadata +130 -76
- data/lib/opal/erb.rb +0 -41
- data/opal/erb.rb +0 -19
- data/spec/opal/erb/erb_spec.rb +0 -31
- data/spec/simple_erb_template.opalerb +0 -1
- data/spec/templates/foo/bar.opalerb +0 -1
- data/spec/templates/prefixed.opalerb +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
class SourceMap
|
|
2
|
+
# Support for encoding/decoding the variable length quantity format
|
|
3
|
+
# described in the spec at:
|
|
4
|
+
#
|
|
5
|
+
# https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
|
|
6
|
+
#
|
|
7
|
+
# This implementation is heavily based on https://github.com/mozilla/source-map
|
|
8
|
+
# Copyright 2009-2011, Mozilla Foundation and contributors, BSD
|
|
9
|
+
#
|
|
10
|
+
module VLQ
|
|
11
|
+
|
|
12
|
+
# A single base 64 digit can contain 6 bits of data. For the base 64 variable
|
|
13
|
+
# length quantities we use in the source map spec, the first bit is the sign,
|
|
14
|
+
# the next four bits are the actual value, and the 6th bit is the
|
|
15
|
+
# continuation bit. The continuation bit tells us whether there are more
|
|
16
|
+
# digits in this value following this digit.
|
|
17
|
+
#
|
|
18
|
+
# Continuation
|
|
19
|
+
# | Sign
|
|
20
|
+
# | |
|
|
21
|
+
# V V
|
|
22
|
+
# 101011
|
|
23
|
+
|
|
24
|
+
VLQ_BASE_SHIFT = 5;
|
|
25
|
+
|
|
26
|
+
# binary: 100000
|
|
27
|
+
VLQ_BASE = 1 << VLQ_BASE_SHIFT;
|
|
28
|
+
|
|
29
|
+
# binary: 011111
|
|
30
|
+
VLQ_BASE_MASK = VLQ_BASE - 1;
|
|
31
|
+
|
|
32
|
+
# binary: 100000
|
|
33
|
+
VLQ_CONTINUATION_BIT = VLQ_BASE;
|
|
34
|
+
|
|
35
|
+
BASE64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')
|
|
36
|
+
BASE64_VALUES = (0..64).inject({}){ |h, i| h.update BASE64_DIGITS[i] => i }
|
|
37
|
+
|
|
38
|
+
# Returns the base 64 VLQ encoded value.
|
|
39
|
+
def self.encode(int)
|
|
40
|
+
|
|
41
|
+
vlq = to_vlq_signed(int)
|
|
42
|
+
encoded = []
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
digit = vlq & VLQ_BASE_MASK
|
|
46
|
+
vlq >>= VLQ_BASE_SHIFT
|
|
47
|
+
digit |= VLQ_CONTINUATION_BIT if vlq > 0
|
|
48
|
+
encoded << base64_encode(digit)
|
|
49
|
+
end while vlq > 0
|
|
50
|
+
|
|
51
|
+
encoded.join
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Decodes the next base 64 VLQ value from the given string and returns the
|
|
55
|
+
# value and the rest of the string.
|
|
56
|
+
def self.decode(str)
|
|
57
|
+
|
|
58
|
+
vlq = 0
|
|
59
|
+
shift = 0
|
|
60
|
+
continue = true
|
|
61
|
+
chars = str.split('')
|
|
62
|
+
|
|
63
|
+
while continue
|
|
64
|
+
char = chars.shift or raise "Expected more digits in base 64 VLQ value."
|
|
65
|
+
digit = base64_decode(char)
|
|
66
|
+
continue = false if (digit & VLQ_CONTINUATION_BIT) == 0
|
|
67
|
+
digit &= VLQ_BASE_MASK
|
|
68
|
+
vlq += digit << shift
|
|
69
|
+
shift += VLQ_BASE_SHIFT
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
[from_vlq_signed(vlq), chars.join('')]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Decode an array of variable length quantities from the given string and
|
|
76
|
+
# return them.
|
|
77
|
+
def self.decode_array(str)
|
|
78
|
+
output = []
|
|
79
|
+
while str != ''
|
|
80
|
+
int, str = decode(str)
|
|
81
|
+
output << int
|
|
82
|
+
end
|
|
83
|
+
output
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
protected
|
|
87
|
+
|
|
88
|
+
def self.base64_encode(int)
|
|
89
|
+
BASE64_DIGITS[int] or raise ArgumentError, "#{int} is not a valid base64 digit"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.base64_decode(char)
|
|
93
|
+
BASE64_VALUES[char] or raise ArgumentError, "#{char} is not a valid base64 digit"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Converts from a two's-complement integer to an integer where the
|
|
97
|
+
# sign bit is placed in the least significant bit. For example, as decimals:
|
|
98
|
+
# 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
|
|
99
|
+
# 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
|
100
|
+
def self.to_vlq_signed(int)
|
|
101
|
+
if int < 0
|
|
102
|
+
((-int) << 1) + 1
|
|
103
|
+
else
|
|
104
|
+
int << 1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Converts to a two's-complement value from a value where the sign bit is
|
|
109
|
+
# placed in the least significant bit. For example, as decimals:
|
|
110
|
+
#
|
|
111
|
+
# 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
|
|
112
|
+
# 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
|
|
113
|
+
def self.from_vlq_signed(vlq)
|
|
114
|
+
if vlq & 1 == 1
|
|
115
|
+
-(vlq >> 1)
|
|
116
|
+
else
|
|
117
|
+
vlq >> 1
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
end
|
data/opal/strscan.rb
CHANGED
|
@@ -7,6 +7,7 @@ class StringScanner
|
|
|
7
7
|
@pos = 0
|
|
8
8
|
@matched = nil
|
|
9
9
|
@working = string
|
|
10
|
+
@match = []
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def scan(regex)
|
|
@@ -15,12 +16,13 @@ class StringScanner
|
|
|
15
16
|
result = regex.exec(#@working);
|
|
16
17
|
|
|
17
18
|
if (result == null) {
|
|
18
|
-
return
|
|
19
|
+
return #{self}.matched = nil;
|
|
19
20
|
}
|
|
20
21
|
else if (typeof(result) === 'object') {
|
|
21
22
|
#@pos += result[0].length;
|
|
22
23
|
#@working = #@working.substring(result[0].length);
|
|
23
24
|
#@matched = result[0];
|
|
25
|
+
#@match = result;
|
|
24
26
|
|
|
25
27
|
return result[0];
|
|
26
28
|
}
|
|
@@ -36,16 +38,32 @@ class StringScanner
|
|
|
36
38
|
}
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
def [](idx)
|
|
42
|
+
%x{
|
|
43
|
+
var match = #@match;
|
|
44
|
+
|
|
45
|
+
if (idx < 0) {
|
|
46
|
+
idx += match.length;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (idx < 0 || idx >= match.length) {
|
|
50
|
+
return nil;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return match[idx];
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
39
57
|
def check(regex)
|
|
40
58
|
%x{
|
|
41
59
|
var regexp = new RegExp('^' + regex.toString().substring(1, regex.toString().length - 1)),
|
|
42
60
|
result = regexp.exec(#@working);
|
|
43
61
|
|
|
44
62
|
if (result == null) {
|
|
45
|
-
return
|
|
63
|
+
return #{self}.matched = nil;
|
|
46
64
|
}
|
|
47
65
|
|
|
48
|
-
return
|
|
66
|
+
return #{self}.matched = result[0];
|
|
49
67
|
}
|
|
50
68
|
end
|
|
51
69
|
|
|
@@ -63,14 +81,14 @@ class StringScanner
|
|
|
63
81
|
var result = re.exec(#@working);
|
|
64
82
|
|
|
65
83
|
if (result == null) {
|
|
66
|
-
return
|
|
84
|
+
return #{self}.matched = nil;
|
|
67
85
|
}
|
|
68
86
|
else {
|
|
69
87
|
var match_str = result[0];
|
|
70
88
|
var match_len = match_str.length;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
#{self}.matched = match_str;
|
|
90
|
+
#{self}.pos += match_len;
|
|
91
|
+
#{self}.working = #{self}.working.substring(match_len);
|
|
74
92
|
return match_len;
|
|
75
93
|
}
|
|
76
94
|
}
|
|
@@ -79,13 +97,13 @@ class StringScanner
|
|
|
79
97
|
def get_byte()
|
|
80
98
|
%x{
|
|
81
99
|
var result = nil;
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
result =
|
|
85
|
-
|
|
100
|
+
if (#{self}.pos < #{self}.string.length) {
|
|
101
|
+
#{self}.pos += 1;
|
|
102
|
+
result = #{self}.matched = #{self}.working.substring(0, 1);
|
|
103
|
+
#{self}.working = #{self}.working.substring(1);
|
|
86
104
|
}
|
|
87
105
|
else {
|
|
88
|
-
|
|
106
|
+
#{self}.matched = nil;
|
|
89
107
|
}
|
|
90
108
|
|
|
91
109
|
return result;
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Class.bridge_class :BridgeClassSpec, `BridgeClassProto`
|
|
13
|
+
|
|
14
|
+
class BridgeClassSpec
|
|
13
15
|
def get_foo
|
|
14
16
|
`#{self}.foo`
|
|
15
17
|
end
|
|
@@ -19,7 +21,7 @@ class BridgeClassSpec < `BridgeClassProto`
|
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
describe "
|
|
24
|
+
describe "Class#bridge_class" do
|
|
23
25
|
it "should have a superclass of Object" do
|
|
24
26
|
BridgeClassSpec.superclass.should == Object
|
|
25
27
|
end
|
|
@@ -34,4 +36,4 @@ describe "Bridging native prototypes to a class" do
|
|
|
34
36
|
obj.get_foo.should == 200
|
|
35
37
|
obj.say_it.should == "hello world"
|
|
36
38
|
end
|
|
37
|
-
end
|
|
39
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# No real support, just mocking
|
|
2
|
+
|
|
3
|
+
describe "Kernel#freeze" do
|
|
4
|
+
it 'responds to #freeze and #frozen?' do
|
|
5
|
+
o = mock('o')
|
|
6
|
+
o.frozen?.should be_false
|
|
7
|
+
o.freeze
|
|
8
|
+
o.frozen?.should be_true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "returns self" do
|
|
12
|
+
o = Object.new
|
|
13
|
+
o.freeze.should equal(o)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/spec/opal/native_spec.rb
CHANGED
|
@@ -20,6 +20,14 @@ require 'spec_helper'
|
|
|
20
20
|
|
|
21
21
|
child_object: {
|
|
22
22
|
grand_child: 100
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
func_returning_null: function() {
|
|
26
|
+
return null;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
func_returning_undefined: function() {
|
|
30
|
+
return undefined;
|
|
23
31
|
}
|
|
24
32
|
};
|
|
25
33
|
}
|
|
@@ -71,13 +79,18 @@ describe "Native objects" do
|
|
|
71
79
|
@obj.check_args(1, 2, 3).should == [1, 2, 3]
|
|
72
80
|
end
|
|
73
81
|
|
|
74
|
-
it "tries to convert each argument with
|
|
82
|
+
it "tries to convert each argument with to_n if defined" do
|
|
75
83
|
obj, obj2, obj3 = Object.new, Object.new, Object.new
|
|
76
|
-
def obj.
|
|
77
|
-
def obj2.
|
|
84
|
+
def obj.to_n; "foo"; end
|
|
85
|
+
def obj2.to_n; 42; end
|
|
78
86
|
|
|
79
87
|
@obj.check_args(obj, obj2, obj3).should == ["foo", 42, obj3]
|
|
80
88
|
end
|
|
89
|
+
|
|
90
|
+
it "converts null/undefined values to nil from function" do
|
|
91
|
+
@obj.func_returning_null.should be_nil
|
|
92
|
+
@obj.func_returning_undefined.should be_nil
|
|
93
|
+
end
|
|
81
94
|
end
|
|
82
95
|
|
|
83
96
|
describe "#[]" do
|
|
@@ -110,6 +123,22 @@ describe "Native objects" do
|
|
|
110
123
|
end
|
|
111
124
|
end
|
|
112
125
|
|
|
126
|
+
describe "#[]=" do
|
|
127
|
+
it "sets values on the receiver object" do
|
|
128
|
+
object = `{}`
|
|
129
|
+
|
|
130
|
+
object["foo"] = 42
|
|
131
|
+
object["foo"].should == 42
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "sets null on the object when nil given as value" do
|
|
135
|
+
object = `{}`
|
|
136
|
+
|
|
137
|
+
object["foo"] = nil
|
|
138
|
+
`(object.foo === null)`.should be_true
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
113
142
|
describe "==" do
|
|
114
143
|
it "returns true if the wrapped objects are `===` to each other" do
|
|
115
144
|
%x{
|
|
@@ -124,4 +153,57 @@ describe "Native objects" do
|
|
|
124
153
|
(a == c).should be_false
|
|
125
154
|
end
|
|
126
155
|
end
|
|
156
|
+
|
|
157
|
+
describe "each" do
|
|
158
|
+
describe "with an array-like object" do
|
|
159
|
+
it "yields each element to block" do
|
|
160
|
+
object = `{ "0": 3.142, "1": 42, "length": 2 }`
|
|
161
|
+
result = []
|
|
162
|
+
|
|
163
|
+
object.each { |obj| result << obj }
|
|
164
|
+
result.should == [3.142, 42]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "yields null and undefined values as nil" do
|
|
168
|
+
object = `{length: 3, 0: null, 1: undefined}`
|
|
169
|
+
result = []
|
|
170
|
+
|
|
171
|
+
object.each { |obj| result << obj }
|
|
172
|
+
result.should == [nil, nil, nil]
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
describe "with a normal js object" do
|
|
177
|
+
it "yields each key-value pair to the block" do
|
|
178
|
+
object = `{"foo": 3.142, "bar": 42}`
|
|
179
|
+
result = []
|
|
180
|
+
|
|
181
|
+
object.each { |k, v| result << [k, v] }
|
|
182
|
+
result.should == [["foo", 3.142], ["bar", 42]]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "yields null and undefined values as nil" do
|
|
186
|
+
object = `{"foo": null, "bar": undefined}`
|
|
187
|
+
result = []
|
|
188
|
+
|
|
189
|
+
object.each { |k, v| result << v }
|
|
190
|
+
result.should == [nil, nil]
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe "#to_h" do
|
|
196
|
+
it "converts a simple js object into a ruby hash" do
|
|
197
|
+
object = `{"foo": true, "bar": 42}`
|
|
198
|
+
hash = object.to_h
|
|
199
|
+
|
|
200
|
+
hash.should be_kind_of(Hash)
|
|
201
|
+
hash.should == {"foo" => true, "bar" => 42}
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "converts all null and undefined values to nil" do
|
|
205
|
+
object = `{"a": null, "b": undefined}`
|
|
206
|
+
object.to_h.should == {"a" => nil, "b" => nil}
|
|
207
|
+
end
|
|
208
|
+
end
|
|
127
209
|
end
|