minstrel 0.1.20101115013901 → 0.2.20101115030455
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.
- data/README.textile +8 -0
- data/bin/minstrel +6 -0
- data/lib/minstrel.rb +98 -8
- data/minstrel.gemspec +3 -1
- metadata +7 -6
data/README.textile
CHANGED
@@ -3,11 +3,19 @@ h1. Ruby Minstrel
|
|
3
3
|
Minstrel allows you to wrap every method call for a given class so you can more
|
4
4
|
easily observe how a class and its methods are being used.
|
5
5
|
|
6
|
+
h2. Get it
|
7
|
+
|
8
|
+
* gem install minstrel
|
9
|
+
* or download versions here: http://rubygems.org/gems/minstrel
|
10
|
+
* or github: https://github.com/jordansissel/ruby-minstrel
|
11
|
+
|
6
12
|
h2. Why?
|
7
13
|
|
8
14
|
Fun. Also, sometimes ruby-prof and similar tools are overkill when I am trying
|
9
15
|
to debug or dig into how a piece of code works.
|
10
16
|
|
17
|
+
It's a lot like strace/tcpdump/dtrace for ruby, or aims to be, anyway.
|
18
|
+
|
11
19
|
h2. Examples
|
12
20
|
|
13
21
|
h3. From the commandline
|
data/bin/minstrel
ADDED
data/lib/minstrel.rb
CHANGED
@@ -18,11 +18,18 @@
|
|
18
18
|
module Minstrel; class Instrument
|
19
19
|
attr_accessor :counter
|
20
20
|
|
21
|
+
class << self
|
22
|
+
@@deferred_wraps = {}
|
23
|
+
end
|
24
|
+
|
21
25
|
# Put methods we must not be wrapping here.
|
22
|
-
DONOTWRAP = [Kernel, Object, Module, Class,
|
26
|
+
#DONOTWRAP = #[Kernel, Object, Module, Class,
|
27
|
+
DONOTWRAP = [Minstrel::Instrument].collect do |obj|
|
23
28
|
obj.methods.collect { |m| m.to_sym }
|
24
29
|
end.flatten
|
25
30
|
DONOTWRAP << :to_sym
|
31
|
+
DONOTWRAP << :respond_to?
|
32
|
+
DONOTWRAP << :send
|
26
33
|
|
27
34
|
# Wrap a class's instance methods with your block.
|
28
35
|
# The block will be called with 4 arguments, and called
|
@@ -33,35 +40,118 @@ module Minstrel; class Instrument
|
|
33
40
|
# * method - the method (symbol) being called
|
34
41
|
# * *args - the arguments (array) passed to this method.
|
35
42
|
def wrap(klass, &block)
|
43
|
+
#puts "Instrumenting #{klass.name} with #{block.inspect}"
|
36
44
|
instrumenter = self
|
37
|
-
self.counter = 0
|
38
45
|
|
39
46
|
klass.instance_methods.each do |method|
|
40
47
|
next if DONOTWRAP.include?(method.to_sym)
|
41
48
|
klass.class_eval do
|
42
49
|
orig_method = "#{method}_original(wrapped)".to_sym
|
43
50
|
alias_method orig_method, method.to_sym
|
44
|
-
instrumenter.counter += 1
|
45
51
|
method = method.to_sym
|
52
|
+
#block.call(:wrap, klass, method)
|
46
53
|
define_method(method) do |*args, &argblock|
|
54
|
+
puts "call #{klass.name}##{method}(#{args.inspect}, #{block_given?})"
|
47
55
|
block.call(:enter, klass, method, *args)
|
48
|
-
|
49
|
-
|
56
|
+
exception = false
|
57
|
+
begin
|
58
|
+
m = self.method(orig_method)
|
59
|
+
val = m.call(*args, &argblock)
|
60
|
+
rescue => e
|
61
|
+
exception = e
|
62
|
+
end
|
63
|
+
if exception
|
64
|
+
block.call(:exit_exception, klass, method, *args)
|
65
|
+
raise e if exception
|
66
|
+
else
|
67
|
+
block.call(:exit, klass, method, *args)
|
68
|
+
end
|
50
69
|
return val
|
51
70
|
end
|
52
71
|
end # klass.class_eval
|
53
72
|
end # klass.instance_methods.each
|
73
|
+
|
74
|
+
klass.methods.each do |method|
|
75
|
+
next if DONOTWRAP.include?(method.to_sym)
|
76
|
+
klass.instance_eval do
|
77
|
+
orig_method = "#{method}_original(classwrapped)".to_sym
|
78
|
+
(class << self; self; end).instance_eval do
|
79
|
+
begin
|
80
|
+
alias_method orig_method, method.to_sym
|
81
|
+
rescue NameError => e
|
82
|
+
# No such method, strange but true.
|
83
|
+
orig_method = self.method(method.to_sym)
|
84
|
+
end
|
85
|
+
method = method.to_sym
|
86
|
+
define_method(method) do |*args, &argblock|
|
87
|
+
block.call(:class_enter, klass, method, *args)
|
88
|
+
exception = false
|
89
|
+
begin
|
90
|
+
if orig_method.is_a?(Symbol)
|
91
|
+
val = send(orig_method, *args, &argblock)
|
92
|
+
else
|
93
|
+
val = orig_method.call(*args, &argblock)
|
94
|
+
end
|
95
|
+
rescue => e
|
96
|
+
exception = e
|
97
|
+
end
|
98
|
+
if exception
|
99
|
+
block.call(:class_exit_exception, klass, method, *args)
|
100
|
+
raise e if exception
|
101
|
+
else
|
102
|
+
block.call(:class_exit, klass, method, *args)
|
103
|
+
end
|
104
|
+
return val
|
105
|
+
end
|
106
|
+
end
|
107
|
+
#block.call(:class_wrap, klass, method, self.method(method))
|
108
|
+
end # klass.class_eval
|
109
|
+
end # klass.instance_methods.each
|
54
110
|
end # def wrap
|
111
|
+
|
112
|
+
def wrap_classname(klassname, &block)
|
113
|
+
begin
|
114
|
+
klass = eval(klassname)
|
115
|
+
self.wrap(klass, &block)
|
116
|
+
return true
|
117
|
+
rescue NameError => e
|
118
|
+
@@deferred_wraps[klassname] = block
|
119
|
+
end
|
120
|
+
return false
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.wrap_require
|
124
|
+
Kernel.class_eval do
|
125
|
+
alias_method :old_require, :require
|
126
|
+
def require(*args)
|
127
|
+
return Minstrel::Instrument::instrumented_require(*args)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.instrumented_require(*args)
|
133
|
+
ret = old_require(*args)
|
134
|
+
klasses = @@deferred_wraps.keys
|
135
|
+
klasses.each do |klassname|
|
136
|
+
block = @@deferred_wraps[klassname]
|
137
|
+
instrument = Minstrel::Instrument.new
|
138
|
+
if instrument.wrap_classname(klassname, &block)
|
139
|
+
puts "Wrap of #{klassname} successful"
|
140
|
+
@@deferred_wraps.delete(klassname)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
return ret
|
144
|
+
end
|
55
145
|
end; end # class Minstrel::Instrument
|
56
146
|
|
147
|
+
Minstrel::Instrument.wrap_require
|
148
|
+
|
57
149
|
# Provide a way to instrument a class using the command line:
|
58
150
|
# RUBY_INSTRUMENT=String ruby -rminstrel ./your/program
|
59
151
|
if ENV["RUBY_INSTRUMENT"]
|
60
152
|
ENV["RUBY_INSTRUMENT"].split(",").each do |klassname|
|
61
153
|
instrument = Minstrel::Instrument.new
|
62
|
-
klass
|
63
|
-
instrument.wrap(klass) do |point, klass, method, *args|
|
64
|
-
next if point == :end
|
154
|
+
instrument.wrap_classname(klassname) do |point, klass, method, *args|
|
65
155
|
puts "#{point} #{klass.name}##{method}(#{args.inspect})"
|
66
156
|
end
|
67
157
|
end
|
data/minstrel.gemspec
CHANGED
@@ -8,11 +8,13 @@ Gem::Specification.new do |spec|
|
|
8
8
|
|
9
9
|
rev = Time.now.strftime("%Y%m%d%H%M%S")
|
10
10
|
spec.name = "minstrel"
|
11
|
-
spec.version = "0.
|
11
|
+
spec.version = "0.2.#{rev}"
|
12
12
|
spec.summary = "minstrel - a ruby instrumentation tool"
|
13
13
|
spec.description = "Instrument class methods"
|
14
14
|
spec.files = files
|
15
15
|
spec.require_paths << "lib"
|
16
|
+
spec.bindir = "bin"
|
17
|
+
spec.executables << "minstrel"
|
16
18
|
|
17
19
|
spec.author = "Jordan Sissel"
|
18
20
|
spec.email = "jls@semicomplete.com"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minstrel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 40202230060921
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 20101115030455
|
10
|
+
version: 0.2.20101115030455
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jordan Sissel
|
@@ -21,8 +21,8 @@ dependencies: []
|
|
21
21
|
|
22
22
|
description: Instrument class methods
|
23
23
|
email: jls@semicomplete.com
|
24
|
-
executables:
|
25
|
-
|
24
|
+
executables:
|
25
|
+
- minstrel
|
26
26
|
extensions: []
|
27
27
|
|
28
28
|
extra_rdoc_files: []
|
@@ -31,6 +31,7 @@ files:
|
|
31
31
|
- ./lib/minstrel.rb
|
32
32
|
- ./README.textile
|
33
33
|
- ./minstrel.gemspec
|
34
|
+
- bin/minstrel
|
34
35
|
has_rdoc: true
|
35
36
|
homepage: https://github.com/jordansissel/ruby-minstrel
|
36
37
|
licenses: []
|