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.
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
+