minstrel 0.1.20101115013901

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.textile +76 -0
  2. data/lib/minstrel.rb +68 -0
  3. data/minstrel.gemspec +21 -0
  4. 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
+