timeasure 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 284614263b2c5c4343831c8d79e391c869009490
4
+ data.tar.gz: 72aa7b99c6eaeef54890c1c12d66679be73895f1
5
+ SHA512:
6
+ metadata.gz: 175a8df40f6cf4a2ef58b11375b6b83da05499d960ed67055812fae8ebb9337b5d76834a432efc781d6ca8afc43f2fe816011538047755746bffb1ca448e853d
7
+ data.tar.gz: 20b2c718f96d7d0f8057cb086dc0cdab8fce80b1933fe9b7c0f68dddfa9606244b99cf57311b89976bac98250c8bd15652f832aba2ceb4317cd2e7d7c29dc5e5
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .idea/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,11 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4.2
3
+
4
+ Metrics/LineLength:
5
+ Max: 120
6
+
7
+ Documentation:
8
+ Enabled: false
9
+
10
+ Metrics/BlockLength:
11
+ ExcludedMethods: ['describe', 'context', 'before']
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in timeasure.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Eliav Lavi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Timeasure
2
+
3
+ **What Is It?**
4
+
5
+ Timeasure is a transparent method-level wrapper for profiling purposes developed by [Eliav Lavi](http://www.eliavlavi.com) & [Riskified](https://www.riskified.com/)).
6
+
7
+ Timeasure is a Ruby gem that allows measuring the runtime of methods in production environments
8
+ without having to alter the code of the methods themselves.
9
+
10
+ Timeasure allows you to declare tracked methods to be measured transparently upon each call.
11
+ Measured calls are then reported to Timeasure's Profiler, which aggregates the measurements on the method level.
12
+ This part is configurable and if you wish you can report measurements to another profiler of your choice.
13
+
14
+ **Why Use It?**
15
+
16
+ Timeasure was created in order to serve as an easy-to-use, self-contained framework for method-level profiling
17
+ that is safe to use in production. Testing runtime in non-production environments is helpful, but there is
18
+ great value to the knowledge gained by measuring what really goes on at real time.
19
+
20
+ **What To Do With the Data?**
21
+
22
+ The imagined usage of measured methods timing is to aggregate it along a certain transaction and report it to a live
23
+ BI service such as [NewRelic Insights](https://newrelic.com/insights) or [Keen.io](https://keen.io/);
24
+ however, different usages might prove helpful as well, such as writing the data to a database or a file.
25
+
26
+ **Disclaimers**
27
+
28
+ Timeasure uses minimal intervention in the Ruby Object Model for tracked modules and classes.
29
+ It integrates well within Rails and non-Rails apps.
30
+
31
+ Timeasure is inspired by [Metaprogramming Ruby 2](https://pragprog.com/book/ppmetr2/metaprogramming-ruby-2)
32
+ by [Paolo Perrotta](https://twitter.com/nusco)
33
+ and by [this](https://hashrocket.com/blog/posts/module-prepend-a-super-story) blog post by Hashrocket.
34
+
35
+ ## Requirements
36
+
37
+ Ruby 2.0 or a later version is mandatory. (Timeasure uses `Module#prepend` introduced in Ruby 2.0.)
38
+
39
+ ## Installation
40
+
41
+ Add this line to your application's Gemfile:
42
+
43
+ gem 'timeasure'
44
+
45
+ And then execute:
46
+
47
+ $ bundle
48
+
49
+ Or install it yourself as:
50
+
51
+ $ gem install timeasure
52
+
53
+ ## Usage
54
+ #### 1. Include Timeasure in Modules and Classes
55
+ Simply include the Timeasure module in any class or module and declare the desired methods to track:
56
+
57
+ ```ruby
58
+ class Foo
59
+ include Timeasure
60
+ tracked_class_methods :bar
61
+ tracked_instance_methods :baz, :qux
62
+
63
+ def self.bar
64
+ # some class-level stuff that can benefit from measuring runtime...
65
+ end
66
+
67
+ def baz
68
+ # some instance-level stuff that can benefit from measuring runtime...
69
+ end
70
+
71
+ def qux
72
+ # some other instance-level stuff that can benefit from measuring runtime...
73
+ end
74
+ end
75
+ ```
76
+
77
+ #### 2. Define the Boundaries of the Tracked Transaction
78
+ **Preparing for Method Tracking**
79
+
80
+ The user is responsible for managing the final reporting and the clean-up of the aggregated data after each transation.
81
+ It is recommended to prepare the profiler at the beginning of a transaction in which tracked methods exist with
82
+
83
+ ```ruby
84
+ Timeasure::Profiling::Manager.prepare
85
+ ```
86
+ and to re-prepare it again at the end of it in order to ensure a "clean slate" -
87
+ after you have handled the aggregated data in some way.
88
+
89
+ **Getting Hold of the Data**
90
+
91
+ In order to get hold of the reported methods data, use
92
+ ```ruby
93
+ Timeasure::Profiling::Manager.export
94
+ ````
95
+ This will return an array of `ReportedMethod`s. Each `ReportedMethod` object holds the aggregated timing data per
96
+ each tracked method call. This means that no matter how many times you call a tracked method, Timeasure's Profiler will
97
+ still hold a single `ReportedMethod` object to represent it.
98
+
99
+ `ReportedMethod` allows reading the following attributes:
100
+ * `klass_name`: Name of the class in which the tracked method resides.
101
+ * `method_name`: Name of the tracked method.
102
+ * `segment`: See [Segmented Method Tracking](#segmented-method-tracking) below.
103
+ * `metadata`: See [Carrying Metadata](#carrying-metadata) below.
104
+ * `method_path`: `klass_name` and `method_name` concatenated.
105
+ * `full_path`: Same as `method_path` unless segmentation is declared,
106
+ in which case the segment will be concatenated to the string as well. See [Segmented Method Tracking](#segmented-method-tracking) below.
107
+ * `runtime_sum`: The aggregated time it took the reported method in question to run across all calls.
108
+ * `call_count`: The times the reported method in question was called across all calls.
109
+
110
+
111
+ ## Advanced Usage
112
+
113
+ #### Segmented Method Tracking
114
+ Timeasure was designed to separate regular code from its time measurement declaration.
115
+ This is achieved by Timeasure's class macros `tracked_class_methods` and `tracked_instance_methods`.
116
+ Sometimes, however, the need for additional data might arise. Imagine this method:
117
+
118
+ ```ruby
119
+ class Foo
120
+ def bar(baz)
121
+ # some stuff that can benefit from measuring runtime
122
+ # yet its runtime is also highly affected by the value of baz...
123
+ end
124
+ end
125
+ ```
126
+
127
+ We've seen how Timeasure makes it easy to measure the `bar` method.
128
+ However, if we wish to segment each call by the value of `baz`,
129
+ we may use Timeasure's direct interface and send this value as a **segment**:
130
+
131
+ ```ruby
132
+ class Foo
133
+ def bar(baz)
134
+ Timeasure.measure(klass_name: 'Foo', method_name: 'bar', segment: { baz: baz }) do
135
+ # the code to be measured
136
+ end
137
+ end
138
+ end
139
+ ```
140
+
141
+ For such calls, Timeasure's Profiler will aggregate the data in `ReportedMethod` objects grouped by
142
+ class, method and segment.
143
+
144
+ This approach obviously violates Timeasure's idea of separating code and measurement-declaration,
145
+ but it allows for much more detailed investigations, if needed.
146
+ This will result in different `ReportedMethod` object in Timeasure's Profiler for
147
+ each combination of class, method and segment. Accordingly, such `ReportedMethod` object will include
148
+ these three elements, concatenated, as the value for `ReportedMethod#full_path`.
149
+
150
+ #### Carrying Metadata
151
+ This feature was developed in order to complement the segmented method tracking.
152
+
153
+ Sometimes carrying data with measurement that does not define a segment might be needed.
154
+ For example, assuming we save all our `ReportedMethod`s to some table called `reported_methods`,
155
+ we might want to supply a custom table name for specific measurements.
156
+ This might be achieved by using `metadata`:
157
+
158
+ ```ruby
159
+ class Foo
160
+ def bar
161
+ Timeasure.measure(klass_name: 'Foo', method_name: 'bar', metadata: { table_name: 'my_custom_table' }) do
162
+ # the code to be measured
163
+ end
164
+ end
165
+ end
166
+ ```
167
+
168
+ Unlike Segments, Timeasure only carries the Metadata onwards.
169
+ It is up to the user to make use of this data, probably after calling `Timeasure::Profiling::Manager.export`.
170
+
171
+ ## Notes
172
+
173
+ #### Compatibility with RSpec
174
+
175
+ If you run your test suite with Timeasure installed and modules, classes and methods tracked and all works fine - hurray!
176
+ However, due to the mechanics of Timeasure - namely, its usage of prepended modules - there exist a problem with
177
+ **stubbing** Timeasure-tracked method (RSpec does not support stubbing methods that appear in a prepended module).
178
+ To be accurate, that means that if you are tracking method `#foo`, you can not
179
+ declare something like `allow(bar).to receive(:foo).and_return(bar)`. Your specs will refuse to run in this case.
180
+ To solve that problem you can configure Timeasure's `enable_timeasure_proc` **not** to run under certain conditions.
181
+
182
+ If you are on Rails, add the following as a Rails initializer:
183
+
184
+ ```ruby
185
+ require 'timeasure'
186
+
187
+ Timeasure.configure do |configuration|
188
+ configuration.enable_timeasure_proc = lambda { !Rails.env.test? }
189
+ end
190
+ ```
191
+
192
+ Timeasure will not come into action if the expression in the block evaluates to `false`.
193
+ By default this block evaluates to `true`.
194
+
195
+
196
+ ## Feature Requests
197
+
198
+ Timeasure is open for changes and requests!
199
+ If you have an idea, a question or some need, feel free to contact me here or at eliavlavi@gmail.com.
200
+
201
+ ## Contributing
202
+
203
+ 1. Fork it ( https://github.com/riskified/timeasure/fork )
204
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
205
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
206
+ 4. Push to the branch (`git push origin my-new-feature`)
207
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/timeasure.rb ADDED
@@ -0,0 +1,69 @@
1
+ require_relative 'timeasure/version'
2
+ require_relative 'timeasure/configuration'
3
+ require_relative 'timeasure/class_methods'
4
+ require_relative 'timeasure/measurement'
5
+ require_relative 'timeasure/profiling/manager'
6
+
7
+ module Timeasure
8
+ class << self
9
+ def configure
10
+ yield(configuration)
11
+ end
12
+
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
+
17
+ def included(base_class)
18
+ base_class.extend ClassMethods
19
+
20
+ instance_interceptor = const_set(instance_interceptor_name_for(base_class), interceptor_module_for(base_class))
21
+ class_interceptor = const_set(class_interceptor_name_for(base_class), interceptor_module_for(base_class))
22
+
23
+ return unless timeasure_enabled?
24
+
25
+ base_class.prepend instance_interceptor
26
+ base_class.singleton_class.prepend class_interceptor
27
+ end
28
+
29
+ def measure(klass_name: nil, method_name: nil, segment: nil, metadata: nil)
30
+ t0 = Time.now.utc
31
+ block_return_value = yield if block_given?
32
+ t1 = Time.now.utc
33
+
34
+ begin
35
+ measurement = Timeasure::Measurement.new(klass_name: klass_name.to_s, method_name: method_name.to_s,
36
+ segment: segment, metadata: metadata, t0: t0, t1: t1)
37
+ Timeasure.configuration.post_measuring_proc.call(measurement)
38
+ rescue => e
39
+ Timeasure.configuration.rescue_proc.call(e, klass_name)
40
+ end
41
+
42
+ block_return_value
43
+ end
44
+
45
+ private
46
+
47
+ def instance_interceptor_name_for(base_class)
48
+ "#{base_class.timeasure_name}InstanceInterceptor"
49
+ end
50
+
51
+ def class_interceptor_name_for(base_class)
52
+ "#{base_class.timeasure_name}ClassInterceptor"
53
+ end
54
+
55
+ def interceptor_module_for(base_class)
56
+ Module.new do
57
+ @klass_name = base_class
58
+
59
+ def self.klass_name
60
+ @klass_name
61
+ end
62
+ end
63
+ end
64
+
65
+ def timeasure_enabled?
66
+ configuration.enable_timeasure_proc.call
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,33 @@
1
+ module Timeasure
2
+ module ClassMethods
3
+ def tracked_instance_methods(*method_names)
4
+ method_names.each do |method_name|
5
+ instance_interceptor = const_get("#{timeasure_name}InstanceInterceptor")
6
+ add_method_to_interceptor(instance_interceptor, method_name)
7
+ end
8
+ end
9
+
10
+ def tracked_class_methods(*method_names)
11
+ method_names.each do |method_name|
12
+ class_interceptor = const_get("#{timeasure_name}ClassInterceptor")
13
+ add_method_to_interceptor(class_interceptor, method_name)
14
+ end
15
+ end
16
+
17
+ def timeasure_name
18
+ name.gsub('::', '_')
19
+ end
20
+
21
+ private
22
+
23
+ def add_method_to_interceptor(interceptor, method_name)
24
+ interceptor.class_eval do
25
+ define_method method_name do |*args, &block|
26
+ Timeasure.measure(klass_name: interceptor.klass_name.to_s, method_name: method_name.to_s) do
27
+ super(*args, &block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ module Timeasure
2
+ class Configuration
3
+ attr_accessor :post_measuring_proc, :rescue_proc, :enable_timeasure_proc,
4
+ :reported_methods_handler_set_proc, :reported_methods_handler_get_proc
5
+
6
+ def initialize
7
+ @post_measuring_proc = lambda do |measurement|
8
+ # Enables the configuration of what to do with each method runtime measurement.
9
+ # By default it reports to Timeasure's Profiling Manager.
10
+
11
+ Timeasure::Profiling::Manager.report(measurement)
12
+ end
13
+
14
+ @rescue_proc = lambda do |e, klass|
15
+ # Enabled the configuration of post_measuring_proc rescue.
16
+ end
17
+
18
+ @enable_timeasure_proc = lambda do
19
+ # Enables toggling Timeasure's activation (e.g. for disabling Timeasure for RSpec).
20
+
21
+ true
22
+ end
23
+
24
+ @reported_methods_handler_set_proc = lambda do |reported_methods_handler|
25
+ # Enables configuring where to store the ReportedMethodsHandler instance.
26
+ # This proc will be called by Timeasure::Profiling::Manager.prepare.
27
+ # By default it stores the handler as a class instance variable (in Timeasure::Profiling::Manager)
28
+
29
+ @reported_methods_handler = reported_methods_handler
30
+ end
31
+
32
+ @reported_methods_handler_get_proc = lambda do
33
+ # Enables configuring where to fetch the ReportedMethodsHandler instance.
34
+ # This proc will be called by Timeasure::Profiling::Manager.report and Timeasure::Profiling::Manager.export.
35
+ # By default it fetches the handler from the class instance variable
36
+ # (see @reported_methods_handler_set_proc).
37
+
38
+ @reported_methods_handler
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ module Timeasure
2
+ class Measurement
3
+ attr_reader :klass_name, :method_name, :segment, :metadata, :t0, :t1
4
+
5
+ def initialize(klass_name:, method_name:, t0:, t1:, segment: nil, metadata: nil)
6
+ @klass_name = klass_name
7
+ @method_name = method_name
8
+ @t0 = t0
9
+ @t1 = t1
10
+ @segment = segment
11
+ @metadata = metadata
12
+ end
13
+
14
+ def runtime_in_milliseconds
15
+ (@t1 - @t0) * 1000
16
+ end
17
+
18
+ def full_path
19
+ @segment.nil? ? method_path : "#{method_path}:#{@segment}"
20
+ end
21
+
22
+ def method_path
23
+ "#{@klass_name}##{@method_name}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+ require_relative 'reported_methods_handler'
3
+ require_relative 'reported_method'
4
+
5
+ module Timeasure
6
+ module Profiling
7
+ class Manager
8
+ class << self
9
+ def prepare
10
+ Timeasure.configuration.reported_methods_handler_set_proc.call(ReportedMethodsHandler.new)
11
+ end
12
+
13
+ def report(measurement)
14
+ handler = reported_methods_handler
15
+ handler.nil? ? warn_unprepared_handler : handler.report(measurement)
16
+ end
17
+
18
+ def export
19
+ handler = reported_methods_handler
20
+ handler.nil? ? warn_unprepared_handler : handler.export
21
+ end
22
+
23
+ private
24
+
25
+ def reported_methods_handler
26
+ Timeasure.configuration.reported_methods_handler_get_proc.call
27
+ end
28
+
29
+ def warn_unprepared_handler
30
+ logger.warn("#{self} is not prepared. Call Timeasure::Profiling::Manager.prepare before trying to report measurements or export reported methods.")
31
+ end
32
+
33
+ def logger
34
+ @logger ||= Logger.new(STDOUT)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module Timeasure
2
+ module Profiling
3
+ class ReportedMethod
4
+ attr_reader :klass_name, :method_name, :segment, :metadata, :full_path, :method_path, :runtime_sum, :call_count
5
+
6
+ def initialize(measurement)
7
+ @klass_name = measurement.klass_name
8
+ @method_name = measurement.method_name
9
+ @segment = measurement.segment
10
+ @metadata = measurement.metadata
11
+ @full_path = measurement.full_path
12
+ @method_path = measurement.method_path
13
+
14
+ @runtime_sum = 0
15
+ @call_count = 0
16
+ end
17
+
18
+ def increment_runtime_sum(runtime)
19
+ @runtime_sum += runtime
20
+ end
21
+
22
+ def increment_call_count
23
+ @call_count += 1
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ module Timeasure
2
+ module Profiling
3
+ class ReportedMethodsHandler
4
+ def initialize
5
+ @reported_methods = {}
6
+ end
7
+
8
+ def report(measurement)
9
+ initialize_path_for(measurement) if path_uninitialized_for(measurement)
10
+
11
+ @reported_methods[measurement.full_path].increment_runtime_sum(measurement.runtime_in_milliseconds)
12
+ @reported_methods[measurement.full_path].increment_call_count
13
+ end
14
+
15
+ def export
16
+ @reported_methods.values
17
+ end
18
+
19
+ private
20
+
21
+ def path_uninitialized_for(measurement)
22
+ @reported_methods[measurement.full_path].nil?
23
+ end
24
+
25
+ def initialize_path_for(measurement)
26
+ @reported_methods[measurement.full_path] = ReportedMethod.new(measurement)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Timeasure
2
+ VERSION = '0.1.0'
3
+ end
data/timeasure.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'timeasure/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'timeasure'
7
+ spec.version = Timeasure::VERSION
8
+ spec.authors = ['Eliav Lavi']
9
+ spec.email = ['eliav@riskified.com', 'eliavlavi@gmail.com']
10
+ spec.summary = 'Transparent method-level wrapper for profiling purposes'
11
+ spec.description = <<-DESCRIPTION
12
+ Timeasure is a Ruby gem that allows measuring the runtime of methods
13
+ without having to alter the code of the methods themselves.
14
+ DESCRIPTION
15
+ spec.homepage = 'https://github.com/riskified/timeasure'
16
+ spec.license = 'MIT'
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.start_with? 'spec/' }
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^spec/})
20
+ spec.require_paths = ['lib', 'lib/timeasure', 'lib/timeasure/profiling']
21
+
22
+ spec.required_ruby_version = '>= 2.0'
23
+ spec.add_development_dependency 'bundler', '~> 1.6'
24
+ spec.add_development_dependency 'coveralls'
25
+ spec.add_development_dependency 'rake', '~> 12.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.6'
27
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timeasure
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eliav Lavi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coveralls
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.6'
69
+ description: |2
70
+ Timeasure is a Ruby gem that allows measuring the runtime of methods
71
+ without having to alter the code of the methods themselves.
72
+ email:
73
+ - eliav@riskified.com
74
+ - eliavlavi@gmail.com
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - ".rspec"
81
+ - ".rubocop.yml"
82
+ - Gemfile
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - lib/timeasure.rb
87
+ - lib/timeasure/class_methods.rb
88
+ - lib/timeasure/configuration.rb
89
+ - lib/timeasure/measurement.rb
90
+ - lib/timeasure/profiling/manager.rb
91
+ - lib/timeasure/profiling/reported_method.rb
92
+ - lib/timeasure/profiling/reported_methods_handler.rb
93
+ - lib/timeasure/version.rb
94
+ - timeasure.gemspec
95
+ homepage: https://github.com/riskified/timeasure
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ - lib/timeasure
104
+ - lib/timeasure/profiling
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '2.0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.6.14
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Transparent method-level wrapper for profiling purposes
121
+ test_files: []