minstrel 0.1.20101115013901
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 +76 -0
- data/lib/minstrel.rb +68 -0
- data/minstrel.gemspec +21 -0
- metadata +70 -0
data/README.textile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
h1. Ruby Minstrel
|
2
|
+
|
3
|
+
Minstrel allows you to wrap every method call for a given class so you can more
|
4
|
+
easily observe how a class and its methods are being used.
|
5
|
+
|
6
|
+
h2. Why?
|
7
|
+
|
8
|
+
Fun. Also, sometimes ruby-prof and similar tools are overkill when I am trying
|
9
|
+
to debug or dig into how a piece of code works.
|
10
|
+
|
11
|
+
h2. Examples
|
12
|
+
|
13
|
+
h3. From the commandline
|
14
|
+
|
15
|
+
You can use minstrel to wrap classes with a default 'print' wrapper that simply
|
16
|
+
prints what is called. For example:
|
17
|
+
|
18
|
+
<pre>
|
19
|
+
% RUBY_INSTRUMENT=String ruby -rminstrel -e 'puts "hello world".capitalize.reverse'
|
20
|
+
String#capitalize([])
|
21
|
+
String#reverse([])
|
22
|
+
dlrow olleH
|
23
|
+
</pre>
|
24
|
+
|
25
|
+
h3. From ruby
|
26
|
+
|
27
|
+
Boilerplate:
|
28
|
+
|
29
|
+
<pre>
|
30
|
+
require "minstrel"
|
31
|
+
|
32
|
+
instrument = Minstrel::Instrument.new()
|
33
|
+
instrument.wrap(String) do |point, klass, method, *args|
|
34
|
+
# * point is either :enter or :exit depending if this function is about to be
|
35
|
+
# called or has finished being called.
|
36
|
+
# * klass is the class object (String, etc)
|
37
|
+
# * method is the method (a Symbol)
|
38
|
+
# * *args is the arguments passed
|
39
|
+
end
|
40
|
+
</pre>
|
41
|
+
|
42
|
+
Example:
|
43
|
+
|
44
|
+
<pre>
|
45
|
+
require "minstrel"
|
46
|
+
|
47
|
+
class Foo
|
48
|
+
def bar(one, &block)
|
49
|
+
yield one
|
50
|
+
end
|
51
|
+
|
52
|
+
def baz
|
53
|
+
puts "Baz!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
instrument = Minstrel::Instrument.new
|
58
|
+
instrument.wrap(Foo) do |point, klass, method, *args|
|
59
|
+
puts "#{point} #{klass.name}##{method}(#{args.inspect})"
|
60
|
+
end
|
61
|
+
|
62
|
+
foo = Foo.new
|
63
|
+
foo.bar(123) { |arg| puts arg }
|
64
|
+
foo.baz
|
65
|
+
</pre>
|
66
|
+
|
67
|
+
Output:
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
enter Foo#bar([123])
|
71
|
+
123
|
72
|
+
exit Foo#bar([123])
|
73
|
+
enter Foo#baz([])
|
74
|
+
Baz!
|
75
|
+
exit Foo#baz([])
|
76
|
+
</pre>
|
data/lib/minstrel.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Wrap method calls for a class of your choosing.
|
2
|
+
# Example:
|
3
|
+
# instrument = Minstrel::Instrument.new()
|
4
|
+
# instrument.wrap(String) do |point, klass, method, *args|
|
5
|
+
# ...
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# * point is either :enter or :exit depending if this function is about to be
|
9
|
+
# called or has finished being called.
|
10
|
+
# * klass is the class object (String, etc)
|
11
|
+
# * method is the method (a Symbol)
|
12
|
+
# * *args is the arguments passed
|
13
|
+
#
|
14
|
+
# You can also wrap from the command-line
|
15
|
+
#
|
16
|
+
# RUBY_INSTRUMENT=comma_separated_classnames ruby -rminstrel ./your/program.rb
|
17
|
+
#
|
18
|
+
module Minstrel; class Instrument
|
19
|
+
attr_accessor :counter
|
20
|
+
|
21
|
+
# Put methods we must not be wrapping here.
|
22
|
+
DONOTWRAP = [Kernel, Object, Module, Class, Minstrel::Instrument].collect do |obj|
|
23
|
+
obj.methods.collect { |m| m.to_sym }
|
24
|
+
end.flatten
|
25
|
+
DONOTWRAP << :to_sym
|
26
|
+
|
27
|
+
# Wrap a class's instance methods with your block.
|
28
|
+
# The block will be called with 4 arguments, and called
|
29
|
+
# before and after the original method.
|
30
|
+
# Arguments:
|
31
|
+
# * point - the point (symbol, :entry or :exit) of call
|
32
|
+
# * klass - the class (object) owning this method
|
33
|
+
# * method - the method (symbol) being called
|
34
|
+
# * *args - the arguments (array) passed to this method.
|
35
|
+
def wrap(klass, &block)
|
36
|
+
instrumenter = self
|
37
|
+
self.counter = 0
|
38
|
+
|
39
|
+
klass.instance_methods.each do |method|
|
40
|
+
next if DONOTWRAP.include?(method.to_sym)
|
41
|
+
klass.class_eval do
|
42
|
+
orig_method = "#{method}_original(wrapped)".to_sym
|
43
|
+
alias_method orig_method, method.to_sym
|
44
|
+
instrumenter.counter += 1
|
45
|
+
method = method.to_sym
|
46
|
+
define_method(method) do |*args, &argblock|
|
47
|
+
block.call(:enter, klass, method, *args)
|
48
|
+
val = send(orig_method, *args, &argblock)
|
49
|
+
block.call(:exit, klass, method, *args)
|
50
|
+
return val
|
51
|
+
end
|
52
|
+
end # klass.class_eval
|
53
|
+
end # klass.instance_methods.each
|
54
|
+
end # def wrap
|
55
|
+
end; end # class Minstrel::Instrument
|
56
|
+
|
57
|
+
# Provide a way to instrument a class using the command line:
|
58
|
+
# RUBY_INSTRUMENT=String ruby -rminstrel ./your/program
|
59
|
+
if ENV["RUBY_INSTRUMENT"]
|
60
|
+
ENV["RUBY_INSTRUMENT"].split(",").each do |klassname|
|
61
|
+
instrument = Minstrel::Instrument.new
|
62
|
+
klass = eval(klassname)
|
63
|
+
instrument.wrap(klass) do |point, klass, method, *args|
|
64
|
+
next if point == :end
|
65
|
+
puts "#{point} #{klass.name}##{method}(#{args.inspect})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/minstrel.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
files = [
|
3
|
+
"./lib",
|
4
|
+
"./lib/minstrel.rb",
|
5
|
+
"./README.textile",
|
6
|
+
"./minstrel.gemspec",
|
7
|
+
]
|
8
|
+
|
9
|
+
rev = Time.now.strftime("%Y%m%d%H%M%S")
|
10
|
+
spec.name = "minstrel"
|
11
|
+
spec.version = "0.1.#{rev}"
|
12
|
+
spec.summary = "minstrel - a ruby instrumentation tool"
|
13
|
+
spec.description = "Instrument class methods"
|
14
|
+
spec.files = files
|
15
|
+
spec.require_paths << "lib"
|
16
|
+
|
17
|
+
spec.author = "Jordan Sissel"
|
18
|
+
spec.email = "jls@semicomplete.com"
|
19
|
+
spec.homepage = "https://github.com/jordansissel/ruby-minstrel"
|
20
|
+
end
|
21
|
+
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: minstrel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 40202230027777
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 20101115013901
|
10
|
+
version: 0.1.20101115013901
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jordan Sissel
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-15 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Instrument class methods
|
23
|
+
email: jls@semicomplete.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- ./lib/minstrel.rb
|
32
|
+
- ./README.textile
|
33
|
+
- ./minstrel.gemspec
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: https://github.com/jordansissel/ruby-minstrel
|
36
|
+
licenses: []
|
37
|
+
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 3
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.7
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: minstrel - a ruby instrumentation tool
|
69
|
+
test_files: []
|
70
|
+
|