opal 1.2.0.beta1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/opal/corelib/hash.rb CHANGED
@@ -476,6 +476,15 @@ class Hash
476
476
 
477
477
  alias eql? ==
478
478
 
479
+ def except(*keys)
480
+ dup.except!(*keys)
481
+ end
482
+
483
+ def except!(*keys)
484
+ keys.each { |key| delete(key) }
485
+ self
486
+ end
487
+
479
488
  def fetch(key, defaults = undefined, &block)
480
489
  %x{
481
490
  var value = Opal.hash_get(self, key);
@@ -0,0 +1,159 @@
1
+ # A "userland" implementation of pattern matching for Opal
2
+
3
+ class PatternMatching
4
+ def self.call(from, pattern)
5
+ pm = new(from, pattern)
6
+ pm.match || (return nil)
7
+ pm.returns
8
+ end
9
+
10
+ def initialize(from, pattern)
11
+ @from, @pattern = from, pattern
12
+ @returns = []
13
+ end
14
+
15
+ attr_reader :returns
16
+
17
+ def match(from = @from, pattern = @pattern)
18
+ if pattern == :var
19
+ @returns << from
20
+ true
21
+ else # Pattern is otherwise an Array
22
+ type, *args = *pattern
23
+
24
+ case type
25
+ when :save # from =>
26
+ @returns << from
27
+ match(from, args[0])
28
+ when :lit # 3, 4, :a, (1..), ... (but also ^a)
29
+ args[0] === from
30
+ when :any # a | b
31
+ args.any? { |arg| match(from, arg) }
32
+ when :all # Array(1) which works as Array & [1] (& doesn't exist though...)
33
+ args.all? { |arg| match(from, arg) }
34
+ when :array # [...]
35
+ fixed_size, array_size, array_match = *args
36
+ return false unless from.respond_to? :deconstruct
37
+ a = from.deconstruct
38
+ return false if fixed_size && a.length != array_size
39
+ return false if a.length < array_size
40
+
41
+ skip_elems = 0
42
+ skip_rests = 0
43
+
44
+ array_match.each_with_index.all? do |elem, i|
45
+ type, *args = elem
46
+ case type
47
+ when :rest
48
+ skip_elems = a.size - array_size
49
+ skip_rests = 1
50
+ match(a[i...i + skip_elems], args[0]) if args[0] # :save?
51
+ true
52
+ else
53
+ match(a[i + skip_elems - skip_rests], elem)
54
+ end
55
+ end
56
+ when :find # [*, a, b, *]
57
+ find_match, = *args
58
+ first, *find_match, last = *find_match
59
+ pattern_length = find_match.length
60
+
61
+ return false unless from.respond_to? :deconstruct
62
+ a = from.deconstruct
63
+ a_length = a.length
64
+ return false if a_length < pattern_length
65
+
66
+ # We will save the backup of returns, to be restored
67
+ # on each iteration to try again.
68
+ returns_backup = @returns.dup
69
+
70
+ # Extract the capture info from first and last.
71
+ # Both are of a form [:rest], or [:rest, :var].
72
+ # So our new variables will be either :var, or nil.
73
+ first, last = first[1], last[1]
74
+
75
+ # Let's try to match each possibility...
76
+ # [A, B, c, d], [a, B, C, d], [a, b, C, D]
77
+ iterations = a_length - pattern_length + 1
78
+
79
+ iterations.times.any? do |skip|
80
+ first_part = a[0, skip]
81
+ content = a[skip, pattern_length]
82
+ last_part = a[skip + pattern_length..-1]
83
+
84
+ match(first_part, first) if first
85
+ success = content.each_with_index.all? do |e, i|
86
+ match(e, find_match[i])
87
+ end
88
+ match(last_part, last) if last
89
+
90
+ # Match failed. Let's not return anything.
91
+ @returns = returns_backup.dup unless success
92
+
93
+ success
94
+ end
95
+ when :hash # {...}
96
+ any_size, hash_match = *args
97
+
98
+ hash_match = hash_match.to_h
99
+
100
+ return false unless from.respond_to? :deconstruct_keys
101
+
102
+ if any_size && any_size != true # a => {a:, **other}
103
+ a = from.deconstruct_keys(nil) # ^^^^^^^
104
+ else
105
+ a = from.deconstruct_keys(hash_match.keys)
106
+ end
107
+
108
+ hash_match.all? do |k, v|
109
+ return false unless a.key? k
110
+ match(a[k], v)
111
+ end || (return false)
112
+
113
+ if any_size && any_size != true
114
+ match(a.except(*hash_match.keys), args[0])
115
+ elsif !any_size
116
+ return false unless a.except(*hash_match.keys).empty?
117
+ end
118
+
119
+ true
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ class Array
126
+ def deconstruct
127
+ self
128
+ end
129
+ end
130
+
131
+ class Hash
132
+ def deconstruct_keys(_)
133
+ self
134
+ end
135
+ end
136
+
137
+ class Struct
138
+ alias deconstruct to_a
139
+ # This function is specified in a very weird way...
140
+ def deconstruct_keys(keys)
141
+ return to_h if keys.nil?
142
+ raise TypeError, 'expected Array or nil' unless Array === keys
143
+ return {} if keys.length > values.length
144
+ out = {}
145
+ keys.each do |key|
146
+ should_break = case key
147
+ when Integer
148
+ values.length < key
149
+ when Symbol # Or String? Doesn't matter, we're in Opal.
150
+ !members.include?(key)
151
+ end
152
+ break if should_break
153
+ out[key] = self[key]
154
+ end
155
+ out
156
+ end
157
+ end
158
+
159
+ class NoMatchingPatternError < StandardError; end
data/opal/opal/full.rb CHANGED
@@ -2,3 +2,4 @@ require 'corelib/marshal'
2
2
  require 'corelib/string/unpack'
3
3
  require 'corelib/array/pack'
4
4
  require 'corelib/object_space'
5
+ require 'corelib/pattern_matching'
@@ -19,7 +19,6 @@ opal_filter "Array" do
19
19
  fails "Array#[]= with [m..] just sets the section defined by range to nil if m and n < 0 and the rhs is nil" # Opal::SyntaxError: undefined method `type' for nil
20
20
  fails "Array#[]= with [m..] replaces the section defined by range" # Opal::SyntaxError: undefined method `type' for nil
21
21
  fails "Array#[]= with [m..] replaces the section if m and n < 0" # Opal::SyntaxError: undefined method `type' for nil
22
- fails "Array#deconstruct returns self" # NoMethodError: undefined method `deconstruct' for [1]
23
22
  fails "Array#drop raises a TypeError when the passed argument can't be coerced to Integer" # Expected TypeError but no exception was raised ([1, 2] was returned)
24
23
  fails "Array#drop raises a TypeError when the passed argument isn't an integer and #to_int returns non-Integer" # Expected TypeError but no exception was raised ([1, 2] was returned)
25
24
  fails "Array#drop tries to convert the passed argument to an Integer using #to_int" # Expected [1, 2, 3] == [3] to be truthy but was false
@@ -9,9 +9,7 @@ opal_filter "Hash" do
9
9
  fails "Hash#[]= does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" # NoMethodError: undefined method `insert' for "rubyexe.rb"
10
10
  fails "Hash#[]= keeps the existing String key in the hash if there is a matching one" # Expected "foo" not to be identical to "foo"
11
11
  fails "Hash#compare_by_identity gives different identity for string literals" # Expected [2] to equal [1, 2]
12
- fails "Hash#deconstruct_keys ignores argument" # NoMethodError: undefined method `deconstruct_keys' for {"a"=>1, "b"=>2}
13
- fails "Hash#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: NoMethodError (undefined method `deconstruct_keys' for {"a"=>1})
14
- fails "Hash#deconstruct_keys returns self" # NoMethodError: undefined method `deconstruct_keys' for {"a"=>1, "b"=>2}
12
+ fails "Hash#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: ArgumentError ([Hash#deconstruct_keys] wrong number of arguments(0 for 1))
15
13
  fails "Hash#delete allows removing a key while iterating" # Exception: Cannot read property '$$is_string' of undefined
16
14
  fails "Hash#each always yields an Array of 2 elements, even when given a callable of arity 2" # Expected ArgumentError but no exception was raised ({"a"=>1} was returned)
17
15
  fails "Hash#each yields 2 values and not an Array of 2 elements when given a callable of arity 2" # ArgumentError: [Object#foo] wrong number of arguments(1 for 2)
@@ -21,9 +19,6 @@ opal_filter "Hash" do
21
19
  fails "Hash#eql? computes equality for complex recursive hashes"
22
20
  fails "Hash#eql? computes equality for recursive hashes & arrays"
23
21
  fails "Hash#except always returns a Hash without a default" # NoMethodError: undefined method `except' for {"bar"=>12, "foo"=>42}
24
- fails "Hash#except ignores keys not present in the original hash" # NoMethodError: undefined method `except' for {"a"=>1, "b"=>2, "c"=>3}
25
- fails "Hash#except returns a hash without the requested subset" # NoMethodError: undefined method `except' for {"a"=>1, "b"=>2, "c"=>3}
26
- fails "Hash#except returns a new duplicate hash without arguments" # NoMethodError: undefined method `except' for {"a"=>1, "b"=>2, "c"=>3}
27
22
  fails "Hash#inspect calls #to_s on the object returned from #inspect if the Object isn't a String" # Expected "{\"a\"=>abc}" to equal "{:a=>abc}"
28
23
  fails "Hash#inspect does not call #to_s on a String returned from #inspect" # Expected "{\"a\"=>\"abc\"}" to equal "{:a=>\"abc\"}"
29
24
  fails "Hash#inspect does not call #to_str on the object returned from #inspect when it is not a String" # Expected "{\"a\"=>#<MockObject:0x30638>}" to match /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
@@ -23,10 +23,8 @@ opal_filter "language" do
23
23
  fails "A block yielded a single Array raises a TypeError if #to_hash does not return a Hash"
24
24
  fails "A block yielded a single Array when non-symbol keys are in a keyword arguments Hash does not separate non-symbol keys and symbol keys and does not autosplat" # Expected [nil, {"a"=>10, "b"=>2}] == [[{"a"=>10, "b"=>2}], {}] to be truthy but was false
25
25
  fails "A block yielded a single Array when non-symbol keys are in a keyword arguments Hash separates non-symbol keys and symbol keys" # Expected [nil, {"a"=>10, "b"=>2}] to equal [{"a"=>10}, {"b"=>2}]
26
- fails "A class definition allows using self as the superclass if self is a class"
27
26
  fails "A class definition extending an object (sclass) allows accessing the block of the original scope" # Opal::SyntaxError: undefined method `uses_block!' for nil
28
27
  fails "A class definition extending an object (sclass) can use return to cause the enclosing method to return"
29
- fails "A class definition extending an object (sclass) raises a TypeError when trying to extend non-Class" # Expected TypeError (/superclass must be a.* Class/) but no exception was raised (nil was returned)
30
28
  fails "A class definition extending an object (sclass) raises a TypeError when trying to extend numbers"
31
29
  fails "A class definition raises TypeError if any constant qualifying the class is not a Module"
32
30
  fails "A class definition raises TypeError if the constant qualifying the class is nil"
@@ -116,6 +114,7 @@ opal_filter "language" do
116
114
  fails "Global variable $\" is read-only"
117
115
  fails "Hash literal checks duplicated keys on initialization" # Expected warning to match: /key 1000 is duplicated|duplicated key/ but got: ""
118
116
  fails "Hash literal expands a BasicObject using ** into the containing Hash literal initialization" # NoMethodError: undefined method `respond_to?' for BasicObject
117
+ fails "Hash#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: ArgumentError ([Hash#deconstruct_keys] wrong number of arguments(0 for 1))
119
118
  fails "Heredoc string allow HEREDOC with <<\"identifier\", interpolated" # Expected #<Encoding:UTF-16LE> to equal #<Encoding:ASCII-8BIT (dummy)>
120
119
  fails "Heredoc string allows HEREDOC with <<'identifier', no interpolation" # Expected #<Encoding:UTF-16LE> to equal #<Encoding:ASCII-8BIT (dummy)>
121
120
  fails "Heredoc string allows HEREDOC with <<-'identifier', allowing to indent identifier, no interpolation" # Expected #<Encoding:UTF-16LE> to equal #<Encoding:ASCII-8BIT (dummy)>
@@ -208,84 +207,29 @@ opal_filter "language" do
208
207
  fails "Optional variable assignments using compounded constants with &&= assignments" # Expected warning to match: /already initialized constant/ but got: ""
209
208
  fails "Optional variable assignments using compounded constants with operator assignments" # Expected warning to match: /already initialized constant/ but got: ""
210
209
  fails "Optional variable assignments using compunded constants with ||= assignments"
211
- fails "Pattern matching AS pattern binds a variable to a value if pattern matches" # Opal::SyntaxError: `n' is not allowed as a local variable name
212
- fails "Pattern matching AS pattern can be used as a nested pattern" # Opal::SyntaxError: `ary' is not allowed as a local variable name
213
- fails "Pattern matching Array pattern accepts a subclass of Array from #deconstruct" # Opal::SyntaxError: Unsupported sexp: case_match
214
- fails "Pattern matching Array pattern binds variables" # Opal::SyntaxError: `a' is not allowed as a local variable name
215
- fails "Pattern matching Array pattern calls #deconstruct even on objects that are already an array" # Opal::SyntaxError: Unsupported sexp: case_match
216
- fails "Pattern matching Array pattern calls #deconstruct once for multiple patterns, caching the result" # Opal::SyntaxError: Unsupported sexp: case_match
217
- fails "Pattern matching Array pattern does match partially from the array beginning if list + , syntax used" # Opal::SyntaxError: Unsupported sexp: case_match
218
- fails "Pattern matching Array pattern does not match object if Constant === object returns false" # Opal::SyntaxError: Unsupported sexp: case_match
219
- fails "Pattern matching Array pattern does not match object if elements of array returned by #deconstruct method does not match elements in pattern" # Opal::SyntaxError: Unsupported sexp: case_match
220
- fails "Pattern matching Array pattern does not match object without #deconstruct method" # Mock '#<Object:0x75326>' expected to receive respond_to?("deconstruct") exactly 1 times but received it 0 times
221
- fails "Pattern matching Array pattern does not match partially by default" # Opal::SyntaxError: Unsupported sexp: case_match
222
- fails "Pattern matching Array pattern matches [] with []" # Opal::SyntaxError: Unsupported sexp: case_match
223
- fails "Pattern matching Array pattern matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" # Opal::SyntaxError: Unsupported sexp: case_match
224
- fails "Pattern matching Array pattern matches anything with *" # Opal::SyntaxError: Unsupported sexp: case_match
225
- fails "Pattern matching Array pattern raises TypeError if #deconstruct method does not return array" # Expected TypeError (/deconstruct must return Array/) but got: Opal::SyntaxError (Unsupported sexp: case_match)
226
- fails "Pattern matching Array pattern supports form Constant(pat, pat, ...)" # Opal::SyntaxError: Unsupported sexp: case_match
227
- fails "Pattern matching Array pattern supports form Constant[pat, pat, ...]" # Opal::SyntaxError: Unsupported sexp: case_match
228
- fails "Pattern matching Array pattern supports form [pat, pat, ...]" # Opal::SyntaxError: Unsupported sexp: case_match
229
- fails "Pattern matching Array pattern supports form pat, pat, ..." # Opal::SyntaxError: Unsupported sexp: case_match
230
- fails "Pattern matching Array pattern supports splat operator *rest" # Opal::SyntaxError: `rest' is not allowed as a local variable name
231
- fails "Pattern matching Hash pattern binds variables" # Opal::SyntaxError: `x' is not allowed as a local variable name
232
- fails "Pattern matching Hash pattern calls #deconstruct_keys per pattern" # Opal::SyntaxError: Unsupported sexp: case_match
233
- fails "Pattern matching Hash pattern can match partially" # Opal::SyntaxError: Unsupported sexp: case_match
234
- fails "Pattern matching Hash pattern can mix key (a:) and key-value (a: b) declarations" # Opal::SyntaxError: `a' is not allowed as a local variable name
235
- fails "Pattern matching Hash pattern does not match object if #deconstruct_keys method does not return Hash" # Expected TypeError (/deconstruct_keys must return Hash/) but got: Opal::SyntaxError (Unsupported sexp: case_match)
236
- fails "Pattern matching Hash pattern does not match object if #deconstruct_keys method returns Hash with non-symbol keys" # Opal::SyntaxError: Unsupported sexp: case_match
237
- fails "Pattern matching Hash pattern does not match object if Constant === object returns false" # Opal::SyntaxError: Unsupported sexp: case_match
238
- fails "Pattern matching Hash pattern does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" # Opal::SyntaxError: Unsupported sexp: case_match
239
- fails "Pattern matching Hash pattern does not match object without #deconstruct_keys method" # Mock '#<Object:0x78c14>' expected to receive respond_to?("deconstruct_keys") exactly 1 times but received it 0 times
240
- fails "Pattern matching Hash pattern matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" # Opal::SyntaxError: Unsupported sexp: case_match
241
- fails "Pattern matching Hash pattern matches anything with **" # Opal::SyntaxError: Unsupported sexp: case_match
242
- fails "Pattern matching Hash pattern matches {} with {}" # Opal::SyntaxError: Unsupported sexp: case_match
243
- fails "Pattern matching Hash pattern passes keys specified in pattern as arguments to #deconstruct_keys method" # Opal::SyntaxError: Unsupported sexp: case_match
244
- fails "Pattern matching Hash pattern passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" # Opal::SyntaxError: Unsupported sexp: case_match
245
- fails "Pattern matching Hash pattern passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" # Opal::SyntaxError: `rest' is not allowed as a local variable name
210
+ fails "Pattern matching Array pattern accepts a subclass of Array from #deconstruct" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
211
+ fails "Pattern matching Array pattern calls #deconstruct even on objects that are already an array" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
212
+ fails "Pattern matching Array pattern calls #deconstruct once for multiple patterns, caching the result" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
213
+ fails "Pattern matching Array pattern does not match object if elements of array returned by #deconstruct method does not match elements in pattern" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
214
+ fails "Pattern matching Array pattern does not match object without #deconstruct method" # Mock '#<Object:0x239ca>' expected to receive respond_to?("deconstruct") exactly 1 times but received it 0 times
215
+ fails "Pattern matching Array pattern matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
216
+ fails "Pattern matching Array pattern raises TypeError if #deconstruct method does not return array" # Expected TypeError (/deconstruct must return Array/) but got: NoMethodError (undefined method `obj' for #<MSpecEnv:0x1af0a>)
217
+ fails "Pattern matching Hash pattern calls #deconstruct_keys per pattern" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
218
+ fails "Pattern matching Hash pattern does not match object if #deconstruct_keys method does not return Hash" # Expected TypeError (/deconstruct_keys must return Hash/) but got: NoMethodError (undefined method `obj' for #<MSpecEnv:0x1af0a>)
219
+ fails "Pattern matching Hash pattern does not match object if #deconstruct_keys method returns Hash with non-symbol keys" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
220
+ fails "Pattern matching Hash pattern does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
221
+ fails "Pattern matching Hash pattern does not match object without #deconstruct_keys method" # Mock '#<Object:0x29382>' expected to receive respond_to?("deconstruct_keys") exactly 1 times but received it 0 times
222
+ fails "Pattern matching Hash pattern matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
223
+ fails "Pattern matching Hash pattern passes keys specified in pattern as arguments to #deconstruct_keys method" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
224
+ fails "Pattern matching Hash pattern passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
225
+ fails "Pattern matching Hash pattern passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" # NoMethodError: undefined method `obj' for #<MSpecEnv:0x1af0a>
246
226
  fails "Pattern matching Hash pattern raise SyntaxError when keys duplicate in pattern" # Expected SyntaxError (/duplicated key name/) but got: Opal::SyntaxError (duplicate hash pattern key a)
247
- fails "Pattern matching Hash pattern supports 'string': key literal" # Opal::SyntaxError: Unsupported sexp: case_match
248
- fails "Pattern matching Hash pattern supports a: which means a: a" # Opal::SyntaxError: `a' is not allowed as a local variable name
249
- fails "Pattern matching Hash pattern supports double splat operator **rest" # Opal::SyntaxError: `rest' is not allowed as a local variable name
250
- fails "Pattern matching Hash pattern supports form Constant(id: pat, id: pat, ...)" # Opal::SyntaxError: Unsupported sexp: case_match
251
- fails "Pattern matching Hash pattern supports form Constant[id: pat, id: pat, ...]" # Opal::SyntaxError: Unsupported sexp: case_match
252
- fails "Pattern matching Hash pattern supports form id: pat, id: pat, ..." # Opal::SyntaxError: Unsupported sexp: case_match
253
- fails "Pattern matching Hash pattern supports form {id: pat, id: pat, ...}" # Opal::SyntaxError: Unsupported sexp: case_match
254
- fails "Pattern matching Hash pattern treats **nil like there should not be any other keys in a matched Hash" # Opal::SyntaxError: Unsupported sexp: case_match
255
- fails "Pattern matching allows using then operator" # Opal::SyntaxError: Unsupported sexp: case_match
256
- fails "Pattern matching alternative pattern does not support variable binding" # Expected SyntaxError (/illegal variable in alternative pattern/) but got: Opal::SyntaxError (`a' is not allowed as a local variable name)
257
- fails "Pattern matching alternative pattern matches if any of patterns matches" # Opal::SyntaxError: Unsupported sexp: case_match
258
- fails "Pattern matching alternative pattern support underscore prefixed variables in alternation" # Opal::SyntaxError: `_' is not allowed as a local variable name
259
- fails "Pattern matching binds variables" # Opal::SyntaxError: `a' is not allowed as a local variable name
260
- fails "Pattern matching can be standalone assoc operator that deconstructs value" # Opal::SyntaxError: `a' is not allowed as a local variable name
227
+ fails "Pattern matching alternative pattern does not support variable binding" # Expected SyntaxError (/illegal variable in alternative pattern/) but no exception was raised (nil was returned)
261
228
  fails "Pattern matching cannot mix in and when operators" # Expected SyntaxError (/syntax error, unexpected `in'/) but got: Opal::SyntaxError (unexpected token kIN)
262
- fails "Pattern matching checks patterns until the first matching" # Opal::SyntaxError: Unsupported sexp: case_match
263
- fails "Pattern matching evaluates the case expression once for multiple patterns, caching the result" # Opal::SyntaxError: Unsupported sexp: case_match
264
- fails "Pattern matching executes else clause if no pattern matches" # Opal::SyntaxError: Unsupported sexp: case_match
265
- fails "Pattern matching extends case expression with case/in construction" # Opal::SyntaxError: Unsupported sexp: case_match
266
- fails "Pattern matching guards does not evaluate guard if pattern does not match" # Opal::SyntaxError: Unsupported sexp: case_match
267
- fails "Pattern matching guards executes else clause if no guarded pattern matches" # Opal::SyntaxError: Unsupported sexp: case_match
268
- fails "Pattern matching guards makes bound variables visible in guard" # Opal::SyntaxError: `a' is not allowed as a local variable name
269
- fails "Pattern matching guards raises NoMatchingPatternError if no guarded pattern matches and no else clause" # NameError: uninitialized constant NoMatchingPatternError
270
- fails "Pattern matching guards supports if guard" # Opal::SyntaxError: Unsupported sexp: case_match
271
- fails "Pattern matching guards supports unless guard" # Opal::SyntaxError: Unsupported sexp: case_match
272
- fails "Pattern matching guards takes guards into account when there are several matching patterns" # Opal::SyntaxError: Unsupported sexp: case_match
273
- fails "Pattern matching raises NoMatchingPatternError if no pattern matches and no else clause" # NameError: uninitialized constant NoMatchingPatternError
274
- fails "Pattern matching refinements are used for #=== in constant pattern" # NoMethodError: undefined method `refine' for #<Module:0x79d4c>
275
- fails "Pattern matching refinements are used for #deconstruct" # NoMethodError: undefined method `refine' for #<Module:0x79d50>
276
- fails "Pattern matching refinements are used for #deconstruct_keys" # NoMethodError: undefined method `refine' for #<Module:0x79d54>
277
- fails "Pattern matching value pattern allows string literal with interpolation" # Opal::SyntaxError: Unsupported sexp: case_match
278
- fails "Pattern matching value pattern matches an object such that pattern === object" # Opal::SyntaxError: Unsupported sexp: case_match
279
- fails "Pattern matching variable pattern allow using _ name to drop values" # Opal::SyntaxError: `a' is not allowed as a local variable name
280
- fails "Pattern matching variable pattern allows applying ^ operator to bound variables" # Opal::SyntaxError: `n' is not allowed as a local variable name
281
- fails "Pattern matching variable pattern create local variables even if a pattern doesn't match" # Opal::SyntaxError: `a' is not allowed as a local variable name
282
- fails "Pattern matching variable pattern does not support using variable name (except _) several times" # Expected SyntaxError (/duplicated variable name/) but got: Opal::SyntaxError (`a' is not allowed as a local variable name)
283
- fails "Pattern matching variable pattern makes bounded variable visible outside a case statement scope" # Opal::SyntaxError: `a' is not allowed as a local variable name
284
- fails "Pattern matching variable pattern matches a value and binds variable name to this value" # Opal::SyntaxError: `a' is not allowed as a local variable name
229
+ fails "Pattern matching variable pattern allows applying ^ operator to bound variables" # NoMatchingPatternError: [1, 1]
230
+ fails "Pattern matching variable pattern does not support using variable name (except _) several times" # Expected SyntaxError (/duplicated variable name/) but got: Opal::SyntaxError (duplicate variable name a)
285
231
  fails "Pattern matching variable pattern requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" # Expected SyntaxError (/n: no such local variable/) but got: Opal::SyntaxError (no such local variable: `n')
286
232
  fails "Pattern matching variable pattern supports existing variables in a pattern specified with ^ operator" # Opal::SyntaxError: no such local variable: `a'
287
- fails "Pattern matching variable pattern supports using _ in a pattern several times" # Opal::SyntaxError: `_' is not allowed as a local variable name
288
- fails "Pattern matching variable pattern supports using any name with _ at the beginning in a pattern several times" # Opal::SyntaxError: `_x' is not allowed as a local variable name
289
233
  fails "Pattern matching warning warns about pattern matching is experimental feature" # NameError: uninitialized constant Warning
290
234
  fails "Post-args with optional args with a circular argument reference shadows an existing local with the same name as the argument"
291
235
  fails "Post-args with optional args with a circular argument reference shadows an existing method with the same name as the argument"
@@ -319,6 +263,7 @@ opal_filter "language" do
319
263
  fails "Safe navigator allows assignment methods"
320
264
  fails "Safe navigator allows assignment operators"
321
265
  fails "Safe navigator does not call the operator method lazily with an assignment operator"
266
+ fails "Struct#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: ArgumentError ([#deconstruct_keys] wrong number of arguments(0 for 1))
322
267
  fails "The =~ operator with named captures on syntax of 'string_literal' =~ /regexp/ does not set local variables" # Exception: named captures are not supported in javascript: "(?<matched>foo)(?<unmatched>bar)?"
323
268
  fails "The =~ operator with named captures on syntax of /regexp/ =~ string_variable sets local variables by the captured pairs"
324
269
  fails "The =~ operator with named captures on syntax of regexp_variable =~ string_variable does not set local variables"
@@ -299,4 +299,5 @@ opal_filter "String" do
299
299
  fails "String#valid_encoding? returns true for IBM720 encoding self is valid in" # ArgumentError: unknown encoding name - IBM720
300
300
  fails "String.new accepts an encoding argument" # ArgumentError: [String.new] wrong number of arguments(2 for -1)
301
301
  fails "String.new is called on subclasses" # Expected nil to equal "subclass"
302
+ fails "Struct#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: ArgumentError ([#deconstruct_keys] wrong number of arguments(0 for 1))
302
303
  end
@@ -1,15 +1,5 @@
1
1
  # NOTE: run bin/format-filters after changing this file
2
2
  opal_filter "Struct" do
3
- fails "Struct#deconstruct returns an array of attribute values" # NoMethodError: undefined method `deconstruct' for #<struct x=1, y=2>
4
- fails "Struct#deconstruct_keys accepts argument position number as well but returns them as keys" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=10, y=20, z=30>
5
- fails "Struct#deconstruct_keys accepts nil argument and return all the attributes" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2>
6
- fails "Struct#deconstruct_keys accepts string attribute names" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2>
7
- fails "Struct#deconstruct_keys raise TypeError if passed anything accept nil or array" # Expected TypeError (/expected Array or nil/) but got: NoMethodError (undefined method `deconstruct_keys' for #<struct x=1, y=2>)
8
- fails "Struct#deconstruct_keys requires one argument" # Expected ArgumentError (/wrong number of arguments \(given 0, expected 1\)/) but got: NoMethodError (undefined method `deconstruct_keys' for #<struct x=1>)
9
- fails "Struct#deconstruct_keys returns a hash of attributes" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2>
10
- fails "Struct#deconstruct_keys returns an empty hash when there are more keys than attributes" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2>
11
- fails "Struct#deconstruct_keys returns at first not existing attribute name" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2>
12
- fails "Struct#deconstruct_keys returns only specified keys" # NoMethodError: undefined method `deconstruct_keys' for #<struct x=1, y=2, z=3>
13
3
  fails "Struct#dig returns the value by the index" # Expected nil == "one" to be truthy but was false
14
4
  fails "Struct#hash returns different hashes for different struct classes" # Expected "Hash" != "Hash" to be truthy but was false
15
5
  fails "Struct#hash returns different hashes for structs with different values when using keyword_init: true" # NameError: wrong constant name 1 non symbol member
@@ -2,4 +2,7 @@
2
2
  opal_unsupported_filter "Refinements" do
3
3
  fails "Kernel#eval with refinements activates refinements from the binding" # NoMethodError: undefined method `refine' for #<Module:0x7ad6a>
4
4
  fails "Kernel#eval with refinements activates refinements from the eval scope" # NoMethodError: undefined method `refine' for #<Module:0x7ad6e>
5
+ fails "Pattern matching refinements are used for #=== in constant pattern" # NoMethodError: undefined method `refine' for #<Module:0x46556>
6
+ fails "Pattern matching refinements are used for #deconstruct" # NoMethodError: undefined method `refine' for #<Module:0x4655e>
7
+ fails "Pattern matching refinements are used for #deconstruct_keys" # NoMethodError: undefined method `refine' for #<Module:0x4655a>
5
8
  end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe "pattern matching" do
4
+ it "supports basic assignment" do
5
+ 5 => a
6
+ a.should == 5
7
+ end
8
+
9
+ it "supports array pattern" do
10
+ [1,2,3,4] => [1,2,*rest]
11
+ rest.should == [3,4]
12
+ [1,2,3,4] => [*rest,3,x]
13
+ rest.should == [1,2]
14
+ x.should == 4
15
+ end
16
+
17
+ it "supports hash pattern" do
18
+ {a: 4} => {a:}
19
+ a.should == 4
20
+ {a: 4, b: 6} => {b:}
21
+ b.should == 6
22
+ {a: 1, b: 2, c: 3} => {a: 1, **rest}
23
+ rest.should == {b: 2, c: 3}
24
+ end
25
+
26
+ it "supports pinning" do
27
+ a = 6
28
+ 6 => ^a
29
+ a.should == 6
30
+ end
31
+
32
+ it "supports a lambda literal" do
33
+ [6, 7] => [->(a) { a == 6 }, b]
34
+ b.should == 7
35
+ end
36
+
37
+ it "supports constants" do
38
+ [6, 7, 8] => [Integer, a, Integer]
39
+ a.should == 7
40
+ end
41
+
42
+ it "supports regexps" do
43
+ "test" => /e(s)t/
44
+ $1.should == 's'
45
+ end
46
+
47
+ it "supports save pattern" do
48
+ [6, 7, 8] => [Integer=>a, Integer=>b, Integer=>c]
49
+ [a,b,c].should == [6, 7, 8]
50
+ end
51
+
52
+ it "supports find pattern with save" do
53
+ [1, 2, 3, 4, 5] => [*before, 3 => three, 4 => four, *after]
54
+ before.should == [1,2]
55
+ three.should == 3
56
+ four.should == 4
57
+ after.should == [5]
58
+ end
59
+
60
+ it "supports custom classes" do
61
+ class TotallyArrayOrHashLike
62
+ def deconstruct
63
+ [1,2,3]
64
+ end
65
+
66
+ def deconstruct_keys(_)
67
+ {a: 1, b: 2}
68
+ end
69
+ end
70
+
71
+ TotallyArrayOrHashLike.new => TotallyArrayOrHashLike[*array]
72
+ array.should == [1,2,3]
73
+
74
+ TotallyArrayOrHashLike.new => TotallyArrayOrHashLike(**hash)
75
+ hash.should == {a: 1, b: 2}
76
+ end
77
+
78
+ it "supports case expressions" do
79
+ case 4
80
+ in 4
81
+ z = true
82
+ in 5
83
+ z = false
84
+ end
85
+
86
+ z.should == true
87
+ end
88
+
89
+ it "supports case expressions with guards" do
90
+ case 4
91
+ in 4 if false
92
+ z = true
93
+ in 4 if true
94
+ z = false
95
+ end
96
+
97
+ z.should == false
98
+ end
99
+
100
+ it "raises if case expression is unmatched" do
101
+ proc do
102
+ case 4
103
+ in 5
104
+ :test
105
+ end
106
+ end.should raise_error NoMatchingPatternError
107
+ end
108
+
109
+ it "doesn't raise when else in a case expression is present" do
110
+ case 4
111
+ in 5
112
+ z = true
113
+ else
114
+ z = false
115
+ end
116
+
117
+ z.should == false
118
+ end
119
+
120
+ it "doesn't raise or set variables if an in expression is unmatched" do
121
+ 4 in String => a
122
+ a.should == nil
123
+ end
124
+ end