rallhook 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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