mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Rewrite Kernel#tap with Ruby (#3281)
* Rewrite Kernel#tap with Ruby This was good for VM too, but of course my intention is to unblock JIT's inlining of a block over yield (inlining invokeyield has not been committed though). * Fix test_settracefunc About the :tap deletions, the :tap events are actually traced (we already have a TracePoint test for builtin methods), but it's filtered out by tp.path == "xyzzy" (it became "<internal:kernel>"). We could trace tp.path == "<internal:kernel>" cases too, but the lineno is impacted by kernel.rb changes and I didn't want to make it fragile for kernel.rb lineno changes.
This commit is contained in:
parent
e8010c7401
commit
f3a0d7a203
Notes:
git
2020-07-04 01:53:09 +09:00
Merged-By: k0kubun <takashikkbn@gmail.com>
4 changed files with 32 additions and 38 deletions
6
benchmark/kernel_tap.yml
Normal file
6
benchmark/kernel_tap.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
prelude: |
|
||||
obj = Object.new
|
||||
x = nil
|
||||
benchmark:
|
||||
kernel_tap: obj.tap { |o| x = o }
|
||||
loop_count: 20000000
|
22
kernel.rb
22
kernel.rb
|
@ -48,6 +48,28 @@ module Kernel
|
|||
Primitive.rb_obj_clone2(freeze)
|
||||
end
|
||||
|
||||
#
|
||||
# call-seq:
|
||||
# obj.tap {|x| block } -> obj
|
||||
#
|
||||
# Yields self to the block, and then returns self.
|
||||
# The primary purpose of this method is to "tap into" a method chain,
|
||||
# in order to perform operations on intermediate results within the chain.
|
||||
#
|
||||
# (1..10) .tap {|x| puts "original: #{x}" }
|
||||
# .to_a .tap {|x| puts "array: #{x}" }
|
||||
# .select {|x| x.even? } .tap {|x| puts "evens: #{x}" }
|
||||
# .map {|x| x*x } .tap {|x| puts "squares: #{x}" }
|
||||
#
|
||||
#--
|
||||
# \private
|
||||
#++
|
||||
#
|
||||
def tap
|
||||
yield(self)
|
||||
self
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
#
|
||||
|
|
26
object.c
26
object.c
|
@ -938,31 +938,6 @@ rb_class_search_ancestor(VALUE cl, VALUE c)
|
|||
return class_search_ancestor(cl, RCLASS_ORIGIN(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* call-seq:
|
||||
* obj.tap {|x| block } -> obj
|
||||
*
|
||||
* Yields self to the block, and then returns self.
|
||||
* The primary purpose of this method is to "tap into" a method chain,
|
||||
* in order to perform operations on intermediate results within the chain.
|
||||
*
|
||||
* (1..10) .tap {|x| puts "original: #{x}" }
|
||||
* .to_a .tap {|x| puts "array: #{x}" }
|
||||
* .select {|x| x.even? } .tap {|x| puts "evens: #{x}" }
|
||||
* .map {|x| x*x } .tap {|x| puts "squares: #{x}" }
|
||||
*
|
||||
*--
|
||||
* \private
|
||||
*++
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_obj_tap(VALUE obj)
|
||||
{
|
||||
rb_yield(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Document-method: inherited
|
||||
|
@ -4638,7 +4613,6 @@ InitVM_Object(void)
|
|||
rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1);
|
||||
rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1);
|
||||
rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1);
|
||||
rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0);
|
||||
|
||||
rb_define_global_function("sprintf", f_sprintf, -1);
|
||||
rb_define_global_function("format", f_sprintf, -1);
|
||||
|
|
|
@ -485,8 +485,6 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
[:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing],
|
||||
[:line, 4, 'xyzzy', self.class, method, self, nil, :nothing],
|
||||
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
|
||||
[:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing],
|
||||
[:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self],
|
||||
[:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1],
|
||||
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
|
||||
[:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing],
|
||||
|
@ -512,8 +510,6 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
[:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
|
||||
[:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
|
||||
[:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing],
|
||||
[:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing],
|
||||
[:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy],
|
||||
[:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy],
|
||||
[:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy],
|
||||
[:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
|
||||
|
@ -610,8 +606,6 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
[:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing],
|
||||
[:line, 4, 'xyzzy', self.class, method, self, nil, :nothing],
|
||||
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
|
||||
[:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing],
|
||||
[:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self],
|
||||
[:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1],
|
||||
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
|
||||
[:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing],
|
||||
|
@ -637,8 +631,6 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
[:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
|
||||
[:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing],
|
||||
[:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing],
|
||||
[:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing],
|
||||
[:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy],
|
||||
[:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy],
|
||||
[:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy],
|
||||
[:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing],
|
||||
|
@ -1685,7 +1677,7 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
TracePoint.new(:return, &capture_events).enable{
|
||||
o.alias_m
|
||||
}
|
||||
assert_equal [[:return, :m, :alias_m]], events
|
||||
assert_equal [[:return, :tap, :tap], [:return, :m, :alias_m]], events
|
||||
events.clear
|
||||
|
||||
o = Class.new{
|
||||
|
@ -1709,13 +1701,13 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
events.clear
|
||||
|
||||
o = Class.new{
|
||||
alias alias_tap tap
|
||||
define_method(:m){alias_tap{return}}
|
||||
alias alias_singleton_class singleton_class
|
||||
define_method(:m){alias_singleton_class}
|
||||
}.new
|
||||
TracePoint.new(:c_return, &capture_events).enable{
|
||||
o.m
|
||||
}
|
||||
assert_equal [[:c_return, :tap, :alias_tap]], events
|
||||
assert_equal [[:c_return, :singleton_class, :alias_singleton_class]], events
|
||||
events.clear
|
||||
|
||||
c = Class.new{
|
||||
|
|
Loading…
Reference in a new issue