instrumentation 0.8.0

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.
@@ -0,0 +1 @@
1
+ v0.8.0. Basic files
@@ -0,0 +1,7 @@
1
+ CHANGELOG
2
+ lib/instrument.rb
3
+ Manifest
4
+ Rakefile
5
+ README.rdoc
6
+ test/instrument_test.rb
7
+ test/test_helper.rb
@@ -0,0 +1,60 @@
1
+ = Instrument Library
2
+
3
+ == Description
4
+
5
+ Provides a simple API for instrumenting Ruby method invocations
6
+
7
+ == Features/Problems
8
+
9
+ Simply wraps methods, times invocations, and yields to the given handler.
10
+
11
+ == SYNOPSIS:
12
+
13
+ class Foo
14
+ def go
15
+ sleep(rand(10) / 10)
16
+ end
17
+ end
18
+
19
+ invocations = []
20
+ instrument 'Foo#go' do |obj, time, *args|
21
+ invocations << time
22
+ end
23
+
24
+ foo = Foo.new
25
+ 5.times { foo.go }
26
+ invocations.size # => 5
27
+ invocations.max # => the max time spent invoking Foo#go
28
+
29
+ == REQUIREMENTS:
30
+
31
+ * activesupport
32
+
33
+ == INSTALL:
34
+
35
+ * sudo gem install instrument
36
+
37
+ == LICENSE:
38
+
39
+ (The FiveRuns License)
40
+
41
+ Copyright (c) 2008 FiveRuns Corporation
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ 'Software'), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
58
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
59
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
60
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+
4
+ Echoe.new 'instrumentation' do |p|
5
+ # Note: Update version by adding a line to CHANGELOG
6
+ p.author = "FiveRuns Development Team"
7
+ p.test_files = Dir['test/**/*_test.rb']
8
+ p.email = 'dev@fiveruns.com'
9
+ p.project = 'fiveruns'
10
+ p.summary = "Provides a simple API for instrumenting Ruby method invocations."
11
+ p.url = "http://github.com/fiveruns/instrumentation"
12
+ p.dependencies = %w(activesupport)
13
+ p.include_rakefile = true
14
+ end
@@ -0,0 +1,46 @@
1
+
2
+ # Gem::Specification for Instrumentation-0.8.0
3
+ # Originally generated by Echoe
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{instrumentation}
7
+ s.version = "0.8.0"
8
+
9
+ s.specification_version = 2 if s.respond_to? :specification_version=
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.authors = ["FiveRuns Development Team"]
13
+ s.date = %q{2008-05-16}
14
+ s.description = %q{Provides a simple API for instrumenting Ruby method invocations.}
15
+ s.email = %q{dev@fiveruns.com}
16
+ s.extra_rdoc_files = ["CHANGELOG", "lib/instrument.rb", "README.rdoc"]
17
+ s.files = ["CHANGELOG", "lib/instrument.rb", "Manifest", "Rakefile", "README.rdoc", "test/instrument_test.rb", "test/test_helper.rb", "instrumentation.gemspec"]
18
+ s.has_rdoc = true
19
+ s.homepage = %q{http://github.com/fiveruns/instrumentation}
20
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Instrumentation", "--main", "README.rdoc"]
21
+ s.require_paths = ["lib"]
22
+ s.rubyforge_project = %q{fiveruns}
23
+ s.rubygems_version = %q{1.1.1}
24
+ s.summary = %q{Provides a simple API for instrumenting Ruby method invocations.}
25
+ s.test_files = ["test/instrument_test.rb", "test/test_helper.rb"]
26
+
27
+ s.add_dependency(%q<activesupport>, [">= 0"])
28
+ end
29
+
30
+
31
+ # # Original Rakefile source (requires the Echoe gem):
32
+ #
33
+ # require 'rubygems'
34
+ # require 'echoe'
35
+ #
36
+ # Echoe.new 'instrumentation' do |p|
37
+ # # Note: Update version by adding a line to CHANGELOG
38
+ # p.author = "FiveRuns Development Team"
39
+ # p.test_files = Dir['test/**/*_test.rb']
40
+ # p.email = 'dev@fiveruns.com'
41
+ # p.project = 'fiveruns'
42
+ # p.summary = "Provides a simple API for instrumenting Ruby method invocations."
43
+ # p.url = "http://github.com/fiveruns/instrumentation"
44
+ # p.dependencies = %w(activesupport)
45
+ # p.include_rakefile = true
46
+ # end
@@ -0,0 +1,74 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+
4
+ # call-seq:
5
+ # instrument("ClassName#instance_method", ...) { |instance, time, *args| ... }
6
+ # instrument("ClassName::class_method", ...) { |klass, time, *args| ... }
7
+ # instrument("ClassName.class_method", ...) { |klass, time, *args| ... }
8
+ #
9
+ # Add a handler to be called every time a method is invoked
10
+ def instrument(*raw_targets, &handler)
11
+ Instrument.add(*raw_targets, &handler)
12
+ end
13
+
14
+ module Instrument
15
+
16
+ class Error < ::NameError; end
17
+
18
+ def self.handlers
19
+ @handlers ||= []
20
+ end
21
+
22
+ def self.add(*raw_targets, &handler)
23
+ raw_targets.each do |raw_target|
24
+ obj, meth = case raw_target
25
+ when /^(.+)#(.+)$/
26
+ [$1.constantize, $2]
27
+ when /^(.+)(?:\.|::)(.+)$/
28
+ [(class << $1.constantize; self; end), $2]
29
+ else
30
+ raise Error, "Bad target format: #{raw_target}"
31
+ end
32
+ instrument(obj, meth, &handler)
33
+ end
34
+ end
35
+
36
+ #######
37
+ private
38
+ #######
39
+
40
+ def self.instrument(obj, meth, &handler)
41
+ handlers << handler unless handlers.include?(handler)
42
+ offset = handlers.size - 1
43
+ code = wrapping meth, :instrument do |without|
44
+ <<-CONTENTS
45
+ # Invoke and time
46
+ _start = Time.now
47
+ _result = #{without}(*args, &block)
48
+ _time = Time.now - _start
49
+ # Call handler (don't change *args!)
50
+ ::Instrument.handlers[#{offset}].call(self, _time, *args)
51
+ # Return the original result
52
+ _result
53
+ CONTENTS
54
+ end
55
+ obj.module_eval code
56
+ rescue => e
57
+ raise Error, "Could not attach (#{e.message})"
58
+ end
59
+
60
+ def self.wrapping(meth, feature)
61
+ format = meth =~ /^(.*?)(\?|!|=)$/ ? "#{$1}_%s_#{feature}#{$2}" : "#{meth}_%s_#{feature}"
62
+ <<-DYNAMIC
63
+ if instance_methods.include?("#{format % :without}")
64
+ # Skip instrumentation
65
+ else
66
+ def #{format % :with}(*args, &block)
67
+ #{yield(format % :without)}
68
+ end
69
+ alias_method_chain :#{meth}, :#{feature}
70
+ end
71
+ DYNAMIC
72
+ end
73
+
74
+ end
@@ -0,0 +1,125 @@
1
+ require File.dirname(__FILE__) << "/test_helper"
2
+ require 'stringio'
3
+
4
+ module Fake
5
+ class Widget
6
+ def turn
7
+ end
8
+ end
9
+ class FancyWidget < Widget
10
+ def screw(direction)
11
+ turn
12
+ end
13
+ end
14
+ class Cat
15
+ def meow
16
+ end
17
+ end
18
+ class Dog
19
+ def bark
20
+ end
21
+ def woof
22
+ end
23
+ end
24
+
25
+ class TargetA
26
+ end
27
+
28
+ class TargetB
29
+ def exists
30
+ end
31
+ end
32
+
33
+ class TargetC
34
+ def exists
35
+ end
36
+ end
37
+
38
+ class TargetD
39
+ def exists
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+
46
+ class InstrumentFake < Test::Unit::TestCase
47
+
48
+ context "Correct Behavior" do
49
+
50
+ setup do
51
+ Instrument.handlers.clear
52
+ end
53
+
54
+ should "executes hooks" do
55
+
56
+ turns = []
57
+
58
+ instrument 'Fake::Widget#turn' do
59
+ turns << :turn
60
+ end
61
+ instrument 'Fake::FancyWidget#screw' do
62
+ turns << :screw
63
+ end
64
+
65
+ widget = Fake::FancyWidget.new
66
+ 4.times { widget.turn }
67
+ widget.screw(:in)
68
+ widget.screw(:out)
69
+
70
+ assert_equal 8, turns.size
71
+ assert_equal 6, turns.select { |t| t == :turn }.size
72
+
73
+ end
74
+
75
+ should "works with multiple targets" do
76
+ calls = 0
77
+ instrument 'Fake::Dog#bark', 'Fake::Dog#woof' do
78
+ calls += 1
79
+ end
80
+ dog = Fake::Dog.new
81
+ dog.bark
82
+ dog.woof
83
+ assert_equal 2, calls
84
+ assert_equal 1, Instrument.handlers.size
85
+ end
86
+
87
+ end
88
+
89
+ context "Errors" do
90
+
91
+ setup do
92
+ @output = StringIO.new
93
+ end
94
+
95
+ should "raise exceptions on bad targets" do
96
+ assert_raises NameError do
97
+ instrument 'Fake::BadConstant#does_not_exist' do
98
+ end
99
+ end
100
+ assert_raises Instrument::Error do
101
+ instrument 'Fake::TargetA#does_not_exist' do
102
+ end
103
+ end
104
+ end
105
+
106
+ should "silently fail to reinstrument already instrumented methods" do
107
+ foo = 0
108
+ bar = 0
109
+ instrument 'Fake::TargetD#exists' do
110
+ foo += 1
111
+ end
112
+ Fake::TargetD.new.exists
113
+ assert_equal 1, foo
114
+ assert_equal 0, bar
115
+ instrument 'Fake::TargetD#exists' do
116
+ bar += 1
117
+ end
118
+ Fake::TargetD.new.exists
119
+ assert_equal 2, foo
120
+ assert_equal 0, bar
121
+ end
122
+
123
+ end
124
+
125
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'Shoulda'
4
+
5
+ $:.unshift(File.dirname(__FILE__) << "/../lib")
6
+ require 'instrument'
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: instrumentation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - FiveRuns Development Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-16 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: Provides a simple API for instrumenting Ruby method invocations.
25
+ email: dev@fiveruns.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - CHANGELOG
32
+ - lib/instrument.rb
33
+ - README.rdoc
34
+ files:
35
+ - CHANGELOG
36
+ - lib/instrument.rb
37
+ - Manifest
38
+ - Rakefile
39
+ - README.rdoc
40
+ - test/instrument_test.rb
41
+ - test/test_helper.rb
42
+ - instrumentation.gemspec
43
+ has_rdoc: true
44
+ homepage: http://github.com/fiveruns/instrumentation
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --line-numbers
48
+ - --inline-source
49
+ - --title
50
+ - Instrumentation
51
+ - --main
52
+ - README.rdoc
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project: fiveruns
70
+ rubygems_version: 1.1.1
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: Provides a simple API for instrumenting Ruby method invocations.
74
+ test_files:
75
+ - test/instrument_test.rb
76
+ - test/test_helper.rb