opal 0.9.0.beta1 → 0.9.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -20
  3. data/CONTRIBUTING.md +8 -16
  4. data/lib/opal/compiler.rb +5 -0
  5. data/lib/opal/nodes/def.rb +10 -3
  6. data/lib/opal/nodes/definitions.rb +14 -3
  7. data/lib/opal/paths.rb +21 -4
  8. data/lib/opal/version.rb +1 -1
  9. data/opal/corelib/array.rb +1 -1
  10. data/opal/corelib/basic_object.rb +9 -9
  11. data/opal/corelib/constants.rb +2 -2
  12. data/opal/corelib/enumerable.rb +79 -2
  13. data/opal/corelib/error.rb +18 -0
  14. data/opal/corelib/helpers.rb +2 -8
  15. data/opal/corelib/kernel.rb +7 -7
  16. data/opal/corelib/module.rb +10 -10
  17. data/opal/corelib/number.rb +1 -1
  18. data/opal/corelib/regexp.rb +31 -30
  19. data/opal/corelib/string.rb +1 -1
  20. data/opal/corelib/struct.rb +8 -10
  21. data/opal/corelib/time.rb +4 -2
  22. data/opal/corelib/unsupported.rb +2 -2
  23. data/spec/filters/bugs/enumerable.rb +0 -19
  24. data/spec/filters/bugs/exception.rb +0 -4
  25. data/spec/filters/bugs/language.rb +7 -5
  26. data/spec/filters/bugs/module.rb +18 -19
  27. data/spec/filters/bugs/regexp.rb +0 -3
  28. data/spec/filters/bugs/set.rb +0 -8
  29. data/spec/filters/bugs/struct.rb +2 -2
  30. data/spec/filters/unsupported/bignum.rb +1 -0
  31. data/spec/filters/unsupported/language.rb +7 -0
  32. data/spec/lib/compiler_spec.rb +5 -0
  33. data/spec/lib/parser/undef_spec.rb +4 -0
  34. data/spec/lib/paths_spec.rb +11 -0
  35. data/spec/lib/spec_helper.rb +1 -1
  36. data/spec/opal/core/arity_spec.rb +142 -0
  37. data/spec/rubyspecs +1 -0
  38. data/stdlib/json.rb +13 -8
  39. data/stdlib/native.rb +1 -1
  40. data/stdlib/observer.rb +1 -1
  41. data/stdlib/ostruct.rb +1 -1
  42. data/stdlib/set.rb +33 -0
  43. data/tasks/testing.rake +8 -7
  44. metadata +7 -3
@@ -112,3 +112,21 @@ class UncaughtThrowError < ArgumentError
112
112
  super("uncaught throw #{@sym.inspect}")
113
113
  end
114
114
  end
115
+
116
+ class NameError
117
+ attr_reader :name
118
+
119
+ def initialize(message, name=nil)
120
+ super message
121
+ @name = name
122
+ end
123
+ end
124
+
125
+ class NoMethodError
126
+ attr_reader :args
127
+
128
+ def initialize(message, name, args=[])
129
+ super message, name
130
+ @args = args
131
+ end
132
+ end
@@ -108,15 +108,9 @@ module Opal
108
108
  name = Opal.coerce_to!(name, String, :to_str)
109
109
 
110
110
  unless `/^@[a-zA-Z_][a-zA-Z0-9_]*?$/.test(name)`
111
- raise NameError, "'#{name}' is not allowed as an instance variable name"
111
+ raise NameError.new("'#{name}' is not allowed as an instance variable name", name)
112
112
  end
113
113
 
114
114
  name
115
- end
116
-
117
- def self.valid_method_name?(method_name)
118
- method_name = Opal.coerce_to!(method_name, String, :to_str)
119
-
120
- `/^[a-zA-Z_][a-zA-Z0-9_]*?$/.test(method_name)`
121
- end
115
+ end
122
116
  end
@@ -1,6 +1,6 @@
1
1
  module Kernel
2
2
  def method_missing(symbol, *args, &block)
3
- raise NoMethodError, "undefined method `#{symbol}' for #{inspect}"
3
+ raise NoMethodError.new("undefined method `#{symbol}' for #{inspect}", symbol, args)
4
4
  end
5
5
 
6
6
  def =~(obj)
@@ -35,7 +35,7 @@ module Kernel
35
35
  var meth = self['$' + name];
36
36
 
37
37
  if (!meth || meth.$$stub) {
38
- #{raise NameError, "undefined method `#{name}' for class `#{self.class}'"};
38
+ #{raise NameError.new("undefined method `#{name}' for class `#{self.class}'", name)};
39
39
  }
40
40
 
41
41
  return #{Method.new(self, `meth`, name)};
@@ -993,7 +993,7 @@ module Kernel
993
993
  $stderr.puts(*strs) unless $VERBOSE.nil? || strs.empty?
994
994
  end
995
995
 
996
- def raise(exception = undefined, string = nil)
996
+ def raise(exception = undefined, string = nil, _backtrace = nil)
997
997
  %x{
998
998
  if (exception == null && #$! !== nil) {
999
999
  throw #$!;
@@ -1010,16 +1010,16 @@ module Kernel
1010
1010
  }
1011
1011
  else if (#{exception.kind_of?(Exception)}) {
1012
1012
  // exception is fine
1013
- }
1013
+ }
1014
1014
  else {
1015
1015
  exception = #{TypeError.new 'exception class/object expected'};
1016
1016
  }
1017
-
1017
+
1018
1018
  if (#$! !== nil) {
1019
1019
  Opal.exceptions.push(#$!);
1020
1020
  }
1021
-
1022
- #$! = exception;
1021
+
1022
+ #$! = exception;
1023
1023
 
1024
1024
  throw exception;
1025
1025
  }
@@ -180,10 +180,10 @@ class Module
180
180
 
181
181
  def class_variable_get(name)
182
182
  name = Opal.coerce_to!(name, String, :to_str)
183
- raise NameError, 'class vars should start with @@' if `name.length < 3 || name.slice(0,2) !== '@@'`
183
+ raise NameError.new('class vars should start with @@', name) if `name.length < 3 || name.slice(0,2) !== '@@'`
184
184
  %x{
185
185
  var value = Opal.cvars[name.slice(2)];
186
- #{raise NameError, 'uninitialized class variable @@a in' if `value == null`}
186
+ #{raise NameError.new('uninitialized class variable @@a in', name) if `value == null`}
187
187
  return value;
188
188
  }
189
189
  end
@@ -204,7 +204,7 @@ class Module
204
204
  # check for constant within current scope
205
205
  # if inherit is true or self is Object, will also check ancestors
206
206
  def const_defined?(name, inherit = true)
207
- raise NameError, "wrong constant name #{name}" unless name =~ /^[A-Z]\w*$/
207
+ raise NameError.new("wrong constant name #{name}", name) unless name =~ /^[A-Z]\w*$/
208
208
 
209
209
  %x{
210
210
  var scopes = [self.$$scope];
@@ -234,7 +234,7 @@ class Module
234
234
  return name.split('::').inject(self) { |o, c| o.const_get(c) }
235
235
  end
236
236
 
237
- raise NameError, "wrong constant name #{name}" unless `/^[A-Z]\w*$/.test(name)`
237
+ raise NameError.new("wrong constant name #{name}", name) unless `/^[A-Z]\w*$/.test(name)`
238
238
 
239
239
  %x{
240
240
  var scopes = [self.$$scope];
@@ -272,11 +272,11 @@ class Module
272
272
  }
273
273
  }
274
274
 
275
- raise NameError, "uninitialized constant #{self}::#{name}"
275
+ raise NameError.new("uninitialized constant #{self}::#{name}", name)
276
276
  end
277
277
 
278
278
  def const_set(name, value)
279
- raise NameError, "wrong constant name #{name}" unless name =~ /^[A-Z]\w*$/
279
+ raise NameError.new("wrong constant name #{name}", name) unless name =~ /^[A-Z]\w*$/
280
280
 
281
281
  begin
282
282
  name = name.to_str
@@ -374,7 +374,7 @@ class Module
374
374
  var meth = self.$$proto['$' + name];
375
375
 
376
376
  if (!meth || meth.$$stub) {
377
- #{raise NameError, "undefined method `#{name}' for class `#{self.name}'"};
377
+ #{raise NameError.new("undefined method `#{name}' for class `#{self.name}'", name)};
378
378
  }
379
379
 
380
380
  return #{UnboundMethod.new(self, `meth`, name)};
@@ -452,16 +452,16 @@ class Module
452
452
 
453
453
  alias class_eval module_eval
454
454
 
455
- def module_exec(&block)
455
+ def module_exec(*args, &block)
456
456
  %x{
457
457
  if (block === nil) {
458
- throw new Error("no block given");
458
+ #{raise LocalJumpError, 'no block given'}
459
459
  }
460
460
 
461
461
  var block_self = block.$$s, result;
462
462
 
463
463
  block.$$s = null;
464
- result = block.apply(self, $slice.call(arguments));
464
+ result = block.apply(self, args);
465
465
  block.$$s = block_self;
466
466
 
467
467
  return result;
@@ -298,7 +298,7 @@ class Number < Numeric
298
298
 
299
299
  def bit_length
300
300
  unless Integer === self
301
- raise NoMethodError, "undefined method `bit_length` for #{self}:Float"
301
+ raise NoMethodError.new("undefined method `bit_length` for #{self}:Float", 'bit_length')
302
302
  end
303
303
 
304
304
  %x{
@@ -7,6 +7,12 @@ class Regexp < `RegExp`
7
7
  `def.$$is_regexp = true`
8
8
 
9
9
  class << self
10
+ def allocate
11
+ allocated = super
12
+ `#{allocated}.uninitialized = true`
13
+ allocated
14
+ end
15
+
10
16
  def escape(string)
11
17
  %x{
12
18
  return string.replace(/([-[\]\/{}()*+?.^$\\| ])/g, '\\$1')
@@ -102,7 +108,7 @@ class Regexp < `RegExp`
102
108
  end
103
109
 
104
110
  def ===(string)
105
- `#{match(string)} !== nil`
111
+ `#{match(Opal.coerce_to?(string, String, :to_str))} !== nil`
106
112
  end
107
113
 
108
114
  def =~(string)
@@ -117,6 +123,10 @@ class Regexp < `RegExp`
117
123
 
118
124
  def match(string, pos = undefined, &block)
119
125
  %x{
126
+ if (self.uninitialized) {
127
+ #{raise TypeError, 'uninitialized Regexp'}
128
+ }
129
+
120
130
  if (pos === undefined) {
121
131
  pos = 0;
122
132
  } else {
@@ -136,8 +146,16 @@ class Regexp < `RegExp`
136
146
  }
137
147
  }
138
148
 
139
- // global RegExp maintains state, so not using self/this
140
- var md, re = new RegExp(self.source, 'gm' + (self.ignoreCase ? 'i' : ''));
149
+ var source = self.source;
150
+ var flags = 'g';
151
+ // m flag + a . in Ruby will match white space, but in JS, it only matches beginning/ending of lines, so we get the equivalent here
152
+ if (self.multiline) {
153
+ source = source.replace('.', "[\\s\\S]");
154
+ flags += 'm';
155
+ }
156
+
157
+ // global RegExp maintains state, so not using self/this
158
+ var md, re = new RegExp(source, flags + (self.ignoreCase ? 'i' : ''));
141
159
 
142
160
  while (true) {
143
161
  md = re.exec(string);
@@ -162,36 +180,19 @@ class Regexp < `RegExp`
162
180
  end
163
181
 
164
182
  def options
165
- # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags is still experimental
166
- # we need the flags and source does not give us that
183
+ # Flags would be nice to use with this, but still experimental - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags
167
184
  %x{
168
- var as_string, text_flags, result, text_flag;
169
- as_string = self.toString();
170
- if (as_string == "/(?:)/") {
185
+ if (self.uninitialized) {
171
186
  #{raise TypeError, 'uninitialized Regexp'}
187
+ }
188
+ var result = 0;
189
+ // should be supported in IE6 according to https://msdn.microsoft.com/en-us/library/7f5z26w4(v=vs.94).aspx
190
+ if (self.multiline) {
191
+ result |= #{MULTILINE};
172
192
  }
173
- text_flags = as_string.replace(self.source, '').match(/\w+/);
174
- result = 0;
175
- // may have no flags
176
- if (text_flags == null) {
177
- return result;
178
- }
179
- // first match contains all of our flags
180
- text_flags = text_flags[0];
181
- for (var i=0; i < text_flags.length; i++) {
182
- text_flag = text_flags[i];
183
- switch(text_flag) {
184
- case 'i':
185
- result |= #{IGNORECASE};
186
- break;
187
- case 'm':
188
- result |= #{MULTILINE};
189
- break;
190
- default:
191
- #{raise "RegExp flag #{`text_flag`} does not have a match in Ruby"}
192
- }
193
- }
194
-
193
+ if (self.ignoreCase) {
194
+ result |= #{IGNORECASE};
195
+ }
195
196
  return result;
196
197
  }
197
198
  end
@@ -455,7 +455,7 @@ class String < `String`
455
455
  def gsub(pattern, replacement = undefined, &block)
456
456
  %x{
457
457
  if (replacement === undefined && block === nil) {
458
- #{return enum_for :gsub, pattern}
458
+ return #{enum_for :gsub, pattern};
459
459
  }
460
460
 
461
461
  var result = '', match_data = nil, index = 0, match, _replacement;
@@ -37,15 +37,13 @@ class Struct
37
37
 
38
38
  members << name
39
39
 
40
- if Opal.valid_method_name?(name)
41
- define_method name do
42
- self[name]
43
- end
44
-
45
- define_method "#{name}=" do |value|
46
- self[name] = value
47
- end
40
+ define_method name do
41
+ self[name]
48
42
  end
43
+
44
+ define_method "#{name}=" do |value|
45
+ self[name] = value
46
+ end
49
47
  end
50
48
 
51
49
  def self.members
@@ -85,7 +83,7 @@ class Struct
85
83
 
86
84
  name = members[name]
87
85
  elsif String === name
88
- raise NameError, "no member '#{name}' in struct" unless members.include?(name.to_sym)
86
+ raise NameError.new("no member '#{name}' in struct", name) unless members.include?(name.to_sym)
89
87
  else
90
88
  raise TypeError, "no implicit conversion of #{name.class} into Integer"
91
89
  end
@@ -101,7 +99,7 @@ class Struct
101
99
 
102
100
  name = members[name]
103
101
  elsif String === name
104
- raise NameError, "no member '#{name}' in struct" unless members.include?(name.to_sym)
102
+ raise NameError.new("no member '#{name}' in struct", name) unless members.include?(name.to_sym)
105
103
  else
106
104
  raise TypeError, "no implicit conversion of #{name.class} into Integer"
107
105
  end
data/opal/corelib/time.rb CHANGED
@@ -159,7 +159,8 @@ class Time < `Date`
159
159
  }
160
160
  end
161
161
 
162
- def self.local(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil)
162
+ def self.local(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil, _dummy1 = nil, _dummy2 = nil, _dummy3 = nil)
163
+ # The _dummy args are there only because the MRI version accepts up to 10 arguments
163
164
  %x{
164
165
  var args, result;
165
166
 
@@ -189,7 +190,8 @@ class Time < `Date`
189
190
  }
190
191
  end
191
192
 
192
- def self.gm(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil)
193
+ def self.gm(year, month = nil, day = nil, hour = nil, min = nil, sec = nil, millisecond = nil, _dummy1 = nil, _dummy2 = nil, _dummy3 = nil)
194
+ # The _dummy args are there only because the MRI version accepts up to 10 arguments
193
195
  %x{
194
196
  var args, result;
195
197
 
@@ -180,8 +180,8 @@ class Module
180
180
 
181
181
  alias nesting public
182
182
 
183
- def private_class_method(name)
184
- `self['$' + name] || nil`
183
+ def private_class_method(*)
184
+ self
185
185
  end
186
186
 
187
187
  alias public_class_method private_class_method
@@ -1,29 +1,10 @@
1
1
  opal_filter "Enumerable" do
2
- fails "Enumerable#cycle passed a number n as an argument raises an ArgumentError if more arguments are passed"
3
- fails "Enumerable#each_cons gathers whole arrays as elements when each yields multiple"
4
- fails "Enumerable#each_cons passes element groups to the block"
5
- fails "Enumerable#each_cons raises an ArgumentError if there is not a single parameter > 0"
6
- fails "Enumerable#each_cons tries to convert n to an Integer using #to_int"
7
- fails "Enumerable#each_cons when no block is given Enumerable with no size when no block is given returned Enumerator size returns nil"
8
- fails "Enumerable#each_cons when no block is given Enumerable with size returned Enumerator size returns 0 when the argument is larger than self"
9
- fails "Enumerable#each_cons when no block is given Enumerable with size returned Enumerator size returns 0 when the enum is empty"
10
- fails "Enumerable#each_cons when no block is given Enumerable with size returned Enumerator size returns enum size - each_cons argument + 1"
11
- fails "Enumerable#each_cons when no block is given returns an enumerator"
12
- fails "Enumerable#each_cons works when n is >= full length"
13
- fails "Enumerable#each_cons yields only as much as needed"
14
2
  fails "Enumerable#each_entry Enumerable with no size when no block is given returned Enumerator size returns nil"
15
3
  fails "Enumerable#each_entry Enumerable with size when no block is given returned Enumerator size returns the enumerable size"
16
4
  fails "Enumerable#each_entry passes extra arguments to #each"
17
5
  fails "Enumerable#each_entry passes through the values yielded by #each_with_index"
18
6
  fails "Enumerable#each_entry returns an enumerator if no block"
19
7
  fails "Enumerable#each_entry yields multiple arguments as an array"
20
- fails "Enumerable#first raises a RangeError when passed a Bignum"
21
- fails "Enumerable#minmax gathers whole arrays as elements when each yields multiple"
22
- fails "Enumerable#minmax min should return the minimum element"
23
- fails "Enumerable#minmax raises a NoMethodError for elements without #<=>"
24
- fails "Enumerable#minmax raises an ArgumentError when elements are incomparable"
25
- fails "Enumerable#minmax returns the minimum when using a block rule"
26
- fails "Enumerable#minmax returns [nil, nil] for an empty Enumerable"
27
8
  fails "Enumerable#minmax_by Enumerable with no size when no block is given returned Enumerator size returns nil"
28
9
  fails "Enumerable#minmax_by Enumerable with size when no block is given returned Enumerator size returns the enumerable size"
29
10
  fails "Enumerable#minmax_by gathers whole arrays as elements when each yields multiple"
@@ -36,12 +36,8 @@ opal_filter "Exception" do
36
36
  fails "Exception#set_backtrace raises a TypeError when the Array contains a Symbol"
37
37
  fails "Exception#set_backtrace raises a TypeError when the array contains nil"
38
38
  fails "IOError is a superclass of EOFError"
39
- fails "NameError.new NameError.new should take optional name argument"
40
- fails "NoMethodError#args returns an array with the same elements as passed to the method"
41
- fails "NoMethodError#args returns an empty array if the caller method had no arguments"
42
39
  fails "NoMethodError#message for an protected method match /protected method/"
43
40
  fails "NoMethodError#message for private method match /private method/"
44
- fails "NoMethodError.new allows passing method args"
45
41
  fails "rescueing SignalException raises a SignalException when sent a signal"
46
42
  fails "SignalException.new raises an exception for an optional argument with a signal name"
47
43
  fails "SignalException.new raises an exception with an invalid signal name"
@@ -54,6 +54,8 @@ opal_filter "language" do
54
54
  fails "A singleton class raises a TypeError for symbols"
55
55
  fails "An ensure block inside a begin block is executed even when a symbol is thrown in it's corresponding begin block"
56
56
  fails "An ensure block inside a method is executed even when a symbol is thrown in the method"
57
+ fails "Assigning an anonymous module to a constant sets the name of contained modules when assigning a toplevel anonymous module"
58
+ fails "Assigning an anonymous module to a constant sets the name of the module"
57
59
  fails "calling methods on the metaclass calls a method defined on the metaclass of the metaclass"
58
60
  fails "Class methods of a singleton class for a class include class methods of Class"
59
61
  fails "Class methods of a singleton class for a class include instance methods of the singleton class of Class"
@@ -67,7 +69,10 @@ opal_filter "language" do
67
69
  fails "Operators * / % are left-associative"
68
70
  fails "self in a metaclass body (class << obj) raises a TypeError for numbers"
69
71
  fails "self in a metaclass body (class << obj) raises a TypeError for symbols"
72
+ fails "The __FILE__ pseudo-variable equals the absolute path of a file loaded by a relative path" # we can't clear $LOADED_FEATURES, should be treated as readonly
73
+ fails "The __FILE__ pseudo-variable equals the absolute path of a file loaded by an absolute path" # we can't clear $LOADED_FEATURES, should be treated as readonly
70
74
  fails "The alias keyword is not allowed against Fixnum or String instances"
75
+ fails "The alias keyword on top level defines the alias on Object"
71
76
  fails "The alias keyword operates on methods defined via attr, attr_reader, and attr_accessor"
72
77
  fails "The alias keyword operates on methods with splat arguments defined in a superclass using text block for class eval"
73
78
  fails "The alias keyword operates on the object's metaclass when used in instance_eval"
@@ -77,6 +82,7 @@ opal_filter "language" do
77
82
  fails "The BEGIN keyword runs in a shared scope"
78
83
  fails "The BEGIN keyword runs multiple begins in FIFO order"
79
84
  fails "The defined? keyword for a scoped constant does not call .const_missing if the constant is not defined"
85
+ fails "The defined? keyword for a scoped constant returns nil when a constant is defined on top-level but not on the module"
80
86
  fails "The defined? keyword for a scoped constant returns nil when an undefined constant is scoped to a defined constant"
81
87
  fails "The defined? keyword for a simple constant does not call Object.const_missing if the constant is not defined"
82
88
  fails "The defined? keyword for a simple constant returns 'constant' for a constant defined in an included module"
@@ -84,8 +90,8 @@ opal_filter "language" do
84
90
  fails "The defined? keyword for a simple constant returns 'constant' when the constant is defined"
85
91
  fails "The defined? keyword for a simple constant returns nil when the constant is not defined"
86
92
  fails "The defined? keyword for a top-level scoped constant returns nil when an undefined constant is scoped to a defined constant"
87
- fails "The defined? keyword for an expression returns nil for an expression with != and an undefined method"
88
93
  fails "The defined? keyword for an expression returns nil for an expression with !~ and an undefined method"
94
+ fails "The defined? keyword for an expression returns nil for an expression with != and an undefined method"
89
95
  fails "The defined? keyword for an expression returns nil for an expression with == and an undefined method"
90
96
  fails "The defined? keyword for an expression with logical connectives does not propagate an exception raised by a method in a 'not' expression"
91
97
  fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an undefined method"
@@ -150,8 +156,6 @@ opal_filter "language" do
150
156
  fails "The super keyword without explicit arguments passes optional arguments that have a default value"
151
157
  fails "The super keyword without explicit arguments passes optional arguments that have a non-default value but were modified"
152
158
  fails "The super keyword without explicit arguments passes rest arguments including any modifications"
153
- # can be removed when https://github.com/opal/opal/pull/1153 is merged
154
- fails "The undef keyword allows undefining multiple methods at a time"
155
159
  fails "The unpacking splat operator (*) unpacks arguments as if they were listed statically"
156
160
  fails "The until expression restarts the current iteration without reevaluating condition with redo"
157
161
  fails "The until modifier restarts the current iteration without reevaluating condition with redo"
@@ -159,6 +163,4 @@ opal_filter "language" do
159
163
  fails "The until modifier with begin .. end block restart the current iteration without reevaluting condition with redo"
160
164
  fails "The until modifier with begin .. end block runs block at least once (even if the expression is true)"
161
165
  fails "The until modifier with begin .. end block skips to end of body with next"
162
- fails "The __FILE__ pseudo-variable equals the absolute path of a file loaded by a relative path" # we can't clear $LOADED_FEATURES, should be treated as readonly
163
- fails "The __FILE__ pseudo-variable equals the absolute path of a file loaded by an absolute path" # we can't clear $LOADED_FEATURES, should be treated as readonly
164
166
  end