opal 1.4.0.alpha1 → 1.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +5 -3
  3. data/.github/workflows/build.yml +20 -18
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +98 -7
  6. data/UNRELEASED.md +31 -59
  7. data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
  8. data/docs/releasing.md +11 -4
  9. data/lib/opal/ast/matcher.rb +77 -0
  10. data/lib/opal/cache.rb +1 -1
  11. data/lib/opal/cli_runners/applescript.rb +2 -0
  12. data/lib/opal/compiler.rb +18 -9
  13. data/lib/opal/nodes/call.rb +73 -28
  14. data/lib/opal/nodes/def.rb +31 -27
  15. data/lib/opal/nodes/definitions.rb +2 -0
  16. data/lib/opal/nodes/helpers.rb +4 -23
  17. data/lib/opal/nodes/if.rb +226 -0
  18. data/lib/opal/nodes/iter.rb +41 -37
  19. data/lib/opal/nodes/literal.rb +2 -2
  20. data/lib/opal/nodes/masgn.rb +15 -17
  21. data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
  22. data/lib/opal/nodes/node_with_args.rb +1 -0
  23. data/lib/opal/nodes/super.rb +9 -9
  24. data/lib/opal/nodes/top.rb +26 -10
  25. data/lib/opal/nodes/x_string.rb +27 -28
  26. data/lib/opal/nodes.rb +0 -1
  27. data/lib/opal/parser/default_config.rb +3 -2
  28. data/lib/opal/repl.rb +1 -1
  29. data/lib/opal/rewriter.rb +13 -6
  30. data/lib/opal/rewriters/base.rb +12 -1
  31. data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
  32. data/lib/opal/version.rb +1 -1
  33. data/opal/corelib/array.rb +23 -28
  34. data/opal/corelib/binding.rb +14 -4
  35. data/opal/corelib/constants.rb +3 -3
  36. data/opal/corelib/hash.rb +2 -2
  37. data/opal/corelib/irb.rb +192 -0
  38. data/opal/corelib/math/polyfills.rb +127 -0
  39. data/opal/corelib/math.rb +14 -194
  40. data/opal/corelib/module.rb +25 -40
  41. data/opal/corelib/number.rb +63 -14
  42. data/opal/corelib/regexp.rb +2 -0
  43. data/opal/corelib/runtime.js +56 -20
  44. data/opal/corelib/string.rb +38 -59
  45. data/opal/corelib/time.rb +106 -68
  46. data/opal/opal/full.rb +0 -1
  47. data/opal/opal.rb +4 -1
  48. data/spec/filters/bugs/date.rb +0 -3
  49. data/spec/filters/bugs/datetime.rb +65 -0
  50. data/spec/filters/bugs/float.rb +0 -18
  51. data/spec/filters/bugs/hash.rb +0 -2
  52. data/spec/filters/bugs/language.rb +0 -3
  53. data/spec/filters/bugs/marshal.rb +0 -1
  54. data/spec/filters/bugs/string.rb +0 -30
  55. data/spec/filters/bugs/time.rb +18 -8
  56. data/spec/lib/cli_spec.rb +2 -2
  57. data/spec/lib/compiler_spec.rb +8 -8
  58. data/spec/lib/rewriters/base_spec.rb +1 -1
  59. data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
  60. data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
  61. data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
  62. data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
  63. data/spec/lib/rewriters/forward_args_spec.rb +2 -3
  64. data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
  65. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
  66. data/spec/lib/rewriters/numblocks_spec.rb +3 -5
  67. data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
  68. data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
  69. data/spec/opal/compiler/irb_spec.rb +4 -0
  70. data/spec/opal/core/language/super_spec.rb +40 -17
  71. data/spec/opal/core/language/xstring_spec.rb +13 -0
  72. data/spec/opal/core/regexp/assertions_spec.rb +19 -0
  73. data/spec/opal/core/string/to_proc_spec.rb +19 -0
  74. data/spec/ruby_specs +4 -0
  75. data/spec/support/rewriters_helper.rb +43 -23
  76. data/stdlib/date/date_time.rb +71 -0
  77. data/stdlib/date/formatters.rb +28 -0
  78. data/stdlib/date/infinity.rb +73 -0
  79. data/stdlib/date.rb +77 -214
  80. data/stdlib/opal/repl_js.rb +1 -1
  81. data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
  82. data/stdlib/promise/v2.rb +0 -7
  83. data/stdlib/time.rb +39 -2
  84. data/stdlib/uri.rb +53 -0
  85. data/tasks/performance/asciidoctor_test.rb.erb +3 -1
  86. data/tasks/performance/optimization_status.rb +3 -2
  87. data/tasks/performance.rake +69 -35
  88. data/tasks/testing.rake +1 -0
  89. data/test/opal/test_uri.rb +35 -0
  90. data/yarn.lock +27 -5
  91. metadata +30 -16
  92. data/lib/opal/nodes/csend.rb +0 -24
  93. data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
  94. data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
  95. data/stdlib/nodejs/irb.rb +0 -43
@@ -1,82 +1,57 @@
1
1
  require 'lib/spec_helper'
2
+ require 'support/rewriters_helper'
2
3
 
3
4
  RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
4
- def s(type, *children)
5
- ::Opal::AST::Node.new(type, children)
6
- end
7
-
8
- let(:rewriter) { Opal::Rewriters::LogicalOperatorAssignment.new }
5
+ include RewritersHelper
9
6
 
10
- def parse(source)
11
- parser = Opal::Parser.default_parser
12
- buffer = ::Opal::Parser::SourceBuffer.new('(eval)')
13
- buffer.source = source
14
- parser.parse(buffer)
15
- end
16
-
17
- def rewrite(ast)
18
- rewriter.process(ast)
19
- end
7
+ use_only_described_rewriter!
20
8
 
21
- around(:each) do |e|
22
- Opal::Rewriters::LogicalOperatorAssignment.reset_tmp_counter!
23
- Opal::Rewriter.disable { e.run }
24
- end
9
+ before(:each) { Opal::Rewriters::LogicalOperatorAssignment.reset_tmp_counter! }
25
10
  let(:cache_tmp_name) { :$logical_op_recvr_tmp_1 }
26
11
  let(:cached) { s(:js_tmp, cache_tmp_name) }
27
12
 
28
- shared_examples 'it rewrites' do |from, to|
29
- it "rewrites #{from.inspect} to #{to.inspect}" do
30
- input = parse(from)
31
- rewritten = rewrite(input)
32
- expected = parse(to)
33
-
34
- expect(rewritten).to eq(expected)
35
- end
36
- end
37
-
38
13
  context 'rewriting or_asgn and and_asgn nodes' do
39
14
  context 'local variable' do
40
- include_examples 'it rewrites', 'a = local; a ||= 1', 'a = local; a = a || 1'
41
- include_examples 'it rewrites', 'a = local; a &&= 1', 'a = local; a = a && 1'
15
+ include_examples 'it rewrites source-to-source', 'a = local; a ||= 1', 'a = local; a = a || 1'
16
+ include_examples 'it rewrites source-to-source', 'a = local; a &&= 1', 'a = local; a = a && 1'
42
17
  end
43
18
 
44
19
  context 'instance variable' do
45
- include_examples 'it rewrites', '@a ||= 1', '@a = @a || 1'
46
- include_examples 'it rewrites', '@a &&= 1', '@a = @a && 1'
20
+ include_examples 'it rewrites source-to-source', '@a ||= 1', '@a = @a || 1'
21
+ include_examples 'it rewrites source-to-source', '@a &&= 1', '@a = @a && 1'
47
22
  end
48
23
 
49
24
  context 'constant' do
50
- include_examples 'it rewrites', 'CONST ||= 1', 'CONST = defined?(CONST) ? (CONST || 1) : 1'
51
- include_examples 'it rewrites', 'CONST &&= 1', 'CONST = CONST && 1'
25
+ include_examples 'it rewrites source-to-source', 'CONST ||= 1', 'CONST = defined?(CONST) ? (CONST || 1) : 1'
26
+ include_examples 'it rewrites source-to-source', 'CONST &&= 1', 'CONST = CONST && 1'
52
27
  end
53
28
 
54
29
  context 'global variable' do
55
- include_examples 'it rewrites', '$g ||= 1', '$g = $g || 1'
56
- include_examples 'it rewrites', '$g &&= 1', '$g = $g && 1'
30
+ include_examples 'it rewrites source-to-source', '$g ||= 1', '$g = $g || 1'
31
+ include_examples 'it rewrites source-to-source', '$g &&= 1', '$g = $g && 1'
57
32
  end
58
33
 
59
34
  context 'class variable' do
60
- include_examples 'it rewrites', '@@a ||= 1', '@@a = defined?(@@a) ? (@@a || 1) : 1'
61
- include_examples 'it rewrites', '@@a &&= 1', '@@a = @@a && 1'
35
+ include_examples 'it rewrites source-to-source', '@@a ||= 1', '@@a = defined?(@@a) ? (@@a || 1) : 1'
36
+ include_examples 'it rewrites source-to-source', '@@a &&= 1', '@@a = @@a && 1'
62
37
  end
63
38
 
64
39
  context 'simple method call' do
65
- include_examples 'it rewrites', 'recvr = 1; recvr.meth ||= rhs', 'recvr = 1; recvr.meth || recvr.meth = rhs'
66
- include_examples 'it rewrites', 'recvr = 1; recvr.meth &&= rhs', 'recvr = 1; recvr.meth && recvr.meth = rhs'
40
+ include_examples 'it rewrites source-to-source', 'recvr = 1; recvr.meth ||= rhs', 'recvr = 1; recvr.meth || recvr.meth = rhs'
41
+ include_examples 'it rewrites source-to-source', 'recvr = 1; recvr.meth &&= rhs', 'recvr = 1; recvr.meth && recvr.meth = rhs'
67
42
  end
68
43
 
69
44
  context '[] / []= method call' do
70
- include_examples 'it rewrites', 'recvr = 1; recvr[idx] ||= rhs', 'recvr = 1; recvr[idx] || recvr[idx] = rhs'
71
- include_examples 'it rewrites', 'recvr = 1; recvr[idx] &&= rhs', 'recvr = 1; recvr[idx] && recvr[idx] = rhs'
45
+ include_examples 'it rewrites source-to-source', 'recvr = 1; recvr[idx] ||= rhs', 'recvr = 1; recvr[idx] || recvr[idx] = rhs'
46
+ include_examples 'it rewrites source-to-source', 'recvr = 1; recvr[idx] &&= rhs', 'recvr = 1; recvr[idx] && recvr[idx] = rhs'
72
47
  end
73
48
 
74
49
  context '[] / []= method call with multiple arguments' do
75
- include_examples 'it rewrites',
50
+ include_examples 'it rewrites source-to-source',
76
51
  'recvr = 1; recvr[idx1, idx2] ||= rhs',
77
52
  'recvr = 1; recvr[idx1, idx2] || recvr[idx1, idx2] = rhs'
78
53
 
79
- include_examples 'it rewrites',
54
+ include_examples 'it rewrites source-to-source',
80
55
  'recvr = 1; recvr[idx1, idx2] &&= rhs',
81
56
  'recvr = 1; recvr[idx1, idx2] && recvr[idx1, idx2] = rhs'
82
57
  end
@@ -84,26 +59,26 @@ RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
84
59
  context 'chain of method calls' do
85
60
  it 'rewrites ||= by caching receiver to a temporary local variable' do
86
61
  input = parse('recvr.a.b ||= rhs')
87
- rewritten = rewrite(input)
62
+ rewritten = rewrite(input).children.first
88
63
 
89
64
  expected = s(:begin,
90
- s(:lvasgn, cache_tmp_name, parse('recvr.a')), # cached = recvr.a
65
+ s(:lvasgn, cache_tmp_name, ast_of('recvr.a')), # cached = recvr.a
91
66
  s(:or,
92
- s(:send, cached, :b), # cached.b
93
- s(:send, cached, :b=, parse('rhs')))) # cached.b = rhs
67
+ s(:send, cached, :b), # cached.b ||
68
+ s(:send, cached, :b=, ast_of('rhs')))) # cached.b = rhs
94
69
 
95
70
  expect(rewritten).to eq(expected)
96
71
  end
97
72
 
98
73
  it 'rewrites &&= by caching receiver to a temporary local variable' do
99
74
  input = parse('recvr.a.b &&= rhs')
100
- rewritten = rewrite(input)
75
+ rewritten = rewrite(input).children.first
101
76
 
102
77
  expected = s(:begin,
103
- s(:lvasgn, cache_tmp_name, parse('recvr.a')), # cached = recvr.a
78
+ s(:lvasgn, cache_tmp_name, ast_of('recvr.a')), # cached = recvr.a
104
79
  s(:and,
105
- s(:send, cached, :b), # cached.b
106
- s(:send, cached, :b=, parse('rhs')))) # cached.b = rhs
80
+ s(:send, cached, :b), # cached.b ||
81
+ s(:send, cached, :b=, ast_of('rhs')))) # cached.b = rhs
107
82
 
108
83
  expect(rewritten).to eq(expected)
109
84
  end
@@ -112,17 +87,17 @@ RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
112
87
  context 'method call using safe nafigator' do
113
88
  it 'rewrites ||= by caching receiver and rewriting it to if and or_asgn' do
114
89
  input = parse('recvr&.meth ||= rhs')
115
- rewritten = rewrite(input)
90
+ rewritten = rewrite(input).children.first
116
91
 
117
92
  expected = s(:begin,
118
- s(:lvasgn, cache_tmp_name, parse('recvr')), # cached = recvr
119
- s(:if, s(:send, cached, :nil?), # if cached.nil?
120
- s(:nil), # nil
121
- # else
93
+ s(:lvasgn, cache_tmp_name, ast_of('recvr')), # cached = recvr
94
+ s(:if, s(:send, cached, :nil?), # if cached.nil?
95
+ s(:nil), # nil
96
+ # else
122
97
  s(:or,
123
- s(:send, cached, :meth), # cached.meth ||
124
- s(:send, cached, :meth=, parse('rhs'))) # cached.meth = rhs
125
- ) # end
98
+ s(:send, cached, :meth), # cached.meth ||
99
+ s(:send, cached, :meth=, ast_of('rhs'))) # cached.meth = rhs
100
+ ) # end
126
101
  )
127
102
 
128
103
  expect(rewritten).to eq(expected)
@@ -130,17 +105,17 @@ RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
130
105
 
131
106
  it 'rewrites &&= by caching receiver and rewriting it to if and or_asgn' do
132
107
  input = parse('recvr&.meth &&= rhs')
133
- rewritten = rewrite(input)
108
+ rewritten = rewrite(input).children.first
134
109
 
135
110
  expected = s(:begin,
136
- s(:lvasgn, cache_tmp_name, parse('recvr')), # cached = recvr
137
- s(:if, s(:send, cached, :nil?), # if cached.nil?
138
- s(:nil), # nil
139
- # else
111
+ s(:lvasgn, cache_tmp_name, ast_of('recvr')), # cached = recvr
112
+ s(:if, s(:send, cached, :nil?), # if cached.nil?
113
+ s(:nil), # nil
114
+ # else
140
115
  s(:and,
141
- s(:send, cached, :meth), # cached.meth ||
142
- s(:send, cached, :meth=, parse('rhs'))) # cached.meth = rhs
143
- ) # end
116
+ s(:send, cached, :meth), # cached.meth &&
117
+ s(:send, cached, :meth=, ast_of('rhs'))) # cached.meth = rhs
118
+ ) # end
144
119
  )
145
120
 
146
121
  expect(rewritten).to eq(expected)
@@ -150,53 +125,53 @@ RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
150
125
 
151
126
  context 'rewriting defined?(or_asgn) and defined?(and_asgn)' do
152
127
  context 'local variable' do
153
- include_examples 'it rewrites', 'a = nil; defined?(a ||= 1)', 'a = nil; "assignment"'
154
- include_examples 'it rewrites', 'a = nil; defined?(a &&= 1)', 'a = nil; "assignment"'
128
+ include_examples 'it rewrites source-to-source', 'a = nil; defined?(a ||= 1)', 'a = nil; "assignment"'
129
+ include_examples 'it rewrites source-to-source', 'a = nil; defined?(a &&= 1)', 'a = nil; "assignment"'
155
130
  end
156
131
 
157
132
  context 'instance variable' do
158
- include_examples 'it rewrites', 'defined?(@a ||= 1)', %q("assignment")
159
- include_examples 'it rewrites', 'defined?(@a &&= 1)', %q("assignment")
133
+ include_examples 'it rewrites source-to-source', 'defined?(@a ||= 1)', %q("assignment")
134
+ include_examples 'it rewrites source-to-source', 'defined?(@a &&= 1)', %q("assignment")
160
135
  end
161
136
 
162
137
  context 'constant' do
163
- include_examples 'it rewrites', 'defined?(CONST ||= 1)', %q("assignment")
164
- include_examples 'it rewrites', 'defined?(CONST &&= 1)', %q("assignment")
138
+ include_examples 'it rewrites source-to-source', 'defined?(CONST ||= 1)', %q("assignment")
139
+ include_examples 'it rewrites source-to-source', 'defined?(CONST &&= 1)', %q("assignment")
165
140
  end
166
141
 
167
142
  context 'global variable' do
168
- include_examples 'it rewrites', 'defined?($g ||= 1)', %q("assignment")
169
- include_examples 'it rewrites', 'defined?($g &&= 1)', %q("assignment")
143
+ include_examples 'it rewrites source-to-source', 'defined?($g ||= 1)', %q("assignment")
144
+ include_examples 'it rewrites source-to-source', 'defined?($g &&= 1)', %q("assignment")
170
145
  end
171
146
 
172
147
  context 'class variable' do
173
- include_examples 'it rewrites', 'defined?(@@a ||= 1)', %q("assignment")
174
- include_examples 'it rewrites', 'defined?(@@a &&= 1)', %q("assignment")
148
+ include_examples 'it rewrites source-to-source', 'defined?(@@a ||= 1)', %q("assignment")
149
+ include_examples 'it rewrites source-to-source', 'defined?(@@a &&= 1)', %q("assignment")
175
150
  end
176
151
 
177
152
  context 'simple method call' do
178
- include_examples 'it rewrites', 'defined?(recvr.meth ||= rhs)', %q("assignment")
179
- include_examples 'it rewrites', 'defined?(recvr.meth &&= rhs)', %q("assignment")
153
+ include_examples 'it rewrites source-to-source', 'defined?(recvr.meth ||= rhs)', %q("assignment")
154
+ include_examples 'it rewrites source-to-source', 'defined?(recvr.meth &&= rhs)', %q("assignment")
180
155
  end
181
156
 
182
157
  context '[] / []= method call' do
183
- include_examples 'it rewrites', 'defined?(recvr[idx] ||= rhs)', %q("assignment")
184
- include_examples 'it rewrites', 'defined?(recvr[idx] &&= rhs)', %q("assignment")
158
+ include_examples 'it rewrites source-to-source', 'defined?(recvr[idx] ||= rhs)', %q("assignment")
159
+ include_examples 'it rewrites source-to-source', 'defined?(recvr[idx] &&= rhs)', %q("assignment")
185
160
  end
186
161
 
187
162
  context '[] / []= method call with multiple arguments' do
188
- include_examples 'it rewrites', 'defined?(recvr[idx1, idx2] ||= rhs)', %q("assignment")
189
- include_examples 'it rewrites', 'defined?(recvr[idx1, idx2] &&= rhs)', %q("assignment")
163
+ include_examples 'it rewrites source-to-source', 'defined?(recvr[idx1, idx2] ||= rhs)', %q("assignment")
164
+ include_examples 'it rewrites source-to-source', 'defined?(recvr[idx1, idx2] &&= rhs)', %q("assignment")
190
165
  end
191
166
 
192
167
  context 'chain of method calls' do
193
- include_examples 'it rewrites', 'defined?(recvr.a.b.c ||= rhs)', %q("assignment")
194
- include_examples 'it rewrites', 'defined?(recvr.a.b.c &&= rhs)', %q("assignment")
168
+ include_examples 'it rewrites source-to-source', 'defined?(recvr.a.b.c ||= rhs)', %q("assignment")
169
+ include_examples 'it rewrites source-to-source', 'defined?(recvr.a.b.c &&= rhs)', %q("assignment")
195
170
  end
196
171
 
197
172
  context 'method call using safe nafigator' do
198
- include_examples 'it rewrites', 'defined?(recvr&.meth ||= rhs)', %q("assignment")
199
- include_examples 'it rewrites', 'defined?(recvr&.meth &&= rhs)', %q("assignment")
173
+ include_examples 'it rewrites source-to-source', 'defined?(recvr&.meth ||= rhs)', %q("assignment")
174
+ include_examples 'it rewrites source-to-source', 'defined?(recvr&.meth &&= rhs)', %q("assignment")
200
175
  end
201
176
  end
202
177
  end
@@ -4,9 +4,7 @@ require 'opal/rewriters/numblocks'
4
4
 
5
5
  RSpec.describe Opal::Rewriters::Numblocks do
6
6
  include RewritersHelper
7
- extend RewritersHelper
8
-
9
- before(:each) { Opal::Rewriters::ForRewriter.reset_tmp_counter! }
7
+ extend RewritersHelper # s() in example scope
10
8
 
11
9
  correct_names = proc do |ast|
12
10
  case ast
@@ -22,7 +20,7 @@ RSpec.describe Opal::Rewriters::Numblocks do
22
20
  end
23
21
  end
24
22
 
25
- include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
23
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(ast_of(<<~ENDDEST))
26
24
  proc do
27
25
  _1
28
26
  end
@@ -32,7 +30,7 @@ RSpec.describe Opal::Rewriters::Numblocks do
32
30
  end
33
31
  ENDDEST
34
32
 
35
- include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
33
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(ast_of(<<~ENDDEST))
36
34
  proc do
37
35
  _3
38
36
  end
@@ -1,20 +1,8 @@
1
1
  require 'lib/spec_helper'
2
+ require 'support/rewriters_helper'
2
3
 
3
4
  RSpec.describe Opal::Rewriters::OpalEngineCheck do
4
- def s(type, *children)
5
- ::Opal::AST::Node.new(type, children)
6
- end
7
-
8
- let(:rewriter) { Opal::Rewriters::OpalEngineCheck.new }
9
-
10
- def expect_rewritten(node)
11
- processed = rewriter.process(node)
12
- expect(processed)
13
- end
14
-
15
- def expect_no_rewriting_for(node)
16
- expect_rewritten(node).to eq(node)
17
- end
5
+ include RewritersHelper
18
6
 
19
7
  let(:opal_str_sexp) { s(:str, 'opal') }
20
8
  let(:true_branch) { s(:int, 1) }
@@ -21,7 +21,7 @@ RSpec.describe Opal::Rubyspec::FiltersRewriter do
21
21
  SOURCE
22
22
  end
23
23
 
24
- let(:ast) { ast_of(source) }
24
+ let(:ast) { parse(source) }
25
25
 
26
26
  context 'when spec is filtered' do
27
27
  around(:each) do |e|
@@ -44,16 +44,24 @@ RSpec.describe Opal::Rubyspec::FiltersRewriter do
44
44
  SOURCE
45
45
  end
46
46
 
47
- let(:expected_ast) { ast_of(rewritten_source) }
47
+ let(:expected_ast) { parse(rewritten_source) }
48
48
 
49
49
  it 'replaces it with nil' do
50
50
  expect_rewritten(ast).to eq(expected_ast)
51
51
  end
52
+
53
+ it 'disables cache' do
54
+ expect(rewritten(ast).meta[:dynamic_cache_result]).to be_truthy
55
+ end
52
56
  end
53
57
 
54
58
  context 'when spec is not filtered' do
55
59
  it 'does not rewrite it' do
56
60
  expect_no_rewriting_for(ast)
57
61
  end
62
+
63
+ it 'disables cache' do
64
+ expect(rewritten(ast).meta[:dynamic_cache_result]).to be_truthy
65
+ end
58
66
  end
59
67
  end
@@ -33,6 +33,10 @@ describe Opal::Compiler do
33
33
  $global["Opal"].irb_vars.bar.should == "HELLO WORLD"
34
34
  end
35
35
 
36
+ it "can reference an outer variable" do
37
+ eval_js("var a = 10;" + compile("a", :irb => true)).should == 10
38
+ end
39
+
36
40
  it "can still call top level methods" do
37
41
  eval_js(compile("to_s", :irb => true)).should == "main"
38
42
  end
@@ -1,24 +1,47 @@
1
+ describe 'super without explicit argument' do
2
+ it 'passes arguments named with js reserved word' do
3
+ parent = Class.new do
4
+ def test_args(*args) = args
5
+ def test_rest_args(*args) = args
6
+ def test_kwargs(**args) = args
7
+ def test_rest_kwargs(**args) = args
8
+ end
9
+ klass = Class.new(parent) do
10
+ def test_args(native) = super
11
+ def test_rest_args(*native) = super
12
+ def test_kwargs(native:) = super
13
+ def test_rest_kwargs(**native) = super
14
+ end
15
+
16
+ klass.new.test_args(1).should == [1]
17
+ klass.new.test_rest_args(2).should == [2]
18
+ klass.new.test_kwargs(native: 3).should == {native: 3}
19
+ klass.new.test_rest_kwargs(native: 4).should == {native: 4}
20
+ end
21
+ end
22
+
23
+ class ABlockWithSuperSpec
24
+ BLOCK = proc {
25
+ return [self, super()]
26
+ }
27
+ def foo; :foo; end
28
+ def bar; :bar; end
29
+ def foo_bar; [foo, bar]; end
30
+ end
31
+
1
32
  describe "a block with super" do
2
33
  it "can be used to define multiple methods" do
3
- block = proc {
4
- super()
5
- }
6
-
7
- c1 = Class.new {
8
- def foo; :foo; end
9
- def bar; :bar; end
10
- def foo_bar; [foo, bar]; end
11
- }
34
+ block = nil
12
35
 
13
- c2 = Class.new(c1) {
14
- define_method :foo, block
15
- define_method :bar, block
16
- define_method :foo_bar, block
36
+ c = Class.new(ABlockWithSuperSpec) {
37
+ define_method :foo, ABlockWithSuperSpec::BLOCK
38
+ define_method :bar, ABlockWithSuperSpec::BLOCK
39
+ define_method :foo_bar, ABlockWithSuperSpec::BLOCK
17
40
  }
18
41
 
19
- obj = c2.new
20
- obj.foo.should == :foo
21
- obj.bar.should == :bar
22
- obj.foo_bar.should == [:foo, :bar]
42
+ obj = c.new
43
+ obj.foo.should == [obj, :foo]
44
+ obj.bar.should == [obj, :bar]
45
+ obj.foo_bar.should == [obj, [[obj, :foo], [obj, :bar]]]
23
46
  end
24
47
  end
@@ -0,0 +1,13 @@
1
+ describe "The x-string expression" do
2
+ it "works with multiline, case and assignment" do
3
+ a = case 1
4
+ when 1
5
+ %x{
6
+ var b = 5;
7
+ return b;
8
+ }
9
+ end
10
+
11
+ a.should == 5
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ describe 'Regexp assertions' do
2
+ it 'matches the beginning of input' do
3
+ /\Atext/.should =~ 'text'
4
+ /\Atext/.should_not =~ 'the text'
5
+
6
+ regexp = Regexp.new('\Atext')
7
+ regexp.should =~ 'text'
8
+ regexp.should_not =~ 'the text'
9
+ end
10
+
11
+ it 'matches the end of input' do
12
+ /text\z/.should =~ 'the text'
13
+ /text\z/.should_not =~ 'text of'
14
+
15
+ regexp = Regexp.new('text\z')
16
+ regexp.should =~ 'the text'
17
+ regexp.should_not =~ 'text of'
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Symbol#to_proc" do
4
+ # bug #2417
5
+ it "correctly passes method name to #method_missing" do
6
+ obj = Object.new
7
+ def obj.method_missing(*args); args; end;
8
+ result = :a.to_proc.call(obj, 6, 7)
9
+ result.should == [:a, 6, 7]
10
+ end
11
+
12
+ it "correctly passes a block to #method_missing" do
13
+ obj = Object.new
14
+ block = ->{}
15
+ def obj.method_missing(*args, &block); block; end;
16
+ result = :a.to_proc.call(obj, 1, 2, 3, &block)
17
+ result.should == block
18
+ end
19
+ end
data/spec/ruby_specs CHANGED
@@ -176,6 +176,7 @@ ruby/library/base64
176
176
  ruby/library/bigdecimal
177
177
  !ruby/library/bigdecimal/util_spec
178
178
  ruby/library/date
179
+ ruby/library/datetime
179
180
  ruby/library/delegate/delegator/send_spec
180
181
  ruby/library/erb/util/h_spec
181
182
  ruby/library/erb/util/html_escape_spec
@@ -203,4 +204,7 @@ ruby/library/singleton
203
204
  ruby/library/stringio/each_line_spec
204
205
  ruby/library/stringio/each_spec
205
206
  ruby/library/stringscanner
207
+
208
+ ruby/library/time
209
+
206
210
  ruby/library/optionparser
@@ -1,13 +1,47 @@
1
1
  module RewritersHelper
2
- def s(type, *children)
3
- ::Opal::AST::Node.new(type, children)
2
+ module Common
3
+ def s(type, *children)
4
+ ::Opal::AST::Node.new(type, children)
5
+ end
6
+
7
+ def parse(source)
8
+ buffer = Opal::Parser::SourceBuffer.new('(eval)')
9
+ buffer.source = source
10
+ parser = Opal::Parser.default_parser
11
+ parser.parse(buffer)
12
+ end
13
+
14
+ # Parse, but drop the :top node
15
+ def ast_of(source)
16
+ parse(source).children.first
17
+ end
18
+ end
19
+
20
+ module DSL
21
+ def use_only_described_rewriter!
22
+ around(:each) do |e|
23
+ Opal::Rewriter.disable(except: described_class) { e.run }
24
+ end
25
+ end
26
+ end
27
+
28
+ include Common
29
+
30
+ def self.included(klass)
31
+ klass.extend(Common)
32
+ klass.extend(DSL)
33
+ end
34
+
35
+ def rewriter
36
+ described_class.new
4
37
  end
5
38
 
6
- def rewritten(ast)
7
- described_class.new.process(ast)
39
+ def rewritten(ast = input)
40
+ rewriter.process(ast)
8
41
  end
9
42
 
10
- alias :rewrite :rewritten
43
+ alias rewrite rewritten
44
+ alias processed rewritten
11
45
 
12
46
  def expect_rewritten(ast)
13
47
  expect(rewritten(ast))
@@ -17,28 +51,15 @@ module RewritersHelper
17
51
  expect_rewritten(ast).to eq(ast)
18
52
  end
19
53
 
20
- def parse(source)
21
- buffer = Opal::Parser::SourceBuffer.new('(eval)')
22
- buffer.source = source
23
- parser = Opal::Parser.default_parser
24
- parser.parse(buffer)
25
- end
26
-
27
- alias :ast_of :parse
28
-
29
54
  def parse_without_rewriting(source)
30
- buffer = Opal::Parser::SourceBuffer.new('(eval)')
31
- buffer.source = source
32
- parser = Parser::Ruby31.new
33
- parser.parse(buffer)
55
+ Opal::Rewriter.disable { parse(source) }
34
56
  end
35
57
  end
36
58
 
37
59
  RSpec.shared_examples 'it rewrites source-to-source' do |from_source, to_source|
38
60
  it "rewrites source #{from_source} to source #{to_source}" do
39
- initial = ast_of(from_source)
40
- rewritten = self.rewritten(initial)
41
- expected = ast_of(to_source)
61
+ rewritten = parse(from_source)
62
+ expected = parse(to_source)
42
63
 
43
64
  expect(rewritten).to eq(expected)
44
65
  end
@@ -46,8 +67,7 @@ end
46
67
 
47
68
  RSpec.shared_examples 'it rewrites source-to-AST' do |from_source, to_ast|
48
69
  it "rewrites source #{from_source} to AST #{to_ast}" do
49
- initial = ast_of(from_source)
50
- rewritten = self.rewritten(initial)
70
+ rewritten = parse(from_source).children.first
51
71
 
52
72
  expect(rewritten).to eq(to_ast)
53
73
  end
@@ -0,0 +1,71 @@
1
+ class DateTime < Date
2
+ class << self
3
+ def now
4
+ wrap Time.now
5
+ end
6
+
7
+ def parse(str)
8
+ wrap Time.parse(str)
9
+ end
10
+ end
11
+
12
+ def initialize(year = -4712, month = 1, day = 1, hours = 0, minutes = 0, seconds = 0, offset = 0, start = ITALY)
13
+ %x{
14
+ // Because of Gregorian reform calendar goes from 1582-10-04 to 1582-10-15.
15
+ // All days in between end up as 4 october.
16
+ if (year === 1582 && month === 10 && day > 4 && day < 15) {
17
+ day = 4;
18
+ }
19
+ }
20
+
21
+ @date = Time.new(year, month, day, hours, minutes, seconds, offset)
22
+ @start = start
23
+ end
24
+
25
+ def_delegators :@date, :min, :hour, :sec
26
+ alias minute min
27
+ alias second sec
28
+
29
+ def sec_fraction
30
+ @date.usec / 1_000_000r
31
+ end
32
+
33
+ alias second_fraction sec_fraction
34
+
35
+ def offset
36
+ @date.gmt_offset / (24 * 3600r)
37
+ end
38
+
39
+ def +(other)
40
+ ::DateTime.wrap @date + other
41
+ end
42
+
43
+ def -(other)
44
+ `if (Opal.is_a(other, #{::Date})) other = other.date`
45
+ result = @date - other
46
+ if result.is_a? ::Time
47
+ ::DateTime.wrap result
48
+ else
49
+ result
50
+ end
51
+ end
52
+
53
+ def new_offset(offset)
54
+ new_date = clone
55
+ offset = Time._parse_offset(offset)
56
+ `new_date.date.timezone = offset`
57
+ new_date
58
+ end
59
+
60
+ def to_datetime
61
+ self
62
+ end
63
+
64
+ def to_time
65
+ @date.dup
66
+ end
67
+
68
+ def to_date
69
+ Date.new(year, month, day)
70
+ end
71
+ end