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.
Files changed (109) hide show
  1. data/.travis.yml +0 -1
  2. data/CHANGELOG.md +52 -0
  3. data/README.md +3 -3
  4. data/Rakefile +32 -8
  5. data/bin/opal +69 -16
  6. data/config.ru +1 -1
  7. data/examples/native/app/app.rb +28 -9
  8. data/examples/rack/app/app.rb +1 -1
  9. data/lib/opal.rb +0 -1
  10. data/lib/opal/cli.rb +106 -0
  11. data/lib/opal/lexer.rb +4 -2
  12. data/lib/opal/parser.rb +603 -360
  13. data/lib/opal/processor.rb +20 -8
  14. data/lib/opal/server.rb +47 -0
  15. data/lib/opal/source_map.rb +63 -0
  16. data/lib/opal/sprockets_parser.rb +77 -0
  17. data/lib/opal/sprockets_source_map_header.rb +21 -0
  18. data/lib/opal/target_scope.rb +14 -7
  19. data/lib/opal/version.rb +1 -1
  20. data/opal.gemspec +2 -0
  21. data/opal/opal-browser/script_loader.rb +7 -7
  22. data/opal/opal-parser.js.erb +2 -2
  23. data/opal/opal-source-maps.js.erb +2 -0
  24. data/opal/opal.rb +3 -4
  25. data/opal/opal/array.rb +31 -28
  26. data/opal/opal/boolean.rb +4 -0
  27. data/opal/opal/class.rb +14 -5
  28. data/opal/opal/enumerable.rb +68 -8
  29. data/opal/opal/error.rb +1 -1
  30. data/opal/opal/hash.rb +15 -18
  31. data/opal/opal/kernel.rb +24 -10
  32. data/opal/opal/native.rb +31 -0
  33. data/opal/opal/nil_class.rb +7 -2
  34. data/opal/opal/numeric.rb +10 -1
  35. data/opal/opal/proc.rb +4 -0
  36. data/opal/opal/range.rb +1 -1
  37. data/opal/opal/regexp.rb +13 -3
  38. data/opal/opal/runtime.js +134 -51
  39. data/opal/opal/string.rb +45 -22
  40. data/opal/opal/time.rb +25 -7
  41. data/opal/source_map.rb +63 -0
  42. data/opal/source_map/generator.rb +251 -0
  43. data/opal/source_map/parser.rb +102 -0
  44. data/opal/source_map/vlq.rb +122 -0
  45. data/opal/strscan.rb +30 -12
  46. data/spec/opal/class/_inherited_spec.rb +1 -1
  47. data/spec/{rubyspec/core → opal}/class/bridge_class_spec.rb +5 -3
  48. data/spec/{rubyspec/core → opal}/class/extend_spec.rb +0 -0
  49. data/spec/{rubyspec/core → opal}/class/instance_methods_spec.rb +0 -0
  50. data/spec/{rubyspec/core → opal}/class/last_value_spec.rb +0 -1
  51. data/spec/{rubyspec/core → opal}/json/parse_spec.rb +0 -0
  52. data/spec/{rubyspec/core/kernel/block_given.rb → opal/kernel/block_given_spec.rb} +0 -0
  53. data/spec/{rubyspec/core → opal}/kernel/class_spec.rb +0 -0
  54. data/spec/{rubyspec/core → opal}/kernel/extend_spec.rb +0 -0
  55. data/spec/{rubyspec/core → opal}/kernel/format_spec.rb +0 -0
  56. data/spec/opal/kernel/freeze_spec.rb +15 -0
  57. data/spec/{rubyspec/core → opal}/kernel/match_spec.rb +0 -0
  58. data/spec/{rubyspec/core → opal}/kernel/method_spec.rb +0 -0
  59. data/spec/{rubyspec/core → opal}/kernel/methods_spec.rb +0 -0
  60. data/spec/{rubyspec/core → opal}/kernel/nil_spec.rb +0 -0
  61. data/spec/{rubyspec/core → opal}/kernel/p_spec.rb +0 -0
  62. data/spec/{rubyspec/core → opal}/kernel/printf_spec.rb +0 -0
  63. data/spec/{rubyspec/core → opal}/kernel/proc_spec.rb +0 -0
  64. data/spec/{rubyspec/core → opal}/kernel/rand_spec.rb +0 -0
  65. data/spec/{rubyspec/core → opal}/kernel/respond_to_spec.rb +0 -0
  66. data/spec/{rubyspec/core → opal}/kernel/sprintf_spec.rb +0 -0
  67. data/spec/{rubyspec/core → opal}/kernel/to_json_spec.rb +0 -0
  68. data/spec/{rubyspec/core → opal}/module/alias_method_spec.rb +0 -0
  69. data/spec/{rubyspec/core → opal}/module/ancestors_spec.rb +0 -0
  70. data/spec/{rubyspec/core → opal}/module/append_features_spec.rb +0 -0
  71. data/spec/{rubyspec/core → opal}/module/constants_spec.rb +0 -0
  72. data/spec/{rubyspec/core → opal}/module/module_function_spec.rb +0 -1
  73. data/spec/opal/native_spec.rb +85 -3
  74. data/spec/opal/numeric/equal_spec.rb +9 -0
  75. data/spec/opal/parser/irb_spec.rb +43 -0
  76. data/spec/{rubyspec/core → opal}/proc/proc_tricks_spec.rb +0 -0
  77. data/spec/opal/runtime/block_send_spec.rb +28 -0
  78. data/spec/{rubyspec/core/runtime → opal/runtime2}/call_spec.rb +0 -0
  79. data/spec/{rubyspec/core/runtime → opal/runtime2}/class_hierarchy_spec.rb +0 -0
  80. data/spec/{rubyspec/core/runtime → opal/runtime2}/def_spec.rb +0 -0
  81. data/spec/{rubyspec/core/runtime → opal/runtime2}/defined_spec.rb +0 -0
  82. data/spec/{rubyspec/core/runtime → opal/runtime2}/super_spec.rb +0 -0
  83. data/spec/opal/source_map_spec.rb +19 -0
  84. data/spec/opal/string/freeze_spec.rb +15 -0
  85. data/spec/{rubyspec/core → opal}/string/to_json_spec.rb +0 -0
  86. data/spec/ospec/runner.rb +3 -0
  87. data/spec/parser/str_spec.rb +4 -0
  88. data/spec/rubyspec/core/enumerable/fixtures/classes.rb +2 -2
  89. data/spec/rubyspec/core/enumerable/none_spec.rb +68 -0
  90. data/spec/rubyspec/core/enumerable/sort_by_spec.rb +31 -0
  91. data/spec/rubyspec/core/hash/size_spec.rb +1 -1
  92. data/spec/rubyspec/core/hash/to_native_spec.rb +3 -3
  93. data/spec/rubyspec/core/string/fixtures/classes.rb +49 -0
  94. data/spec/rubyspec/core/string/index_spec.rb +405 -0
  95. data/spec/rubyspec/filters/bugs/language/class.rb +0 -2
  96. data/spec/rubyspec/filters/bugs/language/module.rb +3 -0
  97. data/spec/rubyspec/language/array_spec.rb +1 -1
  98. data/spec/rubyspec/language/block_spec.rb +1 -1
  99. data/spec/rubyspec/language/module_spec.rb +5 -5
  100. data/spec/rubyspec/language/predefined_spec.rb +1 -2
  101. data/spec/rubyspec/library/stringscanner/element_reference_spec.rb +29 -0
  102. data/spec/rubyspec/spec_helper.rb +31 -0
  103. metadata +130 -76
  104. data/lib/opal/erb.rb +0 -41
  105. data/opal/erb.rb +0 -19
  106. data/spec/opal/erb/erb_spec.rb +0 -31
  107. data/spec/simple_erb_template.opalerb +0 -1
  108. data/spec/templates/foo/bar.opalerb +0 -1
  109. 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
@@ -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 this.matched = nil;
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 this.matched = nil;
63
+ return #{self}.matched = nil;
46
64
  }
47
65
 
48
- return this.matched = result[0];
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 this.matched = nil;
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
- this.matched = match_str;
72
- this.pos += match_len;
73
- this.working = this.working.substring(match_len);
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 (this.pos < this.string.length) {
83
- this.pos += 1;
84
- result = this.matched = this.working.substring(0, 1);
85
- this.working = this.working.substring(1);
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
- this.matched = nil;
106
+ #{self}.matched = nil;
89
107
  }
90
108
 
91
109
  return result;
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  class Class
4
4
  def get_inherited_classes
5
- `#{self}._inherited`
5
+ `#{self}._inherited || []`
6
6
  end
7
7
  end
8
8
 
@@ -9,7 +9,9 @@
9
9
  };
10
10
  }
11
11
 
12
- class BridgeClassSpec < `BridgeClassProto`
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 "Bridging native prototypes to a class" do
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
@@ -1,5 +1,4 @@
1
1
  require File.expand_path('../../../spec_helper', __FILE__)
2
- require File.expand_path('../fixtures/classes', __FILE__)
3
2
 
4
3
  describe 'Class definition returning its last value' do
5
4
  it 'with a number' do
@@ -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
@@ -1,5 +1,4 @@
1
1
  require File.expand_path('../../../spec_helper', __FILE__)
2
- require File.expand_path('../fixtures/classes', __FILE__)
3
2
 
4
3
  describe "Module#module_function with specific method names" do
5
4
  it "creates duplicates of the given instance methods on the Module object" do
@@ -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 to_native if defined" do
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.to_native; "foo"; end
77
- def obj2.to_native; 42; end
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
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Numeric#==" do
4
+ it "should be true when two js Number objects are compared" do
5
+ first = `new Number(42)`
6
+ second = `new Number(42)`
7
+ first.should == second
8
+ end
9
+ end