cuke-step-bm 1.0.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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea/*
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ source "http://rubygems.org"
data/README.rdoc ADDED
@@ -0,0 +1,32 @@
1
+ == Cucumber steps time-consuming
2
+
3
+ figure out which steps are slow.
4
+
5
+ == Configuration
6
+
7
+ * config/cuke_step_bm.rb or ~/.cuke_step_bm
8
+
9
+ output_mode:
10
+ # :bm => BenchMark(only for display)
11
+ # :std => SimpleTimeDiff
12
+ # :std_with_log => SimpleTimeDiff log
13
+ # :off => Cucumber default do nothing
14
+
15
+ CukeStepBm.configure do |config|
16
+ config.root = "/tmp"
17
+ config.output_mode = :std_with_log
18
+ config.log_file = File.join(config.root, 'steps_consuming.bms')
19
+ config.delimiter = "-#{[20879].pack("U*")}-"
20
+ end
21
+
22
+ == Command
23
+
24
+ cuke-step-bm -h for help
25
+
26
+ == TodoList Working in process
27
+
28
+ * add spec test
29
+ * add pp
30
+ * add color
31
+ * refator for something
32
+ * ..
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/cuke-step-bm ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
3
+
4
+ require "cuke-step-bm"
5
+
6
+ CukeStepBm::Cli.execute(ARGV.dup)
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "cuke-step-bm"
6
+ s.version = "1.0.0"
7
+ s.authors = ["elvuel"]
8
+ s.email = ["elvuel@gmail.com"]
9
+ s.homepage = "https://github.com/elvuel"
10
+ s.summary = %q{cucumber steps benchmark}
11
+ s.description = %q{cucumber steps benchmark}
12
+
13
+ s.rubyforge_project = "cuke-step-bm"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ # s.add_development_dependency "rspec"
22
+ # s.add_runtime_dependency "rest-client"
23
+ end
@@ -0,0 +1,4 @@
1
+ 1-冏-step1-冏-features/test.feature:1
2
+ 2-冏-step1-冏-features/test.feature:2
3
+ 3-冏-step3-冏-features/test.feature:3
4
+ 20-冏-step4-冏-features/test.feaDture:4
File without changes
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+ require "cuke-step-bm/cli"
3
+
4
+ module CukeStepBm
5
+ # cuke_step_bm bm-cuke-step cuke-step-bm.rb
6
+ VERSION = "0.0.1".freeze
7
+
8
+ # :bm => BenchMark(only for display)
9
+ # :std => SimpleTimeDiff
10
+ # :std_with_log => SimpleTimeDiff log
11
+ # :off => Cucumber default do nothing
12
+
13
+ BM_SUPPORTED_OUTPUT_MODES = [:bm, :std, :std_with_log, :off]
14
+
15
+ class << self
16
+ attr_accessor :root, :log_file, :output_mode, :delimiter
17
+
18
+ def configure
19
+ yield self
20
+ end
21
+
22
+ def suite!
23
+ use_defaults!
24
+ paths = [
25
+ File.expand_path("config/cuke_step_bm.rb", root),
26
+ File.expand_path(".cuke_step_bm", root)
27
+ ]
28
+ paths.each { |path| load(path) if File.exist?(path) }
29
+ self.output_mode = :std unless BM_SUPPORTED_OUTPUT_MODES.include? output_mode
30
+ end
31
+
32
+ def use_defaults!
33
+ configure do |config|
34
+ config.root = File.expand_path('.', Dir.pwd)
35
+ config.output_mode = :std
36
+ config.log_file = File.join(config.root, 'features', 'steps_consuming.bms')
37
+ config.delimiter = "-#{[20879].pack("U*")}-"
38
+ end
39
+ end
40
+
41
+ def write_to_log(msg)
42
+ File.open(log_file, "a+") { |f| f.write msg }
43
+ rescue
44
+ nil
45
+ end
46
+
47
+ #remove log file before cuke working with :std_with_log
48
+ def remove_log!
49
+ File.delete log_file if File.exist?(log_file) && (output_mode == :std_with_log)
50
+ rescue Exception => e
51
+ warn e.message
52
+ end
53
+
54
+ end # class << self
55
+ end # CucumberStepsBm
56
+
57
+ CukeStepBm.suite!
58
+
59
+ if defined?(Cucumber) && defined?(Cucumber::VERSION) && (Cucumber::VERSION >= "1.1.1") && (CukeStepBm.output_mode != :off)
60
+ CukeStepBm.remove_log!
61
+
62
+ module Cucumber
63
+ module Ast
64
+ class StepInvocation #:nodoc:
65
+ def invoke(step_mother, configuration)
66
+ exec_proc = Proc.new {
67
+ find_step_match!(step_mother, configuration)
68
+ unless @skip_invoke || configuration.dry_run? || @exception || @step_collection.exception
69
+ @skip_invoke = true
70
+ begin
71
+ @step_match.invoke(@multiline_arg)
72
+ step_mother.after_step
73
+ status!(:passed)
74
+ rescue Pending => e
75
+ failed(configuration, e, false)
76
+ status!(:pending)
77
+ rescue Undefined => e
78
+ failed(configuration, e, false)
79
+ status!(:undefined)
80
+ rescue Cucumber::Ast::Table::Different => e
81
+ @different_table = e.table
82
+ failed(configuration, e, false)
83
+ status!(:failed)
84
+ rescue Exception => e
85
+ failed(configuration, e, false)
86
+ status!(:failed)
87
+ end
88
+ end
89
+ }
90
+
91
+ if (CukeStepBm.output_mode == :bm) && defined?(Benchmark)
92
+ Benchmark.bm do |reporter|
93
+ reporter.report("Time consuming:") { exec_proc.call }
94
+ end
95
+ else
96
+ time_begin = Time.now
97
+ exec_proc.call
98
+ time_end = Time.now
99
+ time_for_output = "Step consume %s seconds.\n" % ["#{time_end - time_begin}"]
100
+ time_consuming_message = ["#{time_end - time_begin}", @name, file_colon_line].join(CukeStepBm.delimiter)
101
+ time_consuming_message << "\n"
102
+ if CukeStepBm.output_mode == :std_with_log
103
+ puts time_for_output
104
+ CukeStepBm.write_to_log time_consuming_message
105
+ else
106
+ puts time_for_output
107
+ end
108
+ end
109
+ end # invoke
110
+
111
+ end # StepInvocation
112
+ end # Ast
113
+ end # Cucumber
114
+ end
@@ -0,0 +1,271 @@
1
+ # encoding: utf-8
2
+
3
+ require 'optparse'
4
+ #require 'ostruct'
5
+
6
+ module CukeStepBm
7
+ class Cli
8
+
9
+ class Options
10
+ #SCOPES = [:step, :feature]
11
+ def parse!(args)
12
+ options = {}
13
+ opt_parser = OptionParser.new("", 30, ' ') do |opts|
14
+ opts.banner = "Usage: cuke-step-bm options"
15
+
16
+ opts.on("-f", "--feature FEATURE", String, "In specify feature") do |feature|
17
+ options[:feature] = feature
18
+ end
19
+
20
+ opts.on("-M", "--most", "Show the most time-consuming step") do
21
+ options[:act] = [ :most ]
22
+ end
23
+
24
+ opts.on("-t", "--total", "Show the total time-consuming") do
25
+ options[:act] = [ :total ]
26
+ end
27
+
28
+ opts.on("-w", "--within from,to", Array, "Show the steps time-consuming within the given range (use: -w 1,2)") do |from_to|
29
+ if from_to.size < 2
30
+ puts "wrong argument size"
31
+ exit
32
+ end
33
+ options[:act] = [ :within, [from_to.first, from_to.last] ]
34
+ end
35
+
36
+ opts.on("-l", "--less VALUE", Float, "Show the steps time-consuming less than or equal the given") do |v|
37
+ options[:act] = [ :less, v ]
38
+ end
39
+
40
+ opts.on("-m", "--more VALUE", Float, "Show the steps time-consuming more than or equal the given") do |v|
41
+ options[:act] = [ :more, v ]
42
+ end
43
+
44
+ #opts.on("-s", "--scope value", "Show messages within scope (all/feature_filepath)") do |v|
45
+ # v = v.to_sym
46
+ # v = :step unless SCOPES.include? v
47
+ # options[:scope] = v
48
+ #end
49
+
50
+ opts.separator ""
51
+ opts.separator "Common options:"
52
+
53
+ opts.on_tail("-h", "--help", "Show this usage message") do
54
+ puts opts
55
+ exit
56
+ end
57
+
58
+ opts.on_tail("-v", "--version", "Show version") do
59
+ puts "cuke-step-bm #{CukeStepBm::VERSION}"
60
+ exit
61
+ end
62
+ end
63
+ opt_parser.parse! args
64
+ options
65
+ end
66
+ end # Options
67
+
68
+
69
+ def self.execute(args)
70
+ new(args).execute
71
+ end
72
+
73
+ #attr_reader :opt_parser
74
+
75
+ def initialize(args)
76
+ @config = CukeStepBm
77
+ @log_file = @config.log_file
78
+ bm_validate!
79
+ @options = Options.new.parse! args
80
+ @options = default_options.merge @options
81
+ @options[:act] = [ :most ] unless @options[:act]
82
+ #@scope = @options.delete :scope
83
+ end
84
+
85
+ def execute
86
+ parse_bms!
87
+ self.send *@options[:act]
88
+ end
89
+
90
+ private
91
+ def most
92
+ the_most = @bms.sort_by { |item| item[:consume] }.last
93
+ if in_feature?
94
+ msg = "The most time-consuming in %s:\n\tLine: %s, Step: [ %s ], take %s seconds." % [
95
+ msg_color(the_most[:feature], "red"),
96
+ the_most[:line],
97
+ msg_color(the_most[:step], "red"),
98
+ msg_color(the_most[:consume])
99
+ ]
100
+ info(msg)
101
+ else
102
+ msg = "The most time-consuming in all features:In %s, Line: %s, Step: [ %s ], take %s seconds.\n\n" % [
103
+ msg_color(the_most[:feature], "red"),
104
+ the_most[:line],
105
+ msg_color(the_most[:step], "red"),
106
+ msg_color(the_most[:consume])
107
+ ]
108
+ info(msg)
109
+ feature_grp_hash = @bms.group_by { |item| item[:feature] }
110
+ feature_grp_hash.each do |feature, value|
111
+ the_most = value.sort_by { |item| item[:consume] }.last
112
+ msg = "In feature [ %s ]\n\tLine: %s, Step: [ %s ], take %s seconds.\n\n" % [
113
+ msg_color(the_most[:feature] || feature, "red"),
114
+ the_most[:line],
115
+ msg_color(the_most[:step], "red"),
116
+ msg_color(the_most[:consume])
117
+ ]
118
+ info(msg)
119
+ end # grp_hash
120
+
121
+ end # in_feature?
122
+ end # most
123
+
124
+ def total
125
+ t_ary = @bms.collect { |item| item[:consume] }
126
+ sum = t_ary.inject(:+)
127
+ if in_feature?
128
+ feature = @bms.first[:feature]
129
+ info "Feature %s, %s steps total consume: %s seconds." % [msg_color(feature), msg_color(t_ary.size), msg_color(sum)]
130
+ else
131
+ msg = "Total consume: %s seconds.\n\n" % msg_color(sum)
132
+ info msg
133
+ feature_grp_hash = @bms.group_by { |item| item[:feature] }
134
+ feature_grp_hash.each do |feature, value|
135
+ t_ary = value.collect { |item| item[:consume] }
136
+ sum = t_ary.inject(:+)
137
+ msg = "\tFeature %s, %s steps total consume: %s seconds.\n\n" % [msg_color(feature), msg_color(t_ary.size), msg_color(sum)]
138
+ info msg
139
+ end
140
+ end # in_feature?
141
+ end # total
142
+
143
+ def within(args)
144
+ from, to = args.collect{ |arg| arg.to_f }
145
+ from, to = to, from if to < from
146
+ #grp_by = @bms.group_by { |item| in_feature? ? item[:step] : item[:feature] }
147
+ if in_feature?
148
+ grp_by_step = @bms.group_by { |item| item[:step] }
149
+ step_mean_hash= grp_by_step.inject({}) do |h, item|
150
+ key = item.shift
151
+ consumings = item.flatten.collect { |bm| bm[:consume] }
152
+ h[key] = consumings.inject(:+) / consumings.size
153
+ h
154
+ end
155
+ results = step_mean_hash.select { |k, v| (v >= from ) && (v <= to) }
156
+ feature = @bms.first[:feature]
157
+ unless results.empty?
158
+ info "In %s, Steps within %s .. %s" % [msg_color(feature), msg_color(from), msg_color(to)]
159
+ end
160
+ results.sort_by { |k, v| v }.each do |k, v|
161
+ info "\t Step %s, it average take %s seconds" % [msg_color(k), msg_color(v, "red")]
162
+ end
163
+ else
164
+ grp_by_feature = @bms.group_by { |item| item[:feature] }
165
+ grp_by_feature.each do |feature, all_steps|
166
+ grp_by_step = all_steps.group_by { |item| item[:step] }
167
+ step_mean_hash= grp_by_step.inject({}) do |h, item|
168
+ key = item.shift
169
+ consumings = item.flatten.collect { |bm| bm[:consume] }
170
+ h[key] = consumings.inject(:+) / consumings.size
171
+ h
172
+ end
173
+ results = step_mean_hash.select { |k, v| (v >= from ) && (v <= to) }
174
+ unless results.empty?
175
+ info "In %s, Steps within %s .. %s" % [msg_color(feature), msg_color(from), msg_color(to)]
176
+ end
177
+ results.sort_by { |k, v| v }.each do |k, v|
178
+ info "\t Step %s, it average take %s seconds" % [msg_color(k), msg_color(v, "red")]
179
+ end
180
+ end # grp_by_feature
181
+ end # in_feature?
182
+ end # within
183
+
184
+ def less_or_more(value, lom = "less")
185
+ value = value.to_f
186
+ if in_feature?
187
+ grp_by_step = @bms.group_by { |item| item[:step] }
188
+ step_mean_hash= grp_by_step.inject({}) do |h, item|
189
+ key = item.shift
190
+ consumings = item.flatten.collect { |bm| bm[:consume] }
191
+ h[key] = consumings.inject(:+) / consumings.size
192
+ h
193
+ end
194
+ results = step_mean_hash.select { |k, v| v.send((lom=="less") ? :<= : :>=, value) }
195
+ feature = @bms.first[:feature]
196
+ unless results.empty?
197
+ info "In %s, Steps %s than %s" % [msg_color(feature), msg_color(lom), msg_color(value)]
198
+ end
199
+ results.sort_by { |k, v| v }.each do |k, v|
200
+ info "\t Step %s, it average take %s seconds" % [msg_color(k), msg_color(v, "red")]
201
+ end
202
+ else
203
+ grp_by_feature = @bms.group_by { |item| item[:feature] }
204
+ grp_by_feature.each do |feature, all_steps|
205
+ grp_by_step = all_steps.group_by { |item| item[:step] }
206
+ step_mean_hash= grp_by_step.inject({}) do |h, item|
207
+ key = item.shift
208
+ consumings = item.flatten.collect { |bm| bm[:consume] }
209
+ h[key] = consumings.inject(:+) / consumings.size
210
+ h
211
+ end
212
+ results = step_mean_hash.select { |k, v| v.send((lom=="less") ? :<= : :>=, value) }
213
+ unless results.empty?
214
+ info "In %s, Steps %s than %s" % [msg_color(feature), msg_color(lom), msg_color(value)]
215
+ end
216
+ results.sort_by { |k, v| v }.each do |k, v|
217
+ info "\t Step %s, it average take %s seconds" % [msg_color(k), msg_color(v, "red")]
218
+ end
219
+ end
220
+ end # in_feature?
221
+ end # less_or_more
222
+
223
+ def less(value)
224
+ less_or_more(value, "less")
225
+ end
226
+
227
+ def more(value)
228
+ less_or_more(value, "more")
229
+ end
230
+
231
+ def default_options
232
+ { scope: :step, feature: :all }
233
+ end
234
+
235
+ def bm_validate!
236
+ abort "please make sure that record log file exist!" unless File.exist? @log_file
237
+ @bms ||= File.read(@log_file)
238
+ @bms.strip!
239
+ abort "record log file is empty!" if @bms.empty?
240
+ end
241
+
242
+ def parse_bms!
243
+ bms = @bms.split("\n")
244
+ bms.delete ""
245
+ bms.compact!
246
+ @bms = bms.inject([]) do |ary, item|
247
+ tmp_ary = item.split(@config.delimiter)
248
+ consume_time, step_name, file_colon_line = tmp_ary
249
+ feature, line = file_colon_line.split(":")
250
+ tmp_ary = { feature: feature, step: step_name, line: line, consume: consume_time.to_f }
251
+ ary << tmp_ary if @options[:feature].is_a?(Symbol) or (@options[:feature] == feature)
252
+ ary
253
+ end
254
+ abort msg_color("empty", "r") if @bms.empty?
255
+ end
256
+
257
+ def in_feature?
258
+ !@options[:feature].is_a?(Symbol)
259
+ end
260
+
261
+ def msg_color(msg, color="green")
262
+ color = (color == "green") ? 32 : 31
263
+ "\033[4;1;#{color};40m#{msg}\033[0m"
264
+ end
265
+
266
+ def info(msg)
267
+ puts msg
268
+ end
269
+
270
+ end
271
+ end
data/test.rb ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + '/lib') unless $:.include?(File.dirname(__FILE__) + '/lib')
3
+
4
+ require "cuke-step-bm"
5
+
6
+ CukeStepBm::Cli.execute(ARGV.dup)
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cuke-step-bm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - elvuel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-18 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: cucumber steps benchmark
15
+ email:
16
+ - elvuel@gmail.com
17
+ executables:
18
+ - cuke-step-bm
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - README.rdoc
25
+ - Rakefile
26
+ - bin/cuke-step-bm
27
+ - cuke-step-bm.gemspec
28
+ - features/steps_consuming.bms
29
+ - features/test.feature
30
+ - lib/cuke-step-bm.rb
31
+ - lib/cuke-step-bm/cli.rb
32
+ - test.rb
33
+ homepage: https://github.com/elvuel
34
+ licenses: []
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubyforge_project: cuke-step-bm
53
+ rubygems_version: 1.8.10
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: cucumber steps benchmark
57
+ test_files: []
58
+ has_rdoc: