rallhook 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/AUTHORS +3 -0
  2. data/CHANGELOG +82 -0
  3. data/README +207 -0
  4. data/Rakefile +49 -0
  5. data/TODO +8 -0
  6. data/examples/hook/example1.rb +19 -0
  7. data/examples/hook/example2.rb +30 -0
  8. data/examples/hook/example3.rb +24 -0
  9. data/examples/hook/example4.rb +18 -0
  10. data/examples/hook/intercept.rb +41 -0
  11. data/examples/hook/intercept2.rb +49 -0
  12. data/examples/hook/redirect.rb +55 -0
  13. data/examples/hook/redirect_inherited.rb +28 -0
  14. data/examples/hook/shadow.rb +44 -0
  15. data/examples/instrospection/main.rb +13 -0
  16. data/examples/instrospection/source1.rb +4 -0
  17. data/examples/instrospection/source2.rb +4 -0
  18. data/ext/rallhook_base/distorm.h +401 -0
  19. data/ext/rallhook_base/extconf.rb +21 -0
  20. data/ext/rallhook_base/hook.c +165 -0
  21. data/ext/rallhook_base/hook.h +30 -0
  22. data/ext/rallhook_base/hook_rb_call.c +88 -0
  23. data/ext/rallhook_base/hook_rb_call.h +33 -0
  24. data/ext/rallhook_base/method_node.c +212 -0
  25. data/ext/rallhook_base/method_node.h +27 -0
  26. data/ext/rallhook_base/node_defs.h +294 -0
  27. data/ext/rallhook_base/rallhook.c +396 -0
  28. data/ext/rallhook_base/rb_call_fake.c +398 -0
  29. data/ext/rallhook_base/rb_call_fake.h +138 -0
  30. data/ext/rallhook_base/restrict_def.c +176 -0
  31. data/ext/rallhook_base/restrict_def.h +37 -0
  32. data/ext/rallhook_base/ruby_redirect.c +122 -0
  33. data/ext/rallhook_base/ruby_redirect.h +33 -0
  34. data/ext/rallhook_base/ruby_symbols.c +43 -0
  35. data/ext/rallhook_base/ruby_symbols.h +28 -0
  36. data/ext/rallhook_base/ruby_version.h +21 -0
  37. data/lib/rallhook/thread_hook.rb +37 -0
  38. data/lib/rallhook.rb +384 -0
  39. data/test/basic_proc.rb +45 -0
  40. data/test/integrity/test_array.rb +42 -0
  41. data/test/integrity/test_binding.rb +26 -0
  42. data/test/integrity/test_block.rb +37 -0
  43. data/test/integrity/test_call.rb +1 -0
  44. data/test/integrity/test_class_methods.rb +1 -0
  45. data/test/integrity/test_exception.rb +1 -0
  46. data/test/integrity/test_super.rb +34 -0
  47. data/test/introspection/test_call.rb +29 -0
  48. data/test/introspection/test_class_method.rb +41 -0
  49. data/test/introspection/test_file.rb +15 -0
  50. metadata +113 -0
data/AUTHORS ADDED
@@ -0,0 +1,3 @@
1
+ rallhook de tario <rseminara@hotmail.com>
2
+
3
+
data/CHANGELOG ADDED
@@ -0,0 +1,82 @@
1
+ 0.7.0 Concurrency support, any thread can hook without affect the hook state of the other threads
2
+
3
+ Restrictions about overwrite instance methods disabled
4
+
5
+ Added class shadows to confine the behaviour added throught methods to hook state
6
+
7
+ Implemented UboundMethod#unchecked_bind to bind methods of different classes
8
+
9
+ 0.6.1 Fixed bug on binding of class methods in Object#specific_method
10
+
11
+ 0.6.0 Implemented method UboundMethod#body
12
+
13
+ Improved compatibility of test cases with ruby1.9 and ruby1.8 behaviour
14
+
15
+ Implemented Object#specific_method to lookup methods by klass and method_id
16
+
17
+ Delete overload of Object#method
18
+
19
+ 0.5.0 Security Improved: Restricted define of singleton methods over classes when hook is enabled
20
+
21
+ Added special check for Object#binding to avoid change the binding behaviour with method redirection
22
+
23
+ Security improved: Added hook of rb_add_method to avoid the overwriting of any method
24
+
25
+ Security improved: Fixed leaks of hooking methods by making all methods called over Hook illegal if hook state is enabled
26
+
27
+ More helpers to make easier to use. (see MethodHandler class)
28
+
29
+ Documented methods and classes to generate useful RDoc
30
+
31
+ Internal refactoring to split the logic of rallhook, hooking, method_handle invoke, etc... and the modification of the ruby interpreter with hook calls, etc...
32
+
33
+ 0.4.1 Fixed bug in the hook module
34
+
35
+ 0.4.0 Fixed bug in the version numbering
36
+
37
+ 0.3.1 Added new method of intercept calls
38
+
39
+ Changed interface of handlling of methods (see README and examples) to avoid errors in the handling of yield functions in ruby1.8
40
+
41
+ New internal method of hook fixe many many bugs
42
+
43
+ Fixed fastcall convention calls in i386, hooks and detection of calling convention
44
+
45
+ Fixed compatibility issues with ruby1.8 and ruby1.9 in i386
46
+
47
+ Rakefile configured to build extensions automatically at gem install
48
+
49
+ 0.3.0: Compatibility with ruby1.8 on i386 (tested with ruby 1.8.6 patchlevel 111 in ubuntu 8.04)
50
+
51
+ Compatibility with ruby1.9 on i386 (tested with ruby 1.9.0 in ubuntu 8.04)
52
+
53
+ Compatiblity with ruby1.8 on x86_64 (tested with ruby 1.8.7 patchlevel 72 in ubuntu 9.04)
54
+
55
+ Compatibility with ruby1.9 on x86_64 (tested with ruby 1.9.0 r17482 in ubuntu 9.04)
56
+
57
+ New method introspection features (see README for examples)
58
+
59
+
60
+ 0.2.1: Fixed issue #3: corrupted block arguments in hooking ( http://github.com/tario/rallhook/issues/issue/3 )
61
+
62
+ Added testcase to test the issue #3
63
+
64
+ Added some automatic tests of integrity of the modified interpreter
65
+
66
+ 0.2.0: Fixed RAII issues in RallHook::hook method
67
+
68
+ Changed version of package to 0.2.0 to avoid "malformed" version number
69
+
70
+ 0.2.0-rc1: Added "TagContainer trick" to fix the issue #2: undesirable nest at super call with block ( http://github.com/tario/rallhook/issues/issue/2 )
71
+
72
+ Added klass parameter to hooked_send, fixing the issue #1: undesirable nest at super call ( http://github.com/tario/rallhook/issues/issue/1 )
73
+
74
+ Added classes and methods to read method body info as the file and line where that method was defined
75
+ obj.method(:foo).body.file
76
+ obj.method(:foo).body.line
77
+
78
+
79
+ 0.1.1: Changed hooking and unhooking mechanism in the call of the handler of hooks
80
+ to make it internal at rallhooking (calling of hook and unhook from the call method are unnecesary now)
81
+
82
+ 0.1.0: implemented basic hooking as PoC of rallhook, basic example works fine
data/README ADDED
@@ -0,0 +1,207 @@
1
+ = rallhook - An ruby absolute method hooker
2
+
3
+ This package contains rallhook, a ruby C extension to intercept ruby methods calls at interpreter level in a transparent way from ruby itself.
4
+
5
+ == Installation
6
+
7
+ === Prerequisites
8
+
9
+ * ruby-cymbol >= 0.1.0 (found at http://github.com/tario/ruby-cymbol)
10
+ * ruby debug info ( apt-get install libruby1.8-dbg or libruby1.9-dbg on debian based systems)
11
+ * ruby development package ( apt-get install ruby1.8-dev or ruby1.9-dev on debian based systems)
12
+ * objdump
13
+ * distorm ( found at https://code.google.com/p/distorm/ )
14
+
15
+
16
+ === Gem installation
17
+
18
+ * Download the last version of the gem from http://github.com/tario/ruby-cpp/downloads
19
+ * Install the gem with the following;
20
+
21
+ gem install rallhook-X.X.X.gem
22
+
23
+ == Usage
24
+
25
+ === Basic Example
26
+
27
+ test.rb:
28
+
29
+ require "rubygems"
30
+ require "rallhook"
31
+
32
+ include RallHook
33
+
34
+ class MethodHandler < HookHandler
35
+
36
+ def handle_method (klass,self_,m, method_id)
37
+
38
+ # print to the standar output details about the method called
39
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class} \n"
40
+ nil # do nothing
41
+ end
42
+ end
43
+
44
+ MethodHandler.hook do
45
+ # all ruby calls in this block are intercepted by hook_recv::call
46
+
47
+ [1,2,3].each do |x|
48
+ print x,"\n"
49
+ end
50
+
51
+ end
52
+
53
+ standard output:
54
+
55
+ method call each:4001 over 123:Array
56
+ method call print:7697 over main:Object
57
+ method call write:7649 over #<IO:0x7fb15e54fad0>:IO
58
+ method call to_s:3137 over 1:Fixnum
59
+ 1method call write:7649 over #<IO:0x7fb15e54fad0>:IO
60
+
61
+ method call print:7697 over main:Object
62
+ method call write:7649 over #<IO:0x7fb15e54fad0>:IO
63
+ method call to_s:3137 over 2:Fixnum
64
+ 2method call write:7649 over #<IO:0x7fb15e54fad0>:IO
65
+
66
+ method call print:7697 over main:Object
67
+ method call write:7649 over #<IO:0x7fb15e54fad0>:IO
68
+ method call to_s:3137 over 3:Fixnum
69
+ 3method call write:7649 over #<IO:0x7fb15e54fad0>:IO
70
+
71
+ === Redirecting calls
72
+
73
+ require "rubygems"
74
+ require "rallhook"
75
+
76
+ include RallHook
77
+
78
+ class MethodHandler < HookHandler
79
+ include RallHook::Helper
80
+
81
+ def handle_method (klass,recv,m,method_id)
82
+
83
+ if m == :foo
84
+ # redirects the calls of method foo to method bar on the same object
85
+ return redirect_call(klass,recv, :bar)
86
+ end
87
+
88
+ if m == :bar
89
+ # redirects the calls of method bar to method bar on the method_handler
90
+ return redirect_call(self.class,self, :bar)
91
+ end
92
+
93
+ nil # do nothing
94
+ end
95
+
96
+ def bar
97
+ print "bar in MethodHandler\n"
98
+ end
99
+ end
100
+
101
+ class X
102
+ def foo
103
+ print "foo in X\n"
104
+ end
105
+ def bar
106
+ print "bar in X\n"
107
+ end
108
+ end
109
+
110
+ print "WITHOUT HOOK:\n"
111
+
112
+ x = X.new
113
+ x.foo
114
+ x.bar
115
+
116
+ print "WITH HOOK:\n"
117
+
118
+ MethodHandler.hook do
119
+ # all ruby calls in this block are intercepted by hook_recv::call
120
+ x = X.new
121
+ x.foo # redirected to X#bar
122
+ x.bar # redirected to MethodHandler#bar
123
+
124
+ end
125
+
126
+ === Wrap Calls
127
+ require "rubygems"
128
+ require "rallhook"
129
+
130
+ include RallHook
131
+
132
+ class MethodHandler < HookHandler
133
+ include RallHook::Helper
134
+
135
+ class FooMethodWrapper < MethodWrapper
136
+ def call(*x)
137
+ # call with reyield if block_given
138
+ if block_given?
139
+ original_call(*x) do |*a|
140
+ yield(*a)
141
+ end
142
+ # add "�bar?"
143
+ yield("bar?")
144
+ else
145
+ original_call(*x)
146
+ end
147
+ end
148
+ end
149
+
150
+ def handle_method (klass,recv,m,method_id)
151
+ if m == :each
152
+ return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
153
+ end
154
+ nil # do nothing
155
+ end
156
+ end
157
+
158
+ print "calling Array#each without hook\n"
159
+ [1,2,3,4].each do |x|
160
+ print x.inspect, " "
161
+ end
162
+ print "\n"
163
+
164
+ print "calling Array#each WITH hook\n"
165
+ MethodHandler.hook do
166
+
167
+ # 1 2 3 4 "bar?"
168
+ [1,2,3,4].each do |x|
169
+ print x.inspect," "
170
+ end
171
+ print "\n"
172
+
173
+ end
174
+
175
+
176
+ === Method Instrospection new features example
177
+
178
+ source1.rb
179
+
180
+ class X
181
+ def foo
182
+ end
183
+ end
184
+
185
+ source2.rb
186
+
187
+ class Y < X
188
+ def foo
189
+ end
190
+ end
191
+
192
+ main.rb
193
+
194
+ require "rallhook"
195
+ require "source1.rb"
196
+ require "source2.rb"
197
+
198
+ x = X.new
199
+ y = Y.new
200
+
201
+ print x.method(:foo).body.file,"\n" # source1.rb
202
+ print y.method(:foo).body.file,"\n" # source2.rb
203
+
204
+ print y.method(X,:foo).body.file,"\n" # source1.rb
205
+ print y.method(Y,:foo).body.file,"\n" # source2.rb
206
+
207
+
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+
7
+ spec = Gem::Specification.new do |s|
8
+ s.name = 'rallhook'
9
+ s.version = '0.7.0'
10
+ s.author = 'Dario Seminara'
11
+ s.email = 'robertodarioseminara@gmail.com'
12
+ s.platform = Gem::Platform::RUBY
13
+ s.summary = 'Allow hooking of all method invocations transparently to control and / or monitor the behavior of a ruby program'
14
+ s.homepage = "http://github.com/tario/rallhook"
15
+ s.has_rdoc = true
16
+ s.add_dependency "ruby-cymbol", ">= 0.1.0"
17
+ s.extra_rdoc_files = [ 'README' ]
18
+ s.rdoc_options << '--main' << 'README'
19
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
20
+ s.files = Dir.glob("{examples,lib,test}/**/*.rb") + Dir.glob("ext/**/*.c") + Dir.glob("ext/**/*.h") + Dir.glob("ext/**/extconf.rb") +
21
+ [ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
22
+ end
23
+
24
+ desc 'Run tests'
25
+ task :default => [ :test ]
26
+
27
+ Rake::TestTask.new('test') do |t|
28
+ t.libs << 'test'
29
+ t.pattern = '{test}/**/test_*.rb'
30
+ t.verbose = true
31
+ end
32
+
33
+ desc 'Generate RDoc'
34
+ Rake::RDocTask.new :rdoc do |rd|
35
+ rd.rdoc_dir = 'doc'
36
+ rd.rdoc_files.add 'lib', 'ext', 'README'
37
+ rd.main = 'README'
38
+ end
39
+
40
+ desc 'Build Gem'
41
+ Rake::GemPackageTask.new spec do |pkg|
42
+ pkg.need_tar = true
43
+ end
44
+
45
+ desc 'Clean up'
46
+ task :clean => [ :clobber_rdoc, :clobber_package ]
47
+
48
+ desc 'Clean up'
49
+ task :clobber => [ :clean ]
data/TODO ADDED
@@ -0,0 +1,8 @@
1
+ * Threading support
2
+ * Tests cases for 1.0.0 interface
3
+ * More integrity testcases (with use of ruby core methods)
4
+ * Security testcases (hook bypass checks, security tests)
5
+ * Win32 compatibility
6
+ * Delete distorm dependency
7
+ * Delete libruby debuginfo dependency
8
+ * Make rallhook functionality transparent (backtraces, exceptions, etc ...)
@@ -0,0 +1,19 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class HookProc
7
+ def handle_method (klass,self_,m,method_id)
8
+
9
+ # print to the standard output details about the method called
10
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
11
+ nil # do nothing
12
+ end
13
+ end
14
+
15
+ hook_proc = HookProc.new
16
+ Hook.hook hook_proc do
17
+ print 2+2,"\n"
18
+ print [1,2,3].inject{|x,y| x+y},"\n"
19
+ end
@@ -0,0 +1,30 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class HookProc
7
+ def handle_method (klass,self_,m,method_id)
8
+
9
+ # print to the standard output details about the method called
10
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
11
+ nil # do nothing
12
+ end
13
+ end
14
+
15
+ class X
16
+ def foo
17
+ end
18
+ end
19
+
20
+ class Y <X
21
+ def foo
22
+ super
23
+ end
24
+ end
25
+
26
+ hook_proc = HookProc.new
27
+ Hook.hook hook_proc do
28
+ y = Y.new
29
+ y.foo
30
+ end
@@ -0,0 +1,24 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler
7
+ def handle_method (klass,self_,m,method_id)
8
+
9
+ # print to the standard output details about the method called
10
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
11
+ nil # do nothing
12
+ end
13
+ end
14
+
15
+ mhandler = MethodHandler.new
16
+
17
+ Hook.hook mhandler do
18
+ # all ruby calls in this block are intercepted by hook_recv::call
19
+
20
+ [1,2,3].each do |x|
21
+ print x,"\n"
22
+ end
23
+
24
+ end
@@ -0,0 +1,18 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler < RallHook::HookHandler
7
+ def handle_method (klass,self_,m,method_id)
8
+
9
+ # print to the standard output details about the method called
10
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
11
+ nil # do nothing
12
+ end
13
+ end
14
+
15
+ MethodHandler.hook do
16
+ print 2+2,"\n"
17
+ print [1,2,3].inject{|x,y| x+y},"\n"
18
+ end
@@ -0,0 +1,41 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler
7
+ include RallHook::Helper
8
+
9
+ class FooMethodWrapper < MethodWrapper
10
+ def call(a)
11
+ # replace the a parameter with a+5
12
+ original_call(a+5)
13
+ end
14
+ end
15
+
16
+ def handle_method (klass,recv,m, method_id)
17
+
18
+ if m == :foo
19
+ return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
20
+ end
21
+
22
+ nil # do nothing
23
+ end
24
+
25
+ end
26
+
27
+ class X
28
+ def foo(a)
29
+ print "foo in X with a = #{a}\n"
30
+ end
31
+ end
32
+ x = X.new
33
+ print "calling X#foo without hook\n"
34
+ x.foo 4 # "foo in X with a = 4"
35
+
36
+ print "calling X#foo WITH hook\n"
37
+ mhandler = MethodHandler.new
38
+ Hook.hook mhandler do
39
+ x.foo 4 # "foo in X with a = 9" :)
40
+ end
41
+
@@ -0,0 +1,49 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler
7
+ include RallHook::Helper
8
+
9
+ class FooMethodWrapper < MethodWrapper
10
+ def call(*x)
11
+ # call with reyield if block_given
12
+ if block_given?
13
+ original_call(*x) do |*a|
14
+ yield(*a)
15
+ end
16
+ # add "�bar?"
17
+ yield("bar?")
18
+ else
19
+ original_call(*x)
20
+ end
21
+ end
22
+ end
23
+
24
+ def handle_method (klass,recv,m,method_id)
25
+ if m == :each
26
+ return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
27
+ end
28
+ nil # do nothing
29
+ end
30
+ end
31
+
32
+ print "calling Array#each without hook\n"
33
+ [1,2,3,4].each do |x|
34
+ print x.inspect, " "
35
+ end
36
+ print "\n"
37
+
38
+ print "calling Array#each WITH hook\n"
39
+ mhandler = MethodHandler.new
40
+ Hook.hook mhandler do
41
+
42
+ # 1 2 3 4 "bar?"
43
+ [1,2,3,4].each do |x|
44
+ print x.inspect," "
45
+ end
46
+ print "\n"
47
+
48
+ end
49
+
@@ -0,0 +1,55 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler
7
+ include RallHook::Helper
8
+
9
+ def handle_method (klass,recv,m,method_id)
10
+
11
+ if m == :foo
12
+ # redirects the calls of method foo to method bar on the same object
13
+ return redirect_call(klass,recv, :bar)
14
+ end
15
+
16
+ if m == :bar
17
+ # redirects the calls of method bar to method bar on the method_handler
18
+ return redirect_call(self.class,self, :bar)
19
+ end
20
+
21
+ nil # do nothing
22
+ end
23
+
24
+ def bar
25
+ print "bar in MethodHandler\n"
26
+ end
27
+ end
28
+
29
+ class X
30
+ def foo
31
+ print "foo in X\n"
32
+ end
33
+ def bar
34
+ print "bar in X\n"
35
+ end
36
+ end
37
+
38
+ mhandler = MethodHandler.new
39
+
40
+ print "WITHOUT HOOK:\n"
41
+
42
+ x = X.new
43
+ x.foo
44
+ x.bar
45
+
46
+ print "WITH HOOK:\n"
47
+
48
+ Hook.hook mhandler do
49
+ # all ruby calls in this block are intercepted by hook_recv::call
50
+ x = X.new
51
+ x.foo # redirected to X#bar
52
+ x.bar # redirected to MethodHandler#bar
53
+
54
+ end
55
+
@@ -0,0 +1,28 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler
7
+ include RallHook::Helper
8
+
9
+ def handle_method (klass,recv,m,method_id)
10
+
11
+ print "called method #{m} over #{recv}\n"
12
+
13
+ if m == :inherited
14
+ return redirect_call(klass,recv,:ssss)
15
+ end
16
+
17
+ nil # do nothing
18
+ end
19
+ end
20
+
21
+ mhandler = MethodHandler.new
22
+ Hook.hook mhandler do
23
+ # all ruby calls in this block are intercepted by hook_recv::call
24
+ class N
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,44 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+
4
+ include RallHook
5
+
6
+ class MethodHandler < RallHook::HookHandler
7
+ def handle_method (klass,self_,m,method_id)
8
+ # print to the standard output details about the method called
9
+ print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
10
+ nil # do nothing
11
+ end
12
+ end
13
+
14
+ class X
15
+ def foo
16
+ print "outside of hook foo\n"
17
+ end
18
+ end
19
+
20
+ x = X.new
21
+
22
+ x.foo
23
+
24
+ MethodHandler.hook do
25
+ class X
26
+ def foo
27
+ print "inside of hook foo\n"
28
+ end
29
+
30
+ def bar
31
+ print "inside of hook bar\n"
32
+ end
33
+ end
34
+
35
+ x.foo
36
+ x.bar
37
+ end
38
+
39
+ x.foo
40
+ begin
41
+ x.bar # NoMethodError
42
+ rescue NoMethodError
43
+ print "there is no method bar in X outside the hook\n"
44
+ end
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ require "rallhook"
3
+ require "source1.rb"
4
+ require "source2.rb"
5
+
6
+ x = X.new
7
+ y = Y.new
8
+
9
+ print "definition of method :foo in #{x}: ", x.method(:foo).body.file,"\n" # source1.rb
10
+ print "definition of method :foo in #{y}: ", y.method(:foo).body.file,"\n" # source2.rb
11
+
12
+ print "definition of method :foo of class X in object #{y}: ", y.method(X,:foo).body.file,"\n" # source1.rb
13
+ print "definition of method :foo of class Y in object #{y}: ", y.method(Y,:foo).body.file,"\n" # source1.rb
@@ -0,0 +1,4 @@
1
+ class X
2
+ def foo
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ class Y < X
2
+ def foo
3
+ end
4
+ end