method_profiler 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,6 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ coverage/*
6
+ .yardoc/*
7
+ doc/*
data/README.md CHANGED
@@ -1,19 +1,87 @@
1
1
  # MethodProfiler
2
2
 
3
- **MethodProfiler** collects performance information about the methods in your objects and creates reports to help you identify slow methods.
3
+ **MethodProfiler** collects performance information about the methods in your objects and creates reports to help you identify slow methods. The collected data can be sorted in various ways, converted into an array, or pretty printed as a table.
4
+
5
+ ## Basic usage
6
+
7
+ Create a new profiler by passing the object you want to profile to `MethodProfiler.observe`. All future class and instance methods called on your object will be recorded by the profiler. To see the results of the profiling as a table, simply print out the report returned by `#report` on the profiler object.
4
8
 
5
9
  ```ruby
6
- profiler = MethodProfiler.new(MyClass)
7
- MyClass.new.foo
10
+ profiler = MethodProfiler.observe(MyClass)
11
+
12
+ MyClass.nisi_inventore
13
+ MyClass.nisi_inventore
14
+
15
+ my_obj = MyClass.new
16
+
17
+ my_obj.accusamus_est
18
+ my_obj.accusamus_est
19
+ my_obj.accusamus_est
20
+
8
21
  puts profiler.report
22
+ ```
9
23
 
10
- # MethodProfiler results for:
11
- # MyClass
12
- # +--------+--------------+-------------+
13
- # | Method | Average Time | Total Calls |
14
- # +--------+--------------+-------------+
15
- # | foo | 91.037000 ms | 1 |
16
- # | bar | 15.016000 ms | 2 |
17
- # | baz | 23.005000 ms | 1 |
18
- # +--------+--------------+-------------+
24
+ The resulting chart includes each method, the minimum time it took to run, the maximum time, the average across all calls, and the total number of times it was called. Class methods are prefixed by a `.` and instance methods are prefixed with a `#`.
25
+
26
+ ```
27
+ MethodProfiler results for: MyClass
28
+ +------------------------+-----------+------------+--------------+-------------+
29
+ | Method | Min Time | Max Time | Average Time | Total Calls |
30
+ +------------------------+-----------+------------+--------------+-------------+
31
+ | #accusamus_est | 32.086 ms | 324.140 ms | 160.252 ms | 3 |
32
+ | #autem_iste! | 29.607 ms | 318.592 ms | 156.221 ms | 3 |
33
+ | #distinctio_eos | 29.477 ms | 318.471 ms | 156.097 ms | 3 |
34
+ | #laborum_fugit | 18.388 ms | 291.900 ms | 140.580 ms | 3 |
35
+ | #suscipit_architecto | 12.036 ms | 272.279 ms | 130.247 ms | 3 |
36
+ | #et_fugit | 2.794 ms | 11.658 ms | 6.185 ms | 3 |
37
+ | #porro_rerum | 0.097 ms | 12.096 ms | 1.031 ms | 43 |
38
+ | #provident_molestiae | 0.005 ms | 3.997 ms | 0.871 ms | 6 |
39
+ | .nisi_inventore | 0.368 ms | 1.329 ms | 0.849 ms | 2 |
40
+ | #quis_temporibus | 0.104 ms | 6.696 ms | 0.713 ms | 24 |
41
+ | #labore_voluptatum | 0.004 ms | 8.834 ms | 0.447 ms | 86 |
42
+ | #quia_est | 0.004 ms | 3.667 ms | 0.327 ms | 24 |
43
+ | #ut_reiciendis | 0.004 ms | 2.842 ms | 0.250 ms | 24 |
44
+ | #sint_quasi | 0.066 ms | 1.836 ms | 0.166 ms | 24 |
45
+ | #sed_at | 0.067 ms | 0.119 ms | 0.078 ms | 24 |
46
+ | #repellendus_suscipit | 0.054 ms | 0.128 ms | 0.067 ms | 24 |
47
+ | #quas_nesciunt | 0.024 ms | 0.026 ms | 0.025 ms | 3 |
48
+ | #iure_quis | 0.006 ms | 0.232 ms | 0.014 ms | 48 |
49
+ | #dicta_ipsam | 0.005 ms | 0.068 ms | 0.013 ms | 24 |
50
+ | #perspiciatis_aut | 0.006 ms | 0.006 ms | 0.006 ms | 3 |
51
+ | #aperiam_laborum | 0.004 ms | 0.009 ms | 0.005 ms | 34 |
52
+ +------------------------+-----------+------------+--------------+-------------+
19
53
  ```
54
+
55
+ ## Reporting
56
+
57
+ `MethodProfiler::Profiler#report` actually returns a report object which can be used to sort and display the data in various ways. A report has chainable `#sort_by` and `#order` methods to control the sorting of the report when it is ultimately displayed. The report can be turned into an array by calling `#to_a` and the table shown above by calling `#to_s`.
58
+
59
+ *Example of sorting by the number of total calls, ascending:*
60
+
61
+ ```ruby
62
+ puts profiler.report.sort_by(:total_calls).order(:ascending)
63
+ ```
64
+
65
+ `#sort_by` accepts a symbol or string with the name of any of the columns in the table: `:method`, `:min`, `:max`, `:average`, or `:total_calls`.
66
+
67
+ `#order` accepts a symbol or string of `:ascending` or `:descending`. These can also be abbreviated with `:asc` and `:desc`.
68
+
69
+ ## Documentation
70
+
71
+ The public API is fully documented using [YARD](http://yardoc.org/) and can be viewed on [RubyDoc.info](http://rubydoc.info/).
72
+
73
+ ## Tests
74
+
75
+ All code is tested with [RSpec](https://github.com/rspec/rspec). To run the specs, clone the repository, install the dependencies with `bundle install`, and then run `rake`.
76
+
77
+ ## Issues
78
+
79
+ If you have any problems or suggestions for the project, please open a GitHub issue.
80
+
81
+ ## License
82
+
83
+ MethodProfiler is available under the included MIT license.
84
+
85
+ ## Acknowledgements
86
+
87
+ Thank you to [Change.org](http://www.change.org/) for sponsoring the project and to my coworker [Alain Bloch](https://github.com/alainbloch) for the inspiration.
@@ -1,103 +1,17 @@
1
- require 'benchmark'
2
- require 'hirb'
3
-
4
- class MethodProfiler
5
- attr_reader :observed_methods, :data
6
-
7
- def initialize(obj)
8
- @obj = obj
9
- initialize_data
10
- find_obj_methods
11
- wrap_methods_with_profiling
12
- end
13
-
14
- def profile(method, &block)
15
- result = nil
16
- benchmark = Benchmark.measure { result = block.call }
17
- elapsed_time = benchmark.to_s.match(/\(\s*([^\)]+)\)/)[1].to_f
18
- @data[method.to_sym] << elapsed_time
19
- result
20
- end
21
-
22
- def report
23
- [
24
- "MethodProfiler results for: #{@obj}",
25
- Hirb::Helpers::Table.render(
26
- final_data,
27
- headers: {
28
- method: "Method",
29
- min: "Min Time",
30
- max: "Max Time",
31
- average: "Average Time",
32
- total_calls: "Total Calls"
33
- },
34
- fields: [:method, :min, :max, :average, :total_calls],
35
- description: false
36
- )
37
- ].join("\n")
38
- end
39
-
40
- def reset!
41
- initialize_data
42
- @final_data = nil
43
- end
44
-
45
- private
46
-
47
- def initialize_data
48
- @data = Hash.new { |h, k| h[k] = [] }
49
- end
50
-
51
- def find_obj_methods
52
- @observed_methods ||= begin
53
- methods = @obj.instance_methods
54
- @obj.ancestors.each do |a|
55
- next if a == @obj
56
- methods -= a.instance_methods
57
- end
58
- methods
59
- end
60
- end
61
-
62
- def wrap_methods_with_profiling
63
- profiler = self
64
- observed = observed_methods
65
-
66
- @obj.module_eval do
67
- observed.each do |method|
68
- define_method("#{method}_with_profiling") do |*args|
69
- profiler.profile(method) { send("#{method}_without_profiling", *args) }
70
- end
71
-
72
- alias_method "#{method}_without_profiling", method
73
- alias_method method, "#{method}_with_profiling"
74
- end
75
- end
76
- end
77
-
78
- def final_data
79
- @final_data ||= begin
80
- final_data = []
81
- data.each do |method, records|
82
- total_calls = records.size
83
- average = records.reduce(:+) / total_calls
84
- final_data << {
85
- method: method,
86
- min: records.min,
87
- max: records.max,
88
- average: average,
89
- total_calls: total_calls
90
- }
91
- end
92
- final_data.sort! { |a, b| b[:average] <=> a[:average] }
93
- final_data.each do |record|
94
- [:min, :max, :average].each { |k| record[k] = to_ms(record[k]) }
95
- end
96
- final_data
97
- end
98
- end
99
-
100
- def to_ms(seconds)
101
- "%.3f ms" % (seconds * 1000)
1
+ require 'method_profiler/profiler'
2
+
3
+ # {MethodProfiler} collects performance information about the methods
4
+ # in your objects and creates reports to help you identify slow methods.
5
+ #
6
+ module MethodProfiler
7
+ # Create a new {MethodProfiler::Profiler} which will observe all method calls
8
+ # on the given object. This is a convenience method and has the same effect
9
+ # as {MethodProfiler::Profiler#initialize}.
10
+ #
11
+ # @param [Object] obj The object to observe.
12
+ # @return [MethodProfiler::Profiler] A new profiler.
13
+ #
14
+ def self.observe(obj)
15
+ Profiler.new(obj)
102
16
  end
103
17
  end
@@ -0,0 +1,14 @@
1
+ require 'hirb'
2
+
3
+ # All methods in this module can be used as filters in Hirb.
4
+ #
5
+ module Hirb::Helpers::Table::Filters
6
+ # Converts seconds to milliseconds. Used to format times in
7
+ # the output of {MethodProfiler::Report}.
8
+ #
9
+ # @param [Float] seconds The duration to convert.
10
+ # @return [String] The duration in milliseconds with units displayed. Rounded to 3 decimal places.
11
+ def to_milliseconds(seconds)
12
+ "%.3f ms" % (seconds * 1000)
13
+ end
14
+ end
@@ -0,0 +1,105 @@
1
+ require 'method_profiler/report'
2
+
3
+ require 'benchmark'
4
+
5
+ module MethodProfiler
6
+ # Observes an object, keeping track of all its method calls and the wall clock
7
+ # time spent executing them.
8
+ #
9
+ class Profiler
10
+ # Initializes a new {Profiler}. Wraps all methods in the object and its singleton
11
+ # class with profiling code.
12
+ #
13
+ # @param [Object] obj The object to observe.
14
+ #
15
+ def initialize(obj)
16
+ @obj = obj
17
+ @data = Hash.new { |h, k| h[k] = [] }
18
+
19
+ wrap_methods_with_profiling
20
+ end
21
+
22
+ # Generates a report object with all the data collected so far bay the profiler. This report
23
+ # can be displayed in various ways. See {Report}.
24
+ #
25
+ # @return [Report] A new report with all the data the profiler has collected.
26
+ #
27
+ def report
28
+ Report.new(final_data)
29
+ end
30
+
31
+ private
32
+
33
+ def wrap_methods_with_profiling
34
+ profiler = self
35
+ singleton_methods_to_wrap = find_singleton_methods
36
+ instance_methods_to_wrap = find_instance_methods
37
+
38
+ @obj.singleton_class.module_eval do
39
+ singleton_methods_to_wrap.each do |method|
40
+ define_method("#{method}_with_profiling") do |*args|
41
+ profiler.send(:profile, method, true) { send("#{method}_without_profiling", *args) }
42
+ end
43
+
44
+ alias_method "#{method}_without_profiling", method
45
+ alias_method method, "#{method}_with_profiling"
46
+ end
47
+ end
48
+
49
+ @obj.module_eval do
50
+ instance_methods_to_wrap.each do |method|
51
+ define_method("#{method}_with_profiling") do |*args|
52
+ profiler.send(:profile, method) { send("#{method}_without_profiling", *args) }
53
+ end
54
+
55
+ alias_method "#{method}_without_profiling", method
56
+ alias_method method, "#{method}_with_profiling"
57
+ end
58
+ end
59
+ end
60
+
61
+ def find_singleton_methods
62
+ @obj.singleton_class.instance_methods - @obj.singleton_class.ancestors.map do |a|
63
+ a == @obj ? [] : a.instance_methods
64
+ end.flatten
65
+ end
66
+
67
+ def find_instance_methods
68
+ @obj.instance_methods - @obj.ancestors.map do |a|
69
+ a == @obj ? [] : a.instance_methods
70
+ end.flatten
71
+ end
72
+
73
+ def profile(method, singleton = false, &block)
74
+ method_name = singleton ? ".#{method}" : "##{method}"
75
+ result = nil
76
+ elapsed_time = benchmark(result, &block).to_s.match(/\(\s*([^\)]+)\)/)[1].to_f
77
+ @data[method_name] << elapsed_time
78
+ result
79
+ end
80
+
81
+ def final_data
82
+ results = []
83
+
84
+ @data.each do |method, records|
85
+ total_calls = records.size
86
+ average = records.reduce(:+) / total_calls
87
+ results << {
88
+ method: method,
89
+ min: records.min,
90
+ max: records.max,
91
+ average: average,
92
+ total_calls: total_calls
93
+ }
94
+ end
95
+
96
+ results
97
+ end
98
+
99
+ private
100
+
101
+ def benchmark(result, &block)
102
+ Benchmark.measure { result = block.call }
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,89 @@
1
+ require 'hirb'
2
+ require 'method_profiler/hirb'
3
+
4
+ module MethodProfiler
5
+ # Sorts and displays data collected by a {Profiler}.
6
+ #
7
+ class Report
8
+ # Fields that can be passed to {#sort_by}.
9
+ FIELDS = [:method, :min, :max, :average, :total_calls]
10
+
11
+ # Directions that can be passed to {#order}.
12
+ DIRECTIONS = [:asc, :ascending, :desc, :descending]
13
+
14
+ # Initializes a new {Report}. Used to sort and display data collected by a {Profiler}.
15
+ #
16
+ # @param [Array] data Data collected by a {Profiler}.
17
+ #
18
+ def initialize(data)
19
+ @data = data
20
+ @sort_by = :average
21
+ @order = :descending
22
+ end
23
+
24
+ # Sorts the report by the given field. Defaults to `:average`. Chainable with {#order}.
25
+ #
26
+ # @param [Symbol, String] field Any field from {FIELDS} to sort by.
27
+ # @return [Report] The {Report} object, suitable for chaining or display.
28
+ #
29
+ def sort_by(field)
30
+ field = field.to_sym
31
+ field = :average unless FIELDS.include?(field)
32
+ @sort_by = field
33
+ self
34
+ end
35
+
36
+ # Changes the direction of the sort. Defaults to `:descending`. Chainable with {#sort_by}.
37
+ #
38
+ # @param [Symbol, String] direction Any direction from {DIRECTIONS} to direct the sort.
39
+ # @return [Report] The {Report} object, suitable for chaining or display.
40
+ #
41
+ def order(direction)
42
+ direction = direction.to_sym
43
+ direction = :descending unless DIRECTIONS.include?(direction)
44
+ direction = :descending if direction == :desc
45
+ direction = :ascending if direction == :asc
46
+ @order = direction
47
+ self
48
+ end
49
+
50
+ # Sorts the data by the currently set criteria and returns an array of profiling results.
51
+ #
52
+ # @return [Array] An array of profiling results.
53
+ #
54
+ def to_a
55
+ if @order == :ascending
56
+ @data.sort { |a, b| a[@sort_by] <=> b[@sort_by] }
57
+ else
58
+ @data.sort { |a, b| b[@sort_by] <=> a[@sort_by] }
59
+ end
60
+ end
61
+
62
+ # Sorts the data by the currently set criteria and returns a pretty printed table as a string.
63
+ #
64
+ # @return [String] A table of profiling results.
65
+ #
66
+ def to_s
67
+ [
68
+ "MethodProfiler results for: #{@obj}",
69
+ Hirb::Helpers::Table.render(
70
+ to_a,
71
+ headers: {
72
+ method: "Method",
73
+ min: "Min Time",
74
+ max: "Max Time",
75
+ average: "Average Time",
76
+ total_calls: "Total Calls"
77
+ },
78
+ fields: [:method, :min, :max, :average, :total_calls],
79
+ filters: {
80
+ min: :to_milliseconds,
81
+ max: :to_milliseconds,
82
+ average: :to_milliseconds
83
+ },
84
+ description: false
85
+ )
86
+ ].join("\n")
87
+ end
88
+ end
89
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "method_profiler"
5
- s.version = "0.1.0"
5
+ s.version = "1.0.0"
6
6
  s.authors = ["Jimmy Cuadra"]
7
7
  s.email = ["jimmy@jimmycuadra.com"]
8
8
  s.homepage = "https://github.com/change/method_profiler"
@@ -16,4 +16,5 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.add_runtime_dependency "hirb", ">= 0.6.0"
18
18
  s.add_development_dependency "rspec"
19
+ s.add_development_dependency "simplecov"
19
20
  end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe MethodProfiler::Profiler do
4
+ let!(:profiler) { described_class.new(Petition) }
5
+ let(:petition) { Petition.new }
6
+
7
+ it "creates wrapper methods for the object's methods" do
8
+ petition.should respond_to(:foo)
9
+ petition.should respond_to(:foo_with_profiling)
10
+ petition.should respond_to(:foo_without_profiling)
11
+ petition.should_not respond_to(:foo_with_profiling_with_profiling)
12
+ end
13
+
14
+ describe "#report" do
15
+ it "returns a new Report object" do
16
+ profiler.report.should be_an_instance_of MethodProfiler::Report
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe MethodProfiler::Report do
4
+ before do
5
+ profiler = MethodProfiler::Profiler.new(Petition)
6
+
7
+ # Fake the timings for testing purposes
8
+ profiler.stub(:benchmark) do |result, block|
9
+ result = block.call
10
+ "(#{rand})"
11
+ end
12
+
13
+ petition = Petition.new
14
+
15
+ [:hay, :hay, :guys].each { |m| petition.class.send(m) }
16
+ [:foo, :bar, :baz].each { |m| petition.send(m) }
17
+
18
+ @report = profiler.report
19
+ end
20
+
21
+ describe "#to_a" do
22
+ it "returns an array of records" do
23
+ results = @report.to_a
24
+ results.should be_an Array
25
+ results.size.should == 5
26
+ end
27
+
28
+ it "sorts by average time (descending) by default" do
29
+ results = @report.to_a
30
+ average_times = results.map { |r| r[:average] }
31
+ average_times.should == average_times.sort.reverse
32
+ end
33
+
34
+ it "sorts by another type if it's been changed" do
35
+ results = @report.sort_by(:min).to_a
36
+ min_times = results.map { |r| r[:min] }
37
+ min_times.should == min_times.sort.reverse
38
+ end
39
+
40
+ it "sorts in a different direction if it's been changed" do
41
+ results = @report.order(:ascending).to_a
42
+ average_times = results.map { |r| r[:average] }
43
+ average_times.should == average_times.sort
44
+ end
45
+ end
46
+
47
+ describe "#sort_by" do
48
+ it "sets the sort type" do
49
+ @report.sort_by(:total_calls)
50
+ @report.instance_variable_get("@sort_by").should == :total_calls
51
+ end
52
+
53
+ it "defaults to average if an invalid sort type is passed" do
54
+ @report.sort_by(:foo)
55
+ @report.instance_variable_get("@sort_by").should == :average
56
+ end
57
+ end
58
+
59
+ describe "#order" do
60
+ it "sets the sort direction" do
61
+ @report.order(:ascending)
62
+ @report.instance_variable_get("@order").should == :ascending
63
+ end
64
+
65
+ it "defaults to descending if an invalid direction is passed" do
66
+ @report.order(:foo)
67
+ @report.instance_variable_get("@order").should == :descending
68
+ end
69
+
70
+ it "allows normalizes :asc and :desc aliases" do
71
+ @report.order(:asc)
72
+ @report.instance_variable_get("@order").should == :ascending
73
+
74
+ @report.order(:desc)
75
+ @report.instance_variable_get("@order").should == :descending
76
+ end
77
+ end
78
+
79
+ describe "#to_s" do
80
+ it "outputs one line for each method that was called" do
81
+ output = @report.to_s
82
+
83
+ output.should be_a String
84
+ output.scan(/\.hay/).size.should == 1
85
+ output.scan(/\.guys/).size.should == 1
86
+ output.scan(/#foo/).size.should == 1
87
+ output.scan(/#bar/).size.should == 1
88
+ output.scan(/#baz/).size.should == 1
89
+ end
90
+ end
91
+ end
@@ -1,60 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- profiler = MethodProfiler.new(Petition)
4
-
5
3
  describe MethodProfiler do
6
- before { @petition = Petition.new }
7
- after { profiler.reset! }
8
-
9
- it "can be instantiated with an object to observe" do
10
- profiler.should be_true
11
- end
12
-
13
- it "finds all the object's instance methods" do
14
- profiler.observed_methods.sort.should == [:foo, :bar, :baz].sort
15
- end
16
-
17
- it "creates wrapper methods for each method in the object" do
18
- @petition.should respond_to(:foo)
19
- @petition.should respond_to(:foo_with_profiling)
20
- @petition.should respond_to(:foo_without_profiling)
21
- @petition.should_not respond_to(:foo_with_profiling_with_profiling)
22
- end
23
-
24
- describe "#profile" do
25
- it "adds a new record for the method call" do
26
- @petition.foo
27
- profiler.data[:foo].size.should == 1
28
- end
29
-
30
- it "calls the real method" do
31
- @petition.should_receive(:foo_without_profiling)
32
- @petition.foo
33
- end
34
-
35
- it "returns the value of the real method" do
36
- @petition.baz.should == "blah"
37
- end
38
- end
39
-
40
- describe "#report" do
41
- it "outputs a string of report data" do
42
- profiler.report.should be_an_instance_of(String)
43
- end
44
-
45
- it "outputs one line for each method that was called" do
46
- @petition.foo
47
- @petition.bar
48
- @petition.baz
49
- profiler.report.scan(/foo/).size.should == 1
50
- profiler.report.scan(/bar/).size.should == 1
51
- profiler.report.scan(/baz/).size.should == 1
52
- end
53
-
54
- it "combines multiple calls to the same method into one line" do
55
- @petition.foo
56
- @petition.foo
57
- profiler.report.scan(/foo/).size.should == 1
4
+ describe ".observe" do
5
+ it "returns a new Profiler instance" do
6
+ described_class.observe(Petition).should be_an_instance_of described_class::Profiler
58
7
  end
59
8
  end
60
9
  end
@@ -1,8 +1,13 @@
1
+ require "simplecov"
2
+ SimpleCov.start
3
+
1
4
  $:.unshift(File.expand_path("../../lib", __FILE__))
2
5
  require "method_profiler"
3
6
 
4
- class Petition
5
- def foo; end
6
- def bar; end
7
- def baz; "blah"; end
7
+ RSpec.configure do |config|
8
+ config.around do |example|
9
+ load File.expand_path("../support/petition.rb", __FILE__)
10
+ example.call
11
+ Object.send(:remove_const, :Petition)
12
+ end
8
13
  end
@@ -0,0 +1,18 @@
1
+ class Petition
2
+ def self.hay
3
+ end
4
+
5
+ def self.guys
6
+ "sup"
7
+ end
8
+
9
+ def foo
10
+ end
11
+
12
+ def bar
13
+ end
14
+
15
+ def baz
16
+ "blah"
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: method_profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-02 00:00:00.000000000 Z
12
+ date: 2012-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hirb
16
- requirement: &70179117063300 !ruby/object:Gem::Requirement
16
+ requirement: &70181816945620 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.6.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70179117063300
24
+ version_requirements: *70181816945620
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70179117084460 !ruby/object:Gem::Requirement
27
+ requirement: &70181816945220 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,18 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70179117084460
35
+ version_requirements: *70181816945220
36
+ - !ruby/object:Gem::Dependency
37
+ name: simplecov
38
+ requirement: &70181816944760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70181816944760
36
47
  description: MethodProfiler observes your code and generates reports about the methods
37
48
  that were run and how long they took.
38
49
  email:
@@ -47,9 +58,15 @@ files:
47
58
  - README.md
48
59
  - Rakefile
49
60
  - lib/method_profiler.rb
61
+ - lib/method_profiler/hirb.rb
62
+ - lib/method_profiler/profiler.rb
63
+ - lib/method_profiler/report.rb
50
64
  - method_profiler.gemspec
65
+ - spec/method_profiler/profiler_spec.rb
66
+ - spec/method_profiler/report_spec.rb
51
67
  - spec/method_profiler_spec.rb
52
68
  - spec/spec_helper.rb
69
+ - spec/support/petition.rb
53
70
  homepage: https://github.com/change/method_profiler
54
71
  licenses: []
55
72
  post_install_message:
@@ -75,5 +92,9 @@ signing_key:
75
92
  specification_version: 3
76
93
  summary: Find slow methods in your program.
77
94
  test_files:
95
+ - spec/method_profiler/profiler_spec.rb
96
+ - spec/method_profiler/report_spec.rb
78
97
  - spec/method_profiler_spec.rb
79
98
  - spec/spec_helper.rb
99
+ - spec/support/petition.rb
100
+ has_rdoc: