time_method 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f772b3b225ddfb7f9ea1139a0f5ee224473361d7
4
+ data.tar.gz: 077a6d1cb862368364e73d7a9e4fb18262b2d70e
5
+ SHA512:
6
+ metadata.gz: 90d6af20d3084cd37f347bf9cee0ba96f8dc7d14d11e7b3590d21061894e4d48fe0cb16a789b3cbcb92fbb76dbe69cf36651ffb92dbfad97b2db5c5b6997c826
7
+ data.tar.gz: b9efdcceb0b84bf72079df9ca46de7cf01570df15c5275a8d0eeb6af0acc14ad60039c49aa2654818e52ca21fcdca9a84f450ff97ca7d177476f96aa442942ba
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.5
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in time_method.gemspec
6
+ gemspec
7
+
@@ -0,0 +1,50 @@
1
+ # TimeMethod
2
+
3
+
4
+ TimeMethod is a gem that makes it easy to see the run-time of different methods within Terminal
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'time_method'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install time_method
22
+
23
+ ## Usage
24
+
25
+
26
+ TimeMethod is built upon the excellent gem made here [here](https://github.com/Riskified/timeasure)
27
+
28
+ You can visit the above page for more details on usage. This version has some functionality trimmed down
29
+ and some functionality added. The focus is on development profiling of methods.
30
+
31
+ It outputs two tables at the end of a request/test being run.
32
+
33
+ 1) A list of methods sorted by total run time
34
+
35
+ 2) A list of methods sorted by total execution order
36
+
37
+ ![Table image 1](img_1.png)
38
+
39
+ In order to show these tables, call
40
+ ```StoreMeasurement.instance.print_all```
41
+ at the end of your request.
42
+
43
+ You can also create a middleware to do this.
44
+
45
+ ## Development
46
+
47
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
48
+
49
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
50
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
Binary file
@@ -0,0 +1,85 @@
1
+ require_relative "lib/class_methods"
2
+ require_relative "lib/configuration"
3
+ require_relative "lib/measurement"
4
+
5
+ module TimeMethod
6
+ class << self
7
+
8
+ def configure
9
+ yield(configuration)
10
+ end
11
+
12
+ def measure(klass_name: nil, method_name: nil)
13
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
+ StoreMeasurement.instance.add_to_stack(
15
+ "in",klass_name,method_name
16
+ )
17
+ block_return_value = yield if block_given?
18
+ StoreMeasurement.instance.add_to_stack(
19
+ "out", klass_name, method_name
20
+ )
21
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
+ begin
23
+ measurement = TimeMethod::Measurement.new(
24
+ klass_name: klass_name.to_s,
25
+ method_name: method_name.to_s,
26
+ t0: t0,
27
+ t1: t1
28
+ )
29
+ rescue => e
30
+ puts e,e.backtrace[0..3]
31
+ end
32
+
33
+ block_return_value
34
+ end
35
+
36
+ def print_all_run_times
37
+ StoreMeasurement.instance.print_all
38
+ end
39
+
40
+ def configuration
41
+ @configuration ||= Configuration.new
42
+ end
43
+
44
+ def included(base_class)
45
+ base_class.extend ClassMethods
46
+ # below creates two modules and then makes
47
+ # them accessible through a constant name
48
+ instance_interceptor = const_set(
49
+ instance_interceptor_name_for(base_class),
50
+ interceptor_module_for(base_class)
51
+ )
52
+ class_interceptor = const_set(
53
+ class_interceptor_name_for(base_class),
54
+ interceptor_module_for(base_class)
55
+ )
56
+
57
+ return unless should_run_and_time_methods?
58
+
59
+ base_class.prepend instance_interceptor
60
+ base_class.singleton_class.prepend class_interceptor
61
+ end
62
+
63
+ def instance_interceptor_name_for(base_class)
64
+ "#{base_class.time_method_name}InstanceInterceptor"
65
+ end
66
+
67
+ def class_interceptor_name_for(base_class)
68
+ "#{base_class.time_method_name}ClassInterceptor"
69
+ end
70
+
71
+
72
+ def interceptor_module_for(base_class)
73
+ Module.new do
74
+ @klass_name = base_class
75
+ def self.klass_name
76
+ @klass_name
77
+ end
78
+ end
79
+ end
80
+
81
+ def should_run_and_time_methods?
82
+ configuration.enable_time_method
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,52 @@
1
+ load "#{Rails.root}/lib/time_method/store_measurement.rb"
2
+ module TimeMethod
3
+ module ClassMethods
4
+
5
+ def time_method_name
6
+ name.gsub("::","_")
7
+ end
8
+
9
+ def tracked_instance_methods(*method_names)
10
+ method_names.each do |method_name|
11
+ add_method_to_interceptor(instance_interceptor,method_name)
12
+ end
13
+ end
14
+
15
+ def tracked_class_methods(*method_names)
16
+ method_names.each do |method_name|
17
+ add_method_to_interceptor(class_interceptor,method_name)
18
+ end
19
+ end
20
+ def tracked_private_instance_methods(*method_names)
21
+ tracked_instance_methods(*method_names)
22
+ method_names.each { |method_name| private_interceptor_method(instance_interceptor,method_name)}
23
+ end
24
+
25
+ def tracked_private_class_methods(*method_namess)
26
+ tracked_class_methods(*method_names)
27
+ method_names.each { |method_name| private_interceptor_method(class_interceptor,method_name)}
28
+ end
29
+
30
+ def privatize_interceptor_method(interceptor,method_name)
31
+ interceptor.class_eval {private method_name}
32
+ end
33
+
34
+ def instance_interceptor
35
+ const_get("#{time_method_name}InstanceInterceptor")
36
+ end
37
+
38
+ def class_interceptor
39
+ const_get("#{time_method_name}ClassInterceptor")
40
+ end
41
+
42
+ def add_method_to_interceptor(interceptor,method_name)
43
+ interceptor.class_eval do
44
+ define_method method_name do |*args, &block|
45
+ TimeMethod.measure(klass_name:interceptor.klass_name.to_s,method_name:method_name.to_s) do
46
+ super(*args,&block)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,8 @@
1
+ module TimeMethod
2
+ class Configuration
3
+ attr_accessor :enable_time_method
4
+ def initialize
5
+ @enable_time_method = true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ module TimeMethod
2
+ class Measurement
3
+ attr_accessor :klass_name, :method_name, :segment, :metadata, :t0, :t1,:time
4
+ def initialize(klass_name:, method_name:, t0:, t1:)
5
+ @klass_name = klass_name
6
+ @method_name = method_name
7
+ @t0 = t0
8
+ @t1 = t1
9
+ # @time = runtime_ms
10
+ @time = runtime_seconds
11
+ store_measurement
12
+ end
13
+
14
+ def store_measurement
15
+ StoreMeasurement.instance.store(klass_name:@klass_name,method_name:@method_name,time:@time)
16
+ end
17
+
18
+ def output_stack
19
+ StoreMeasurement.instance.output_stack
20
+ end
21
+
22
+ def runtime
23
+ @runtime_in_milliseconds ||= ((@t1 - @t0) * 1000).round(2)
24
+ end
25
+
26
+ def runtime_ms
27
+ @runtime_in_milliseconds ||= ((@t1 - @t0) * 1000).round(2)
28
+ end
29
+
30
+ def runtime_seconds
31
+ @runtime_in_seconds ||= (@t1 - @t0).round(2)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,93 @@
1
+ module TimeMethod
2
+ class StoreMeasurement
3
+ include Singleton
4
+ def initialize
5
+ @time_for_method = []
6
+ @methods_in_order = []
7
+ @depth = 0
8
+ @full_stack = []
9
+ end
10
+
11
+ def add_to_stack(in_or_out,klass_name,method_name)
12
+ @depth+=1 if in_or_out == "in"
13
+ @depth-=1 if in_or_out == "out"
14
+ mod_klass_name=klass_name.split("::").last
15
+ name="#{mod_klass_name}.#{method_name}"
16
+ end
17
+
18
+ # can add some logic here when/while storing as well
19
+ def store(klass_name:,method_name:,time:)
20
+ mod_klass_name=klass_name.split("::").last
21
+ name="#{mod_klass_name}.#{method_name}"
22
+ @time_for_method.push([name,time,@depth])
23
+ end
24
+
25
+ def make_summary_arr(sort_by:)
26
+ updated_time_for_method = @time_for_method.map{|x| [x[0],(x[1].real*1000).round(2)," "*x[2]]}
27
+ h=updated_time_for_method.group_by{|a| a[0]}
28
+ new_h={}
29
+ h.each do |k,v|
30
+ sum = 0
31
+ count=0
32
+ v.each do |el|
33
+ sum+=el[1]
34
+ count+=1
35
+ end
36
+ avg = (sum/count)
37
+ tabs = v[0][2]
38
+ new_h[k]=[sum,count,avg,tabs]
39
+ end
40
+ new_arr=[]
41
+ new_h.each do |k,v|
42
+ k_with_tabs = v[3]+k
43
+ method_and_class_name=k_with_tabs.scan(/[a-zA-Z::_0-9\t ]+/)
44
+ new_arr.push([*method_and_class_name,*v])
45
+ end
46
+
47
+ if sort_by == "run_time"
48
+ new_arr.map! {|x| [x[0].gsub(" ",""),x[1],x[2].round(0),x[3].round(0),x[4].round(0)]}
49
+ new_arr.sort! {|a,b| b[2] <=> a[2]}
50
+ title = "Sorted List of Methods By Total Run Time"
51
+ elsif sort_by == "execution_order"
52
+ new_arr.map! {|x| [x[0],x[1],x[2].round(0),x[3].round(0),x[4].round(0)]}
53
+ new_arr = new_arr.reverse
54
+ title = "Sorted List of Methods By Total Execution Order"
55
+ end
56
+
57
+ headings=[ "Class Name", "Method Name", "Total Run Time (ms)","# of Calls","Average Time Per Call (ms)"]
58
+ table = Terminal::Table.new :title => title ,:headings => headings do |t|
59
+ t.rows = new_arr
60
+ end
61
+ return table
62
+ end
63
+
64
+ def make_summary_arr_run_time
65
+ @summary_arr = make_summary_arr(sort_by:"run_time")
66
+ end
67
+
68
+ def print_summary_arr_run_time
69
+ puts @summary_arr
70
+ end
71
+
72
+
73
+ def make_summary_arr_execution_order
74
+ @summary_arr_execution_order = make_summary_arr(sort_by:"execution_order")
75
+ end
76
+
77
+ def print_summary_arr_execution_order
78
+ puts @summary_arr_execution_order
79
+ end
80
+
81
+ def print_summary_arr
82
+ puts @summary_arr
83
+ end
84
+
85
+ def print_all
86
+ make_summary_arr_run_time
87
+ make_summary_arr_execution_order
88
+ print_summary_arr_run_time
89
+ print_summary_arr_execution_order
90
+ @time_for_method=[]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,3 @@
1
+ module TimeMethod
2
+ VERSION = '0.1.0'
3
+ end
@@ -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.
@@ -0,0 +1,29 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "time_method/version.rb"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "time_method"
8
+ spec.version = TimeMethod::VERSION
9
+ spec.authors = ["Seyon Vasantharajan"]
10
+ spec.email = ["seyon.vasantharajan@gmail.com"]
11
+
12
+ spec.summary = %q{Easily set methods to profile and view run-times in terminal }
13
+ spec.description = <<-DESCRIPTION
14
+ Time Method allows easy setting of runtime without having to alter
15
+ the code of the methods and also allows
16
+ DESCRIPTION
17
+ spec.homepage = "https://github.com/seyonv/time_method"
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib","lib/time_method"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "terminal-table"
29
+ end
@@ -0,0 +1,85 @@
1
+ require_relative "time_method/class_methods"
2
+ require_relative "time_method/configuration"
3
+ require_relative "time_method/measurement"
4
+
5
+ module TimeMethod
6
+ class << self
7
+
8
+ def configure
9
+ yield(configuration)
10
+ end
11
+
12
+ def measure(klass_name: nil, method_name: nil)
13
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
+ StoreMeasurement.instance.add_to_stack(
15
+ "in",klass_name,method_name
16
+ )
17
+ block_return_value = yield if block_given?
18
+ StoreMeasurement.instance.add_to_stack(
19
+ "out", klass_name, method_name
20
+ )
21
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
+ begin
23
+ measurement = TimeMethod::Measurement.new(
24
+ klass_name: klass_name.to_s,
25
+ method_name: method_name.to_s,
26
+ t0: t0,
27
+ t1: t1
28
+ )
29
+ rescue => e
30
+ puts e,e.backtrace[0..3]
31
+ end
32
+
33
+ block_return_value
34
+ end
35
+
36
+ def print_all_run_times
37
+ StoreMeasurement.instance.print_all
38
+ end
39
+
40
+ def configuration
41
+ @configuration ||= Configuration.new
42
+ end
43
+
44
+ def included(base_class)
45
+ base_class.extend ClassMethods
46
+ # below creates two modules and then makes
47
+ # them accessible through a constant name
48
+ instance_interceptor = const_set(
49
+ instance_interceptor_name_for(base_class),
50
+ interceptor_module_for(base_class)
51
+ )
52
+ class_interceptor = const_set(
53
+ class_interceptor_name_for(base_class),
54
+ interceptor_module_for(base_class)
55
+ )
56
+
57
+ return unless should_run_and_time_methods?
58
+
59
+ base_class.prepend instance_interceptor
60
+ base_class.singleton_class.prepend class_interceptor
61
+ end
62
+
63
+ def instance_interceptor_name_for(base_class)
64
+ "#{base_class.time_method_name}InstanceInterceptor"
65
+ end
66
+
67
+ def class_interceptor_name_for(base_class)
68
+ "#{base_class.time_method_name}ClassInterceptor"
69
+ end
70
+
71
+
72
+ def interceptor_module_for(base_class)
73
+ Module.new do
74
+ @klass_name = base_class
75
+ def self.klass_name
76
+ @klass_name
77
+ end
78
+ end
79
+ end
80
+
81
+ def should_run_and_time_methods?
82
+ configuration.enable_time_method
83
+ end
84
+ end
85
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_method
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Seyon Vasantharajan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-02-13 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.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: terminal-table
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: " Time Method allows easy setting of runtime without
70
+ having to alter \n the code of the methods and also allows\n"
71
+ email:
72
+ - seyon.vasantharajan@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - README.md
82
+ - Rakefile
83
+ - img_1.png
84
+ - lib/time_method.rb
85
+ - lib/time_method/class_methods.rb
86
+ - lib/time_method/configuration.rb
87
+ - lib/time_method/measurement.rb
88
+ - lib/time_method/store_measurement.rb
89
+ - lib/time_method/version.rb
90
+ - license.txt
91
+ - time_method.gemspec
92
+ - time_method.rb
93
+ homepage: https://github.com/seyonv/time_method
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ - lib/time_method
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.6.10
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Easily set methods to profile and view run-times in terminal
117
+ test_files: []