require 'test/unit' class TestBlock < Test::Unit::TestCase def test_block_variable_closure values = [] 5.times do |i| values.push i end assert_equal([0,1,2,3,4], values) values = [] 2.step 10, 2 do |i| values.push i end assert_equal([2,4,6,8,10], values) end def test_block_break values = [] [1,2,3].each {|v| values << v; break } assert_equal([1], values) values = [] result = [1,2,3,4,5].collect {|v| if v > 2 break end values << v v } assert_equal([1,2], values) assert(result.nil?) end def method1 if object_id # Any non-toplevel method will do yield end end def method2 method1 { yield } end def test_block_yield flag = false method2 { flag = true } assert(flag) end class TestBlock_Foo def foo Proc.new { self } end end def test_proc_as_block_arg proc = TestBlock_Foo.new.foo o = Object.new assert_equal(o, o.instance_eval(&proc)) end def test_proc_arity assert_equal(-1, Proc.new { 1 }.arity) #assert_equal(0, Proc.new{|| 1 }.arity) #assert_equal(2, Proc.new {|x,y| 1}.arity) assert_equal(-1, Proc.new{|*x| 1}.arity) end def f; yield; end def test_yield_with_zero_arity f {|*a| assert(a == []) } end class A def foo yield end end class B < A def foo super end end def test_block_passed_to_super assert_equal("bar", B.new.foo { "bar" }) end # test blocks being available to procs (JRUBY-91) class Baz def foo bar do qux end end def bar(&block) block.call end def qux if block_given? return false end return true end end def test_block_available_to_proc assert(Baz.new.foo { }) end # test instance_evaling with more complicated block passing (JRUBY-88) $results = [] class C def t(&block) if block instance_eval &block end end def method_missing(sym, *args, &block) $results << "C: #{sym} #{!block}" if sym == :b return D.new { |block| t(&block) } end t(&block) end end class D def initialize(&blk) @blk = blk end def method_missing(sym, *args, &block) $results << "D: #{sym} #{!block}" @blk.call(block) end end def do_it(&blk) C.new.b.c { a 'hello' } end def test_block_passing_with_instance_eval do_it { } assert_equal(["C: b true", "D: c false", "C: a true"], $results) end if defined? instance_exec def test_instance_exec_self o = Object.new assert_equal(o, o.instance_exec { self }) end def test_instance_exec_self_args o = Object.new assert_equal(o, o.instance_exec(1) { self }) end def test_instance_exec_args_result o = Object.new assert_equal(2, o.instance_exec(1) { |x| x + 1 }) end def test_instance_exec_args_multiple_result o = Object.new assert_equal([1, 3], o.instance_exec(1, 2, 3) { |a, b, c| [a, c] }) end def test_instance_exec_no_block o = Object.new assert_raise(ArgumentError) { o.instance_exec } end def test_instance_exec_no_block_args o = Object.new assert_raise(ArgumentError) { o.instance_exec(1) } end end # if defined? instance_exec # ensure proc-ified blocks can be yielded to when no block arg is specified in declaration class Holder def call_block yield end end class Creator def create_block proc do yield end end end def test_block_converted_to_proc_yields block = Creator.new.create_block { "here" } assert_nothing_raised {Holder.new.call_block(&block)} assert_equal("here", Holder.new.call_block(&block)) end def proc_call(&b) b.call end def proc_return1 proc_call{return 42}+1 end def proc_return2 puts proc_call{return 42}+1 end def test_proc_or_block_return assert_nothing_raised { assert_equal 42, proc_return1 } assert_nothing_raised { assert_equal 42, proc_return2 } end def bar(a, b) yield a, b end def test_block_hash_args h = Hash.new bar(1, 2) { |h[:v], h[:u]| } puts h[:v], h[:u] end def block_arg_that_breaks_while(&block) while true block.call end end def block_that_breaks_while while true yield end end def test_block_arg_that_breaks_while assert_nothing_raised { block_arg_that_breaks_while { break }} end def test_block_that_breaks_while assert_nothing_raised { block_that_breaks_while { break }} end def yield_arg(arg) yield arg end def block_call_arg(arg,&block) block.call arg end def test_yield_arg_expansion assert_equal 1, yield_arg([1,2]) { |a,b| a } assert_equal 1, block_call_arg([1,2]) { |a,b| a } end end