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 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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ require "rubygems"
4
+ require "minstrel"
5
+
6
+ load ARGV[0]
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, Minstrel::Instrument].collect do |obj|
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
- val = send(orig_method, *args, &argblock)
49
- block.call(:exit, klass, method, *args)
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 = eval(klassname)
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.1.#{rev}"
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: 40202230027777
4
+ hash: 40202230060921
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 20101115013901
10
- version: 0.1.20101115013901
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: []