opal 1.1.1 → 1.2.0.beta1

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +3 -2
  3. data/.github/ISSUE_TEMPLATE/bug-report.md +47 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/build.yml +11 -5
  6. data/.gitignore +1 -0
  7. data/.jshintrc +1 -1
  8. data/Gemfile +0 -4
  9. data/HACKING.md +1 -1
  10. data/README.md +19 -15
  11. data/UNRELEASED.md +41 -0
  12. data/benchmark-ips/bm_array_unshift.rb +7 -0
  13. data/bin/opal-mspec +2 -0
  14. data/docs/compiler.md +1 -1
  15. data/examples/rack/Gemfile +0 -1
  16. data/examples/rack/Gemfile.lock +0 -4
  17. data/lib/opal/cli.rb +1 -0
  18. data/lib/opal/cli_options.rb +4 -0
  19. data/lib/opal/cli_runners/nodejs.rb +4 -0
  20. data/lib/opal/cli_runners/source-map-support-browser.js +3 -1
  21. data/lib/opal/cli_runners/source-map-support-node.js +3 -1
  22. data/lib/opal/cli_runners/source-map-support.js +3 -1
  23. data/lib/opal/compiler.rb +2 -2
  24. data/lib/opal/nodes/args/arity_check.rb +1 -0
  25. data/lib/opal/nodes/args/parameters.rb +6 -0
  26. data/lib/opal/nodes/class.rb +1 -13
  27. data/lib/opal/nodes/literal.rb +14 -7
  28. data/lib/opal/nodes/module.rb +13 -9
  29. data/lib/opal/nodes/variables.rb +13 -4
  30. data/lib/opal/nodes/while.rb +54 -17
  31. data/lib/opal/parser.rb +1 -5
  32. data/lib/opal/parser/patch.rb +34 -0
  33. data/lib/opal/repl.rb +7 -0
  34. data/lib/opal/rewriter.rb +2 -0
  35. data/lib/opal/rewriters/arguments.rb +4 -1
  36. data/lib/opal/rewriters/forward_args.rb +54 -0
  37. data/lib/opal/rewriters/logical_operator_assignment.rb +5 -2
  38. data/lib/opal/rewriters/opal_engine_check.rb +5 -7
  39. data/lib/opal/version.rb +1 -1
  40. data/opal/corelib/array.rb +42 -20
  41. data/opal/corelib/array/pack.rb +6 -1
  42. data/opal/corelib/complex.rb +2 -0
  43. data/opal/corelib/constants.rb +3 -3
  44. data/opal/corelib/hash.rb +36 -38
  45. data/opal/corelib/module.rb +2 -7
  46. data/opal/corelib/number.rb +2 -180
  47. data/opal/corelib/numeric.rb +156 -0
  48. data/opal/corelib/object_space.rb +102 -0
  49. data/opal/corelib/random.rb +31 -66
  50. data/opal/corelib/random/formatter.rb +122 -0
  51. data/opal/corelib/range.rb +50 -19
  52. data/opal/corelib/runtime.js +82 -21
  53. data/opal/corelib/string.rb +86 -52
  54. data/opal/corelib/string/encoding.rb +140 -25
  55. data/opal/corelib/string/unpack.rb +26 -40
  56. data/opal/opal.rb +1 -0
  57. data/opal/opal/full.rb +1 -0
  58. data/spec/filters/bugs/array.rb +0 -22
  59. data/spec/filters/bugs/basicobject.rb +3 -0
  60. data/spec/filters/bugs/encoding.rb +0 -2
  61. data/spec/filters/bugs/exception.rb +1 -0
  62. data/spec/filters/bugs/float.rb +0 -2
  63. data/spec/filters/bugs/hash.rb +2 -7
  64. data/spec/filters/bugs/integer.rb +0 -2
  65. data/spec/filters/bugs/kernel.rb +16 -3
  66. data/spec/filters/bugs/language.rb +6 -14
  67. data/spec/filters/bugs/marshal.rb +1 -3
  68. data/spec/filters/bugs/module.rb +16 -1
  69. data/spec/filters/bugs/numeric.rb +4 -12
  70. data/spec/filters/bugs/objectspace.rb +67 -0
  71. data/spec/filters/bugs/pack_unpack.rb +0 -9
  72. data/spec/filters/bugs/pathname.rb +1 -0
  73. data/spec/filters/bugs/proc.rb +8 -0
  74. data/spec/filters/bugs/random.rb +3 -6
  75. data/spec/filters/bugs/range.rb +83 -113
  76. data/spec/filters/bugs/set.rb +2 -0
  77. data/spec/filters/bugs/string.rb +31 -70
  78. data/spec/filters/bugs/struct.rb +2 -0
  79. data/spec/filters/bugs/time.rb +8 -2
  80. data/spec/filters/unsupported/float.rb +3 -0
  81. data/spec/filters/unsupported/freeze.rb +1 -0
  82. data/spec/filters/unsupported/integer.rb +3 -0
  83. data/spec/filters/unsupported/refinements.rb +5 -0
  84. data/spec/filters/unsupported/string.rb +100 -95
  85. data/spec/filters/unsupported/time.rb +4 -0
  86. data/spec/lib/compiler_spec.rb +16 -0
  87. data/spec/lib/rewriters/forward_args_spec.rb +61 -0
  88. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +1 -1
  89. data/spec/lib/rewriters/numblocks_spec.rb +44 -0
  90. data/spec/lib/rewriters/opal_engine_check_spec.rb +49 -4
  91. data/spec/opal/core/language/forward_args_spec.rb +53 -0
  92. data/spec/opal/core/language/infinite_range_spec.rb +13 -0
  93. data/spec/opal/core/language/memoization_spec.rb +16 -0
  94. data/spec/opal/core/module_spec.rb +38 -2
  95. data/spec/opal/core/number/to_i_spec.rb +28 -0
  96. data/spec/opal/core/runtime/bridged_classes_spec.rb +16 -0
  97. data/spec/opal/core/runtime/constants_spec.rb +20 -1
  98. data/spec/opal/core/string/subclassing_spec.rb +16 -0
  99. data/spec/opal/core/string/unpack_spec.rb +22 -0
  100. data/spec/opal/core/string_spec.rb +4 -4
  101. data/spec/ruby_specs +4 -1
  102. data/stdlib/json.rb +3 -1
  103. data/stdlib/securerandom.rb +55 -35
  104. data/tasks/testing.rake +6 -3
  105. data/test/nodejs/test_string.rb +25 -0
  106. data/vendored-minitest/minitest/assertions.rb +2 -0
  107. metadata +31 -10
  108. data/lib/opal/parser/with_c_lexer.rb +0 -15
@@ -123,6 +123,7 @@ opal_unsupported_filter "Time" do
123
123
  fails "Time#utc_offset returns the correct offset for US Eastern time zone around daylight savings time change"
124
124
  fails "Time#utc_offset returns the offset in seconds between the timezone of time and UTC"
125
125
  fails "Time#wday returns an integer representing the day of the week, 0..6, with Sunday being 0"
126
+ fails "Time#yday returns an integer representing the day of the year, 1..366" # Expected 117 == 116
126
127
  fails "Time#year returns the four digit year for a Time with a fixed offset"
127
128
  fails "Time#year returns the four digit year for a local Time as an Integer"
128
129
  fails "Time#zone Encoding.default_internal is set doesn't raise errors for a Time with a fixed offset"
@@ -201,4 +202,7 @@ opal_unsupported_filter "Time" do
201
202
  fails "Time.utc ignores fractional seconds if a passed fractional number of microseconds"
202
203
  fails "Time.utc ignores fractional seconds if a passed whole number of microseconds"
203
204
  fails "Time.utc returns subclass instances"
205
+ fails_badly "Marshal.load for a Time loads the zone" # Seasonal failure
206
+ fails_badly "Time#inspect formats the local time following the pattern 'yyyy-MM-dd HH:mm:ss Z'" # Seasonal failure
207
+ fails_badly "Time#to_s formats the local time following the pattern 'yyyy-MM-dd HH:mm:ss Z'" # Seasonal failure
204
208
  end
@@ -42,6 +42,22 @@ RSpec.describe Opal::Compiler do
42
42
  expect_compiled('"hello #{100}"').to include('"hello "', '100')
43
43
  end
44
44
 
45
+ it "should compile ruby ranges" do
46
+ expect_compiled('1..1').to include('$range(1, 1, false)')
47
+ expect_compiled('1...1').to include('$range(1, 1, true)')
48
+ expect_compiled('..1').to include('$range(nil, 1, false)')
49
+ expect_compiled('...1').to include('$range(nil, 1, true)')
50
+ expect_compiled('1..').to include('$range(1, nil, false)')
51
+ expect_compiled('1...').to include('$range(1, nil, true)')
52
+ # Following return Opal.range.$new instead of $range. Some also miss a space.
53
+ expect_compiled('nil..1').to include('(nil, 1, false)')
54
+ expect_compiled('nil...1').to include('(nil,1, true)')
55
+ expect_compiled('"a"..nil').to include('("a", nil, false)')
56
+ expect_compiled('"a"...nil').to include('("a",nil, true)')
57
+ expect_compiled('..nil').to include('(nil, nil, false)')
58
+ expect_compiled('...nil').to include('(nil,nil, true)')
59
+ end
60
+
45
61
  it "should compile method calls" do
46
62
  expect_compiled("self.inspect").to include("$inspect()")
47
63
  expect_compiled("self.map { |a| a + 10 }").to include("$map")
@@ -0,0 +1,61 @@
1
+ require 'lib/spec_helper'
2
+ require 'support/rewriters_helper'
3
+ require 'opal/rewriters/forward_args'
4
+
5
+ RSpec.describe Opal::Rewriters::ForwardArgs do
6
+ include RewritersHelper
7
+ extend RewritersHelper
8
+
9
+ before(:each) { Opal::Rewriters::ForRewriter.reset_tmp_counter! }
10
+
11
+ correct_names = proc do |ast|
12
+ case ast
13
+ when Opal::AST::Node
14
+ ast.children.map do |i|
15
+ correct_names.(i)
16
+ end.yield_self { |children| s(ast.type, *children) }
17
+ when :fwd_rest
18
+ "$fwd_rest"
19
+ when :fwd_block
20
+ "$fwd_block"
21
+ else
22
+ ast
23
+ end
24
+ end
25
+
26
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
27
+ def forward(...)
28
+ other(...)
29
+ end
30
+ ENDSOURCE
31
+ def forward(*fwd_rest, &fwd_block)
32
+ other(*fwd_rest, &fwd_block)
33
+ end
34
+ ENDDEST
35
+
36
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
37
+ def forward(first_arg, ...)
38
+ other(first_arg, second_arg, ...)
39
+ other(other_arg, ...)
40
+ other(...)
41
+ end
42
+ ENDSOURCE
43
+ def forward(first_arg, *fwd_rest, &fwd_block)
44
+ other(first_arg, second_arg, *fwd_rest, &fwd_block)
45
+ other(other_arg, *fwd_rest, &fwd_block)
46
+ other(*fwd_rest, &fwd_block)
47
+ end
48
+ ENDDEST
49
+
50
+ # Not supported by the parser (nor by the rewriter which would have to rearrange the arguments)
51
+
52
+ # include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
53
+ # def forward(a:, ...)
54
+ # other(...)
55
+ # end
56
+ # ENDSOURCE
57
+ # def forward(*fwd_rest, a:, &fwd_block)
58
+ # other(*fwd_rest, &fwd_block)
59
+ # end
60
+ # ENDDEST
61
+ end
@@ -57,7 +57,7 @@ RSpec.describe Opal::Rewriters::LogicalOperatorAssignment do
57
57
  end
58
58
 
59
59
  context 'class variable' do
60
- include_examples 'it rewrites', '@@a ||= 1', '@@a = @@a || 1'
60
+ include_examples 'it rewrites', '@@a ||= 1', '@@a = defined?(@@a) ? (@@a || 1) : 1'
61
61
  include_examples 'it rewrites', '@@a &&= 1', '@@a = @@a && 1'
62
62
  end
63
63
 
@@ -0,0 +1,44 @@
1
+ require 'lib/spec_helper'
2
+ require 'support/rewriters_helper'
3
+ require 'opal/rewriters/numblocks'
4
+
5
+ RSpec.describe Opal::Rewriters::Numblocks do
6
+ include RewritersHelper
7
+ extend RewritersHelper
8
+
9
+ before(:each) { Opal::Rewriters::ForRewriter.reset_tmp_counter! }
10
+
11
+ correct_names = proc do |ast|
12
+ case ast
13
+ when Opal::AST::Node
14
+ ast.children.map do |i|
15
+ correct_names.(i)
16
+ end.yield_self { |children| s(ast.type, *children) }
17
+ when :arg1 then :_1
18
+ when :arg2 then :_2
19
+ when :arg3 then :_3
20
+ else
21
+ ast
22
+ end
23
+ end
24
+
25
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
26
+ proc do
27
+ _1
28
+ end
29
+ ENDSOURCE
30
+ proc do |arg1|
31
+ arg1
32
+ end
33
+ ENDDEST
34
+
35
+ include_examples 'it rewrites source-to-AST', <<~ENDSOURCE, correct_names.(parse(<<~ENDDEST))
36
+ proc do
37
+ _3
38
+ end
39
+ ENDSOURCE
40
+ proc do |arg1, arg2, arg3|
41
+ arg3
42
+ end
43
+ ENDDEST
44
+ end
@@ -30,11 +30,11 @@ RSpec.describe Opal::Rewriters::OpalEngineCheck do
30
30
  s(:send, ruby_const_sexp, :==, opal_str_sexp)
31
31
  end
32
32
 
33
- it 'replaces true branch with s(:nil)' do
33
+ it 'replaces the expression with the true branch' do
34
34
  expect_rewritten(
35
35
  s(:if, check, true_branch, false_branch)
36
36
  ).to eq(
37
- s(:if, check, true_branch, s(:nil))
37
+ true_branch
38
38
  )
39
39
  end
40
40
  end
@@ -58,11 +58,11 @@ RSpec.describe Opal::Rewriters::OpalEngineCheck do
58
58
  s(:send, ruby_const_sexp, :!=, opal_str_sexp)
59
59
  end
60
60
 
61
- it 'replaces true branch with s(:nil)' do
61
+ it 'replaces the expression with the false branch' do
62
62
  expect_rewritten(
63
63
  s(:if, check, true_branch, false_branch)
64
64
  ).to eq(
65
- s(:if, check, s(:nil), false_branch)
65
+ false_branch
66
66
  )
67
67
  end
68
68
  end
@@ -79,6 +79,51 @@ RSpec.describe Opal::Rewriters::OpalEngineCheck do
79
79
  end
80
80
  end
81
81
  end
82
+
83
+ it 'supports nested blocks' do
84
+ expect_rewritten(
85
+ # if true
86
+ # if RUBY_ENGINE == 'opal'
87
+ # if RUBY_ENGINE == 'opal'
88
+ # :a
89
+ # end
90
+ # if RUBY_ENGINE != 'opal'
91
+ # :b
92
+ # end
93
+ # end
94
+ # end
95
+
96
+ s(:if,
97
+ s(:true),
98
+ s(:if,
99
+ s(:send, ruby_const_sexp, :==, opal_str_sexp),
100
+ s(:begin,
101
+ s(:if,
102
+ s(:send, ruby_const_sexp, :==, opal_str_sexp),
103
+ s(:sym, :a)
104
+ ),
105
+ s(:if,
106
+ s(:send, ruby_const_sexp, :!=, opal_str_sexp),
107
+ s(:sym, :b)
108
+ )
109
+ )
110
+ )
111
+ )
112
+ ).to eq(
113
+ # if true
114
+ # :a
115
+ # nil
116
+ # end
117
+
118
+ s(:if,
119
+ s(:true),
120
+ s(:begin,
121
+ s(:sym, :a),
122
+ s(:nil)
123
+ )
124
+ )
125
+ )
126
+ end
82
127
  end
83
128
  end
84
129
  end
@@ -0,0 +1,53 @@
1
+ describe "Forward arguments" do
2
+ it "forwards args, kwargs and blocks" do
3
+ def fwd_t1_pass1(...)
4
+ fwd_t1_pass2(...)
5
+ end
6
+
7
+ def fwd_t1_pass2(*args, **kwargs, &block)
8
+ [args.count, kwargs.count, block_given?]
9
+ end
10
+
11
+ fwd_t1_pass1(1, 2, 3, a: 1, b: 2).should == [3, 2, false]
12
+ fwd_t1_pass1(1, 2, &:itself).should == [2, 0, true]
13
+ fwd_t1_pass1(a: 1, b: 2).should == [0, 2, false]
14
+ end
15
+
16
+ it "supports forwarding with initial arguments (3.0 behavior)" do
17
+ def fwd_t2_pass1(initial, ...)
18
+ fwd_t2_pass2(0, initial + 1, ...)
19
+ end
20
+
21
+ def fwd_t2_pass2(a, b, c)
22
+ a + b + c
23
+ end
24
+
25
+ fwd_t2_pass1(2, 3).should == 6
26
+ error = nil
27
+ begin
28
+ fwd_t2_pass1(2, 3, 4) # Too many arguments passwd to fwd_t2_pass2
29
+ rescue ArgumentError
30
+ error = :ArgumentError
31
+ end
32
+ error.should == :ArgumentError
33
+ end
34
+
35
+ it "supports forwarding to multiple methods at once" do
36
+ def fwd_t3_pass1(...)
37
+ fwd_t3_pass2a(...) + fwd_t3_pass2b(...) + fwd_t3_pass2c(...)
38
+ end
39
+
40
+ def fwd_t3_pass2a(*args)
41
+ -2 * args.count
42
+ end
43
+ def fwd_t3_pass2b(*args)
44
+ 1 * args.count
45
+ end
46
+ def fwd_t3_pass2c(*args)
47
+ 0 * args.count
48
+ end
49
+
50
+ fwd_t3_pass1(0, 0, 0).should == -3
51
+ fwd_t3_pass1(0, 0).should == -2
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ describe "Infinite ranges" do
2
+ it "supports endless ranges" do
3
+ range = (10..)
4
+ range.begin.should == 10
5
+ range.end.should == nil
6
+ end
7
+
8
+ it "supports beginless ranges" do
9
+ range = (..10)
10
+ range.begin.should == nil
11
+ range.end.should == 10
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ describe "memoization" do
2
+ it "memoizes a value with complex internal logic" do
3
+ klass = Class.new do
4
+ def memoized_value(dependency: nil)
5
+ @memoized_value ||= begin
6
+ return nil if dependency.nil?
7
+
8
+ dependency.call
9
+ end
10
+ end
11
+ end
12
+
13
+ expect(klass.new.memoized_value(dependency: proc { :value })).to eq :value
14
+ expect(klass.new.memoized_value).to eq nil
15
+ end
16
+ end
@@ -15,8 +15,30 @@ module ModuleSubclassIncludedSpec
15
15
  M2 = Module2.new
16
16
  end
17
17
 
18
- describe 'Module#included' do
19
- it 'gets called in subclasses (regression for https://github.com/opal/opal/issues/1900)' do
18
+ module ModuleCVarSpec
19
+ module Mod0
20
+ def cvar0; @@cvar; end
21
+ def cvarx0; @@cvarx ||= 5; end
22
+ def cvary0; @@cvary; 0; end
23
+ def cvarz0; @@cvarz = @@cvarz || 5; end
24
+ end
25
+
26
+ module Mod1
27
+ include Mod0
28
+ @@cvar = 10
29
+ def cvar1; @@cvar; end
30
+ def cvar1=(new); @@cvar=new; end
31
+ end
32
+
33
+ module Mod2
34
+ include Mod1
35
+ def cvar2; @@cvar; end
36
+ def cvar2=(new); @@cvar=new; end
37
+ end
38
+ end
39
+
40
+ describe 'Module' do
41
+ it '#included gets called in subclasses (regression for https://github.com/opal/opal/issues/1900)' do
20
42
  $ScratchPad = []
21
43
  klass = Class.new
22
44
  klass.include ::ModuleSubclassIncludedSpec::M0
@@ -24,4 +46,18 @@ describe 'Module#included' do
24
46
  klass.include ::ModuleSubclassIncludedSpec::M2
25
47
  $ScratchPad.should == ['A included', 'B included']
26
48
  end
49
+
50
+ it "can access ancestor's @@cvar" do
51
+ klass = Class.new
52
+ klass.include ::ModuleCVarSpec::Mod2
53
+ klass.new.cvar1.should == 10
54
+ klass.new.cvar2.should == 10
55
+ klass.new.cvar2 = 50
56
+ klass.new.cvar1.should == 50
57
+ klass.new.cvar2.should == 50
58
+ klass.new.cvarx0.should == 5
59
+ klass.new.cvary0.should == 0
60
+ ->{ klass.new.cvarz0 }.should raise_error NameError
61
+ ->{ klass.new.cvar0 }.should raise_error NameError
62
+ end
27
63
  end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Number#to_i' do
4
+ it "should not change huge number" do
5
+ 1504642339053716000000.to_i.should == 1504642339053716000000
6
+ end
7
+
8
+ it "should not change negative huge number" do
9
+ -1504642339053716000000.to_i.should == -1504642339053716000000
10
+ end
11
+
12
+ it "equals Number#truncate(0) with huge number" do
13
+ 1504642339053716000000.to_i.should == 1504642339053716000000.truncate(0)
14
+ end
15
+
16
+ it "should not change Infinity" do
17
+ `Infinity`.to_i.should == `Infinity`
18
+ end
19
+
20
+ it "should not change -Infinity" do
21
+ `-Infinity`.to_i.should == `-Infinity`
22
+ end
23
+
24
+ it "should not change NaN" do
25
+ x = `NaN`.to_i
26
+ `Number.isNaN(x)`.should be_true
27
+ end
28
+ end
@@ -121,3 +121,19 @@ describe 'Bridged classes in different modules' do
121
121
  @bridged.new.some_bridged_method.should == [4, 5, 6]
122
122
  end
123
123
  end
124
+
125
+
126
+ describe "Invalid bridged classes" do
127
+ it "raises a TypeError when trying to extend with non-Class" do
128
+ error_msg = /superclass must be a Class/
129
+ -> { class TestClass < `""`; end }.should raise_error(TypeError, error_msg)
130
+ -> { class TestClass < `3`; end }.should raise_error(TypeError, error_msg)
131
+ -> { class TestClass < `true`; end }.should raise_error(TypeError, error_msg)
132
+ -> { class TestClass < `Math`; end }.should raise_error(TypeError, error_msg)
133
+ -> { class TestClass < `Object.create({})`; end }.should raise_error(TypeError, error_msg)
134
+ -> { class TestClass < `Object.create(null)`; end }.should raise_error(TypeError, error_msg)
135
+ -> { class TestClass < Module.new; end }.should raise_error(TypeError, error_msg)
136
+ -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
137
+ end
138
+ end
139
+
@@ -4,9 +4,15 @@ module RuntimeFixtures
4
4
 
5
5
  class A::B
6
6
  module C
7
-
8
7
  end
9
8
  end
9
+
10
+ module ModuleB
11
+ end
12
+
13
+ module ModuleA
14
+ include ModuleB
15
+ end
10
16
  end
11
17
 
12
18
  describe "Constants access via .$$ with dots (regression for #1418)" do
@@ -14,3 +20,16 @@ describe "Constants access via .$$ with dots (regression for #1418)" do
14
20
  `Opal.Object.$$.RuntimeFixtures.$$.A.$$.B.$$.C`.should == RuntimeFixtures::A::B::C
15
21
  end
16
22
  end
23
+
24
+ describe "Inclusion of modules" do
25
+ it "that have been included by other modules works" do
26
+ # here ClassC would have failed to be created due to a bug in Opal.append_features
27
+ module RuntimeFixtures
28
+ class ClassC
29
+ include ModuleA
30
+ include ModuleB
31
+ end
32
+ end
33
+ RuntimeFixtures::ClassC.new.class.should == RuntimeFixtures::ClassC
34
+ end
35
+ end