1 # frozen_string_literal: false
5 class TestRubyYield < Test::Unit::TestCase
9 ary.each {|a, b, c, d| assert_equal [1,nil,nil,nil], [a,b,c,d] }
10 ary.each {|a, b, c| assert_equal [1,nil,nil], [a,b,c] }
11 ary.each {|a, b| assert_equal [1,nil], [a,b] }
12 ary.each {|a| assert_equal 1, a }
22 assert_equal [:a, 1], kv
27 assert_equal 1, iter0 { 1 }
28 assert_equal 2, iter0 { 2 }
36 iter1([]) {|a, b| assert_equal [nil,nil], [a, b] }
37 iter1([1]) {|a, b| assert_equal [1,nil], [a, b] }
38 iter1([1, 2]) {|a, b| assert_equal [1,2], [a,b] }
39 iter1([1, 2, 3]) {|a, b| assert_equal [1,2], [a,b] }
41 iter1([]) {|a| assert_equal [], a }
42 iter1([1]) {|a| assert_equal [1], a }
43 iter1([1, 2]) {|a| assert_equal [1,2], a }
44 iter1([1, 2, 3]) {|a| assert_equal [1,2,3], a }
52 def iter2_1() yield 1, *[2, 3] end
53 iter2_1 {|a, b, c| assert_equal [1,2,3], [a,b,c] }
54 def iter2_2() yield 1, *[] end
55 iter2_2 {|a, b, c| assert_equal [1,nil,nil], [a,b,c] }
56 def iter2_3() yield 1, *[2] end
57 iter2_3 {|a, b, c| assert_equal [1,2,nil], [a,b,c] }
61 [[1, [2, 3]]].each {|a, (b, c)|
62 assert_equal [1,2,3], [a,b,c]
64 [[1, [2, 3]]].map {|a, (b, c)|
65 assert_equal [1,2,3], [a,b,c]
74 obj.each{|*v| assert_equal([], [], '[ruby-dev:32392]')}
75 obj.to_enum.each{|*v| assert_equal([], [], '[ruby-dev:32392]')}
78 def block_args_unleashed
82 def test_block_args_unleashed
83 r = block_args_unleashed {|a,b=1,*c,d,e|
86 assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]")
90 require_relative 'sentence'
91 class TestRubyYieldGen < Test::Unit::TestCase
100 :opt_block_param => [[],
102 :block_param_def => [['|', '|'],
103 ['|', :block_param, '|']],
104 :block_param => [[:f_arg, ",", :f_rest_arg, :opt_f_block_arg],
106 [:f_arg, ',', :f_rest_arg, ",", :f_arg, :opt_f_block_arg],
107 [:f_arg, :opt_f_block_arg],
108 [:f_rest_arg, :opt_f_block_arg],
109 [:f_rest_arg, ',', :f_arg, :opt_f_block_arg],
111 :f_arg => [[:f_arg_item],
112 [:f_arg, ',', :f_arg_item]],
113 :f_rest_arg => [['*', "var"],
115 :opt_f_block_arg => [[',', :f_block_arg],
117 :f_block_arg => [['&', 'var']],
118 :f_arg_item => [[:f_norm_arg],
119 ['(', :f_margs, ')']],
120 :f_margs => [[:f_marg_list],
121 [:f_marg_list, ',', '*', :f_norm_arg],
122 [:f_marg_list, ',', '*', :f_norm_arg, ',', :f_marg_list],
123 [:f_marg_list, ',', '*'],
124 [:f_marg_list, ',', '*', ',', :f_marg_list],
126 [ '*', :f_norm_arg, ',', :f_marg_list],
128 [ '*', ',', :f_marg_list]],
129 :f_marg_list => [[:f_marg],
130 [:f_marg_list, ',', :f_marg]],
131 :f_marg => [[:f_norm_arg],
132 ['(', :f_margs, ')']],
133 :f_norm_arg => [['var']],
135 :command_args => [[:open_args]],
136 :open_args => [[' ',:call_args],
138 ['(', :call_args2, ')']],
139 :call_args => [[:command],
140 [ :args, :opt_block_arg],
141 [ :assocs, :opt_block_arg],
142 [ :args, ',', :assocs, :opt_block_arg],
144 :call_args2 => [[:arg, ',', :args, :opt_block_arg],
145 [:arg, ',', :block_arg],
146 [ :assocs, :opt_block_arg],
147 [:arg, ',', :assocs, :opt_block_arg],
148 [:arg, ',', :args, ',', :assocs, :opt_block_arg],
151 :command_args_noblock => [[:open_args_noblock]],
152 :open_args_noblock => [[' ',:call_args_noblock],
154 ['(', :call_args2_noblock, ')']],
155 :call_args_noblock => [[:command],
158 [ :args, ',', :assocs]],
159 :call_args2_noblock => [[:arg, ',', :args],
161 [:arg, ',', :assocs],
162 [:arg, ',', :args, ',', :assocs]],
168 [:args,",","*",:arg]],
170 :assocs => [[:assoc],
171 [:assocs, ',', :assoc]],
172 :assoc => [[:arg, '=>', :arg],
173 ['label', ':', :arg]],
174 :opt_block_arg => [[',', :block_arg],
176 :block_arg => [['&', :arg]],
177 #:test => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']]
178 :test_proc => [['def m() yield', :command_args_noblock, ' end; r = m {', :block_param_def, 'vars', '}; undef m; r']],
179 :test_lambda => [['def m() yield', :command_args_noblock, ' end; r = m(&lambda {', :block_param_def, 'vars', '}); undef m; r']],
180 :test_enum => [['o = Object.new; def o.each() yield', :command_args_noblock, ' end; r1 = r2 = nil; o.each {|*x| r1 = x }; o.to_enum.each {|*x| r2 = x }; [r1, r2]']]
185 r = obj.subst('var') {
186 var = "v#{vars.length}"
193 def split_by_comma(ary)
194 return [] if ary.empty?
206 def emu_return_args(*vs)
210 def emu_eval_args(args)
214 code = "emu_return_args(#{args.map {|a| a.join('') }.join(",")})"
215 eval code, nil, 'generated_code_in_emu_eval_args'
218 def emu_bind_single(arg, param, result_binding)
219 #p [:emu_bind_single, arg, param]
220 if param.length == 1 && String === param[0] && /\A[a-z0-9]+\z/ =~ param[0]
221 result_binding[param[0]] = arg
222 elsif param.length == 1 && Array === param[0] && param[0][0] == '(' && param[0][-1] == ')'
223 arg = [arg] unless Array === arg
224 emu_bind_params(arg, split_by_comma(param[0][1...-1]), false, result_binding)
226 raise "unexpected param: #{param.inspect}"
231 def emu_bind_params(args, params, islambda, result_binding={})
232 #p [:emu_bind_params, args, params]
233 if params.last == [] # extra comma
238 params.each_with_index {|par, i|
239 star_index = i if par[0] == '*'
244 if args.length < params.length - 1
245 throw :emuerror, ArgumentError
248 if args.length != params.length
249 throw :emuerror, ArgumentError
254 # TRICK #2 : adjust mismatch on number of arguments
256 pre_params = params[0...star_index]
257 rest_param = params[star_index]
258 post_params = params[(star_index+1)..-1]
259 pre_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
260 if post_params.length <= args.length
261 post_params.reverse_each {|par| emu_bind_single(args.pop, par, result_binding) }
263 post_params.each {|par| emu_bind_single(args.shift, par, result_binding) }
265 if rest_param != ['*']
266 emu_bind_single(args, rest_param[1..-1], result_binding)
269 params.each_with_index {|par, i|
270 emu_bind_single(args[i], par, result_binding)
274 #p [args, params, result_binding]
279 def emu_bind(t, islambda)
282 command_args_noblock = t[1]
283 block_param_def = t[3]
284 command_args_noblock = command_args_noblock.expand {|a| !(a[0] == '[' && a[-1] == ']') }
285 block_param_def = block_param_def.expand {|a| !(a[0] == '(' && a[-1] == ')') }
287 if command_args_noblock.to_a[0] == ' '
288 args = command_args_noblock.to_a[1..-1]
289 elsif command_args_noblock.to_a[0] == '(' && command_args_noblock.to_a[-1] == ')'
290 args = command_args_noblock.to_a[1...-1]
292 raise "unexpected command_args_noblock: #{command_args_noblock.inspect}"
294 args = emu_eval_args(split_by_comma(args))
296 params = block_param_def.to_a[1...-1]
297 params = split_by_comma(params)
299 #p [:emu0, args, params]
303 if params.last && params.last[0] == '&'
304 result_binding[params.last[1]] = nil
309 # TRICK #1 : single array argument is expanded if there are two or more params.
310 # * block parameter is not counted.
311 # * extra comma after single param forces the expansion.
312 if args.length == 1 && Array === args[0] && 1 < params.length
317 emu_bind_params(args, params, islambda, result_binding)
322 def emu(t, vars, islambda)
324 emu_binding = emu_bind(t, islambda)
325 vars.map {|var| emu_binding.fetch(var, "NOVAL") }
331 save_stderr = $stderr
332 $stderr = StringIO.new
335 $stderr = save_stderr
339 def check_nofork(t, islambda=false)
340 t, vars = rename_var(t)
341 t = t.subst('vars') { " [#{vars.join(",")}]" }
342 emu_values = emu(t, vars, islambda)
347 eval_values = disable_stderr {
349 o.instance_eval(s, 'generated_code_in_check_nofork')
354 #success = emu_values == eval_values ? 'succ' : 'fail'
355 #puts "eval:#{vs_ev.inspect[1...-1].delete(' ')}\temu:#{vs_emu.inspect[1...-1].delete(' ')}\t#{success}"
356 assert_equal(emu_values, eval_values, s)
359 def assert_all_sentences(syntax, *args)
360 syntax = Sentence.expand_syntax(syntax)
361 all_assertions do |a|
362 Sentence.each(syntax, *args) {|t|
369 assert_all_sentences(Syntax, :test_proc, 4) {|t|
374 def test_yield_lambda
375 assert_all_sentences(Syntax, :test_lambda, 4) {|t|
376 check_nofork(t, true)
381 assert_all_sentences(Syntax, :test_enum, 4) {|t|
383 r1, r2 = disable_stderr {
384 eval(code, nil, 'generated_code_in_test_yield_enum')
386 assert_equal(r1, r2, "#{t}")
390 def test_block_with_mock
396 def m.method_missing(*a)
399 assert_equal [m, nil], y.s(m){|a,b|[a,b]}
402 def test_block_cached_argc
404 assert_separately([], <<-"end;")
413 Yielder.new.each(&block)
419 Yielder.new.each { |a, b, c, d| yield(a) }
422 Getter1.new.map{Getter2.new.each{|x|}}