cuke_sniffer 0.0.2 → 0.0.3
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/bin/cuke_sniffer.rb +11 -2
- data/lib/cuke_sniffer.rb +2 -0
- data/lib/cuke_sniffer/cli.rb +79 -11
- data/lib/cuke_sniffer/feature.rb +20 -10
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +69 -69
- data/lib/cuke_sniffer/report/markup.rhtml +16 -7
- data/lib/cuke_sniffer/rule_config.rb +183 -152
- data/lib/cuke_sniffer/rules_evaluator.rb +4 -1
- data/lib/cuke_sniffer/scenario.rb +32 -18
- data/lib/cuke_sniffer/step_definition.rb +75 -16
- metadata +20 -10
data/bin/cuke_sniffer.rb
CHANGED
@@ -6,8 +6,9 @@ Calling CukeSniffer with no arguments will run it against the current directory.
|
|
6
6
|
Other Options for Running include:
|
7
7
|
<feature_file_path>, <step_def_file_path> : Runs CukeSniffer against the
|
8
8
|
specified paths.
|
9
|
-
-o, --out
|
10
|
-
|
9
|
+
-o, --out <type> (name) : Where <type> is 'html' or 'xml'.
|
10
|
+
Runs CukeSniffer then outputs an
|
11
|
+
html/xml file in the current
|
11
12
|
directory (with optional name).
|
12
13
|
-h, --help : You get this lovely document."
|
13
14
|
|
@@ -41,6 +42,14 @@ if ARGV.include? "--out" or ARGV.include? "-o"
|
|
41
42
|
file_name = file_name + ".html" unless file_name =~ /\.html$/
|
42
43
|
cuke_sniffer.output_html(file_name)
|
43
44
|
end
|
45
|
+
when "xml"
|
46
|
+
file_name = ARGV[index + 2]
|
47
|
+
if file_name.nil?
|
48
|
+
cuke_sniffer.output_xml
|
49
|
+
else
|
50
|
+
file_name = file_name + ".xml" unless file_name =~ /\.xml$/
|
51
|
+
cuke_sniffer.output_xml(file_name)
|
52
|
+
end
|
44
53
|
else
|
45
54
|
print_results(cuke_sniffer)
|
46
55
|
end
|
data/lib/cuke_sniffer.rb
CHANGED
data/lib/cuke_sniffer/cli.rb
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
require 'erb'
|
2
|
+
require 'roxml'
|
2
3
|
|
3
4
|
module CukeSniffer
|
4
5
|
class CLI
|
5
6
|
include CukeSniffer::Constants
|
7
|
+
include ROXML
|
6
8
|
|
7
|
-
|
9
|
+
class SummaryNode
|
10
|
+
include ROXML
|
11
|
+
xml_accessor :score
|
12
|
+
xml_accessor :count
|
13
|
+
xml_accessor :average
|
14
|
+
xml_accessor :good
|
15
|
+
xml_accessor :bad
|
16
|
+
xml_accessor :threshold
|
17
|
+
end
|
18
|
+
|
19
|
+
xml_name "cuke_sniffer"
|
20
|
+
xml_accessor :features_summary, :as => SummaryNode
|
21
|
+
xml_accessor :scenarios_summary, :as => SummaryNode
|
22
|
+
xml_accessor :step_definitions_summary, :as => SummaryNode
|
23
|
+
xml_accessor :improvement_list, :as => {:key => "rule", :value => "total"}, :in => "improvement_list", :from => "improvement"
|
24
|
+
xml_accessor :features, :as => [CukeSniffer::Feature], :in => "features"
|
25
|
+
xml_accessor :step_definitions, :as => [CukeSniffer::StepDefinition], :in => "step_definitions"
|
26
|
+
|
27
|
+
attr_accessor :summary, :features_location, :step_definitions_location, :scenarios
|
8
28
|
|
9
29
|
def initialize(features_location = Dir.getwd, step_definitions_location = Dir.getwd)
|
10
30
|
@features_location = features_location
|
@@ -50,6 +70,21 @@ module CukeSniffer
|
|
50
70
|
catalog_step_calls
|
51
71
|
puts "\nAssessing Score: "
|
52
72
|
assess_score
|
73
|
+
@improvement_list = @summary[:improvement_list]
|
74
|
+
@features_summary = load_summary_data(@summary[:features])
|
75
|
+
@scenarios_summary = load_summary_data(@summary[:scenarios])
|
76
|
+
@step_definitions_summary = load_summary_data(@summary[:step_definitions])
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_summary_data(summary_hash)
|
80
|
+
summary_node = SummaryNode.new
|
81
|
+
summary_node.count = summary_hash[:total]
|
82
|
+
summary_node.score = summary_hash[:total_score]
|
83
|
+
summary_node.average = summary_hash[:average]
|
84
|
+
summary_node.threshold = summary_hash[:threshold]
|
85
|
+
summary_node.good = summary_hash[:good]
|
86
|
+
summary_node.bad = summary_hash[:bad]
|
87
|
+
summary_node
|
53
88
|
end
|
54
89
|
|
55
90
|
def good?
|
@@ -183,16 +218,27 @@ module CukeSniffer
|
|
183
218
|
output
|
184
219
|
end
|
185
220
|
|
221
|
+
def extract_steps_hash(scenario)
|
222
|
+
steps_hash = {}
|
223
|
+
counter = 1
|
224
|
+
scenario.steps.each do |step|
|
225
|
+
location = scenario.location.gsub(/:\d*$/, ":#{scenario.start_line + counter}")
|
226
|
+
steps_hash[location] = step
|
227
|
+
counter += 1
|
228
|
+
end
|
229
|
+
steps_hash
|
230
|
+
end
|
231
|
+
|
186
232
|
def get_all_steps
|
187
233
|
steps = {}
|
188
234
|
@features.each do |feature|
|
235
|
+
unless feature.background.nil?
|
236
|
+
background_steps = extract_steps_hash(feature.background)
|
237
|
+
background_steps.each_key { |key| steps[key] = background_steps[key] }
|
238
|
+
end
|
189
239
|
feature.scenarios.each do |scenario|
|
190
|
-
|
191
|
-
|
192
|
-
location = scenario.location.gsub(/:\d*$/, ":#{scenario.start_line + counter}")
|
193
|
-
steps[location] = step
|
194
|
-
counter += 1
|
195
|
-
end
|
240
|
+
scenario_steps = extract_steps_hash(scenario)
|
241
|
+
scenario_steps.each_key { |key| steps[key] = scenario_steps[key] }
|
196
242
|
end
|
197
243
|
end
|
198
244
|
@step_definitions.each do |definition|
|
@@ -215,12 +261,25 @@ module CukeSniffer
|
|
215
261
|
end
|
216
262
|
|
217
263
|
def get_dead_steps
|
218
|
-
|
264
|
+
dead_steps_hash = {}
|
219
265
|
@step_definitions.each do |step_definition|
|
220
|
-
|
266
|
+
location_match = step_definition.location.match(/(?<file>.*).rb:(?<line>\d+)/)
|
267
|
+
file_name = location_match[:file]
|
268
|
+
regex = step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex]
|
269
|
+
dead_steps_hash[file_name] ||= []
|
270
|
+
dead_steps_hash[file_name] << "#{location_match[:line]}: /#{regex}/" if step_definition.calls.empty?
|
221
271
|
end
|
222
|
-
|
223
|
-
|
272
|
+
total = 0
|
273
|
+
dead_steps_hash.each_key do |key|
|
274
|
+
unless dead_steps_hash[key] == []
|
275
|
+
total += dead_steps_hash[key].size
|
276
|
+
dead_steps_hash[key].sort_by! {|row| row[/^\d+/].to_i}
|
277
|
+
else
|
278
|
+
dead_steps_hash.delete(key)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
dead_steps_hash[:total] = total
|
282
|
+
dead_steps_hash
|
224
283
|
end
|
225
284
|
|
226
285
|
def extract_markup
|
@@ -242,5 +301,14 @@ module CukeSniffer
|
|
242
301
|
f.write(output)
|
243
302
|
end
|
244
303
|
end
|
304
|
+
|
305
|
+
def output_xml(file_name = "cuke_sniffer.xml")
|
306
|
+
doc = Nokogiri::XML::Document.new
|
307
|
+
doc.root = self.to_xml
|
308
|
+
open(file_name, "w") do |file|
|
309
|
+
file << doc.serialize
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
245
313
|
end
|
246
314
|
end
|
data/lib/cuke_sniffer/feature.rb
CHANGED
@@ -2,28 +2,38 @@ module CukeSniffer
|
|
2
2
|
class Feature < FeatureRulesEvaluator
|
3
3
|
include CukeSniffer::Constants
|
4
4
|
include CukeSniffer::RuleConfig
|
5
|
+
include ROXML
|
6
|
+
|
7
|
+
xml_accessor :scenarios, :as => [CukeSniffer::FeatureRulesEvaluator], :in => "scenarios"
|
5
8
|
|
6
9
|
SCENARIO_TITLE_REGEX = /#{COMMENT_REGEX}#{SCENARIO_TITLE_STYLES}(?<name>.*)/
|
7
10
|
|
8
|
-
attr_accessor :background, :scenarios, :scenarios_score
|
11
|
+
attr_accessor :background, :scenarios, :scenarios_score,:total_score
|
9
12
|
|
10
13
|
def initialize(file_name)
|
11
14
|
super(file_name)
|
12
15
|
@scenarios = []
|
13
|
-
@
|
16
|
+
@RULES_hash = {}
|
14
17
|
@scenarios_score = 0
|
15
18
|
@total_score = 0
|
16
|
-
|
17
|
-
|
19
|
+
feature_lines = extract_feature_from_file(file_name)
|
20
|
+
if feature_lines == []
|
21
|
+
store_rule(RULES[:empty_feature])
|
22
|
+
else
|
23
|
+
split_feature(file_name, feature_lines)
|
24
|
+
evaluate_score
|
25
|
+
end
|
18
26
|
end
|
19
27
|
|
20
|
-
def
|
28
|
+
def extract_feature_from_file(file_name)
|
21
29
|
feature_lines = []
|
22
|
-
|
23
30
|
feature_file = File.open(file_name)
|
24
31
|
feature_file.each_line { |line| feature_lines << line }
|
25
32
|
feature_file.close
|
33
|
+
feature_lines
|
34
|
+
end
|
26
35
|
|
36
|
+
def split_feature(file_name, feature_lines)
|
27
37
|
index = 0
|
28
38
|
until feature_lines[index].match /Feature:\s*(?<name>.*)/
|
29
39
|
update_tag_list(feature_lines[index])
|
@@ -87,20 +97,20 @@ module CukeSniffer
|
|
87
97
|
end
|
88
98
|
|
89
99
|
def rule_no_scenarios
|
90
|
-
store_rule(
|
100
|
+
store_rule(RULES[:no_scenarios]) if @scenarios.empty?
|
91
101
|
end
|
92
102
|
|
93
103
|
def rule_too_many_scenarios
|
94
|
-
rule =
|
104
|
+
rule = RULES[:too_many_scenarios]
|
95
105
|
store_rule(rule) if @scenarios.size >= rule[:max]
|
96
106
|
end
|
97
107
|
|
98
108
|
def rule_background_with_no_scenarios
|
99
|
-
store_rule(
|
109
|
+
store_rule( RULES[:background_with_no_scenarios]) if @scenarios.empty? and !@background.nil?
|
100
110
|
end
|
101
111
|
|
102
112
|
def rule_background_with_one_scenario
|
103
|
-
store_rule(
|
113
|
+
store_rule(RULES[:background_with_one_scenario]) if @scenarios.size == 1 and !@background.nil?
|
104
114
|
end
|
105
115
|
|
106
116
|
end
|
@@ -1,69 +1,69 @@
|
|
1
|
-
require 'cuke_sniffer/constants'
|
2
|
-
require 'cuke_sniffer/rule_config'
|
3
|
-
require 'cuke_sniffer/rules_evaluator'
|
4
|
-
|
5
|
-
module CukeSniffer
|
6
|
-
class FeatureRulesEvaluator < RulesEvaluator
|
7
|
-
include CukeSniffer::Constants
|
8
|
-
include CukeSniffer::RuleConfig
|
9
|
-
|
10
|
-
attr_accessor :tags, :name
|
11
|
-
|
12
|
-
def initialize(location)
|
13
|
-
@name = ""
|
14
|
-
@tags = []
|
15
|
-
super(location)
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_name(line, filter)
|
19
|
-
line.gsub!(/#{COMMENT_REGEX}#{filter}/, "")
|
20
|
-
line.strip!
|
21
|
-
@name += " " unless @name.empty? or line.empty?
|
22
|
-
@name += line
|
23
|
-
end
|
24
|
-
|
25
|
-
def update_tag_list(line)
|
26
|
-
if TAG_REGEX.match(line) && !is_comment?(line)
|
27
|
-
line.scan(TAG_REGEX).each { |tag| @tags << tag[0] }
|
28
|
-
else
|
29
|
-
@tags << line.strip unless line.empty?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def evaluate_score
|
34
|
-
super
|
35
|
-
cls_name = self.class.to_s.gsub('CukeSniffer::', '')
|
36
|
-
rule_too_many_tags(cls_name)
|
37
|
-
rule_no_description(cls_name)
|
38
|
-
rule_numbers_in_name(cls_name)
|
39
|
-
rule_long_name(cls_name)
|
40
|
-
end
|
41
|
-
|
42
|
-
def rule_too_many_tags(type)
|
43
|
-
rule =
|
44
|
-
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if tags.size >= rule[:max]
|
45
|
-
end
|
46
|
-
|
47
|
-
def rule_no_description(type)
|
48
|
-
rule =
|
49
|
-
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name.empty?
|
50
|
-
end
|
51
|
-
|
52
|
-
def rule_numbers_in_name(type)
|
53
|
-
rule =
|
54
|
-
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name =~ /\d/
|
55
|
-
end
|
56
|
-
|
57
|
-
def rule_long_name(type)
|
58
|
-
rule =
|
59
|
-
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name.size >= rule[:max]
|
60
|
-
end
|
61
|
-
|
62
|
-
def == (comparison_object)
|
63
|
-
super(comparison_object)
|
64
|
-
comparison_object.name == name
|
65
|
-
comparison_object.tags == tags
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
1
|
+
require 'cuke_sniffer/constants'
|
2
|
+
require 'cuke_sniffer/rule_config'
|
3
|
+
require 'cuke_sniffer/rules_evaluator'
|
4
|
+
|
5
|
+
module CukeSniffer
|
6
|
+
class FeatureRulesEvaluator < RulesEvaluator
|
7
|
+
include CukeSniffer::Constants
|
8
|
+
include CukeSniffer::RuleConfig
|
9
|
+
|
10
|
+
attr_accessor :tags, :name
|
11
|
+
|
12
|
+
def initialize(location)
|
13
|
+
@name = ""
|
14
|
+
@tags = []
|
15
|
+
super(location)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_name(line, filter)
|
19
|
+
line.gsub!(/#{COMMENT_REGEX}#{filter}/, "")
|
20
|
+
line.strip!
|
21
|
+
@name += " " unless @name.empty? or line.empty?
|
22
|
+
@name += line
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_tag_list(line)
|
26
|
+
if TAG_REGEX.match(line) && !is_comment?(line)
|
27
|
+
line.scan(TAG_REGEX).each { |tag| @tags << tag[0] }
|
28
|
+
else
|
29
|
+
@tags << line.strip unless line.empty?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def evaluate_score
|
34
|
+
super
|
35
|
+
cls_name = self.class.to_s.gsub('CukeSniffer::', '')
|
36
|
+
rule_too_many_tags(cls_name)
|
37
|
+
rule_no_description(cls_name)
|
38
|
+
rule_numbers_in_name(cls_name)
|
39
|
+
rule_long_name(cls_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def rule_too_many_tags(type)
|
43
|
+
rule = RULES[:too_many_tags]
|
44
|
+
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if tags.size >= rule[:max]
|
45
|
+
end
|
46
|
+
|
47
|
+
def rule_no_description(type)
|
48
|
+
rule = RULES[:no_description]
|
49
|
+
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def rule_numbers_in_name(type)
|
53
|
+
rule = RULES[:numbers_in_description]
|
54
|
+
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name =~ /\d/
|
55
|
+
end
|
56
|
+
|
57
|
+
def rule_long_name(type)
|
58
|
+
rule = RULES[:long_name]
|
59
|
+
store_updated_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if name.size >= rule[:max]
|
60
|
+
end
|
61
|
+
|
62
|
+
def == (comparison_object)
|
63
|
+
super(comparison_object)
|
64
|
+
comparison_object.name == name
|
65
|
+
comparison_object.tags == tags
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -209,13 +209,22 @@
|
|
209
209
|
|
210
210
|
<div class="sections">
|
211
211
|
<div name="dead_steps" class="shrink_section" id="dead_steps">
|
212
|
+
<% dead_steps = cuke_sniffer.get_dead_steps %>
|
213
|
+
<br>
|
212
214
|
<div style="font:bold;padding-left:3%;font:bold;font-size:14pt;">Total Dead
|
213
|
-
Steps: <%=
|
214
|
-
<%
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
215
|
+
Steps: <%= dead_steps[:total] %></div>
|
216
|
+
<% dead_steps.delete :total%>
|
217
|
+
<% dead_steps.each_key do |step_file| %>
|
218
|
+
<div style="font:bold;padding-left:3%;font-size:14pt;">
|
219
|
+
<%= step_file %>
|
220
|
+
<br>
|
221
|
+
<div style="padding-left:3%;font-size:12pt;">
|
222
|
+
<%dead_steps[step_file].each do |regex|%>
|
223
|
+
<%= regex %>
|
224
|
+
<br>
|
225
|
+
<% end %>
|
226
|
+
</div></div>
|
227
|
+
<br>
|
219
228
|
<% end %>
|
220
229
|
</div>
|
221
230
|
</div>
|
@@ -320,7 +329,7 @@
|
|
320
329
|
<% i=0 %>
|
321
330
|
<% cuke_sniffer.step_definitions.each do |step_definition| %>
|
322
331
|
<div style="cursor: hand;" onclick="toggle(this,4)" class="feature <%= i%2==0 ? "even" : "odd" %>">
|
323
|
-
<% next if step_definition.score <= 0
|
332
|
+
<% next if step_definition.score <= 0 or step_definition.calls.empty? %>
|
324
333
|
<div style="float:left;padding:4px;font-weight:bold;color:red;"><%= step_definition.score %></div>
|
325
334
|
<div style="width:55%;padding:4px; float:left;">
|
326
335
|
|
@@ -1,160 +1,191 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
module CukeSniffer
|
4
2
|
module RuleConfig
|
5
3
|
|
6
|
-
FATAL =
|
7
|
-
ERROR =
|
8
|
-
WARNING = 10
|
9
|
-
INFO =
|
10
|
-
|
11
|
-
SHARED_RULES = {
|
12
|
-
:too_many_tags => {
|
13
|
-
:enabled => true,
|
14
|
-
:phrase => "{class} has too many tags.",
|
15
|
-
:score => INFO,
|
16
|
-
:max => 8
|
17
|
-
},
|
18
|
-
:no_description => {
|
19
|
-
:enabled => true,
|
20
|
-
:phrase => "{class} has no description.",
|
21
|
-
:score => ERROR,
|
22
|
-
},
|
23
|
-
:numbers_in_description => {
|
24
|
-
:enabled => true,
|
25
|
-
:phrase => "{class} has numbers in the description.",
|
26
|
-
:score => WARNING,
|
27
|
-
},
|
28
|
-
:long_name => {
|
29
|
-
:enabled => true,
|
30
|
-
:phrase => "{class} has a long description.",
|
31
|
-
:score => INFO,
|
32
|
-
:max => 180
|
33
|
-
},
|
34
|
-
:implementation_word => {
|
35
|
-
:enabled => true,
|
36
|
-
:phrase => "Implementation word used: {word}.",
|
37
|
-
:score => INFO,
|
38
|
-
:words => ["page", "site", "url", "button", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen"]
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
|
-
FEATURE_RULES = {
|
43
|
-
:background_with_no_scenarios => {
|
44
|
-
:enabled => true,
|
45
|
-
:phrase => "Feature has a background with no scenarios.",
|
46
|
-
:score => WARNING,
|
47
|
-
},
|
48
|
-
:background_with_one_scenario => {
|
49
|
-
:enabled => true,
|
50
|
-
:phrase => "Feature has a background with one scenario.",
|
51
|
-
:score => WARNING,
|
52
|
-
},
|
53
|
-
:no_scenarios => {
|
54
|
-
:enabled => true,
|
55
|
-
:phrase => "Feature with no scenarios.",
|
56
|
-
:score => ERROR,
|
57
|
-
},
|
58
|
-
:too_many_scenarios => {
|
59
|
-
:enabled => true,
|
60
|
-
:phrase => "Feature with too many scenarios.",
|
61
|
-
:score => INFO,
|
62
|
-
:max => 10,
|
63
|
-
},
|
64
|
-
}
|
65
|
-
|
66
|
-
SCENARIO_RULES = {
|
67
|
-
:too_many_steps => {
|
68
|
-
:enabled => true,
|
69
|
-
:phrase => "Scenario with too many steps.",
|
70
|
-
:score => WARNING,
|
71
|
-
:max => 7,
|
72
|
-
},
|
73
|
-
:out_of_order_steps => {
|
74
|
-
:enabled => true,
|
75
|
-
:phrase => "Scenario steps out of Given/When/Then order.",
|
76
|
-
:score => WARNING,
|
77
|
-
},
|
78
|
-
:invalid_first_step => {
|
79
|
-
:enabled => true,
|
80
|
-
:phrase => "Invalid first step. Began with And/But.",
|
81
|
-
:score => WARNING,
|
82
|
-
},
|
83
|
-
:asterisk_step => {
|
84
|
-
:enabled => true,
|
85
|
-
:phrase => "Step includes a * instead of Given/When/Then/And/But.",
|
86
|
-
:score => WARNING,
|
87
|
-
},
|
88
|
-
:commented_step => {
|
89
|
-
:enabled => true,
|
90
|
-
:phrase => "Commented step.",
|
91
|
-
:score => ERROR,
|
92
|
-
},
|
93
|
-
:commented_example => {
|
94
|
-
:enabled => true,
|
95
|
-
:phrase => "Commented example.",
|
96
|
-
:score => ERROR,
|
97
|
-
},
|
98
|
-
:no_examples => {
|
99
|
-
:enabled => true,
|
100
|
-
:phrase => "Scenario Outline with no examples.",
|
101
|
-
:score => FATAL,
|
102
|
-
},
|
103
|
-
:one_example => {
|
104
|
-
:enabled => true,
|
105
|
-
:phrase => "Scenario Outline with only one example.",
|
106
|
-
:score => WARNING,
|
107
|
-
},
|
108
|
-
:no_examples_table => {
|
109
|
-
:enabled => true,
|
110
|
-
:phrase => "Scenario Outline with no examples table.",
|
111
|
-
:score => FATAL,
|
112
|
-
},
|
113
|
-
:too_many_examples => {
|
114
|
-
:enabled => true,
|
115
|
-
:phrase => "Scenario Outline with too many examples.",
|
116
|
-
:score => WARNING,
|
117
|
-
:max => 10
|
118
|
-
},
|
119
|
-
:date_used => {
|
120
|
-
:enabled => true,
|
121
|
-
:phrase => "Date used.",
|
122
|
-
:score => INFO,
|
123
|
-
},
|
124
|
-
:no_steps => {
|
125
|
-
:enabled => true,
|
126
|
-
:phrase => "No steps in Scenario.",
|
127
|
-
:score => ERROR,
|
128
|
-
},
|
129
|
-
}
|
4
|
+
FATAL = 100 #will prevent suite from executing properly
|
5
|
+
ERROR = 25 #will cause problem with debugging
|
6
|
+
WARNING = 10 #readibility/misuse of cucumber
|
7
|
+
INFO = 1 #Small improvements that can be made
|
130
8
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
:
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
:
|
155
|
-
|
9
|
+
RULES = {
|
10
|
+
:too_many_tags => {
|
11
|
+
:enabled => true,
|
12
|
+
:phrase => "{class} has too many tags.",
|
13
|
+
:score => INFO,
|
14
|
+
:max => 8
|
15
|
+
},
|
16
|
+
:no_description => {
|
17
|
+
:enabled => true,
|
18
|
+
:phrase => "{class} has no description.",
|
19
|
+
:score => ERROR,
|
20
|
+
},
|
21
|
+
:numbers_in_description => {
|
22
|
+
:enabled => true,
|
23
|
+
:phrase => "{class} has numbers in the description.",
|
24
|
+
:score => WARNING,
|
25
|
+
},
|
26
|
+
:long_name => {
|
27
|
+
:enabled => true,
|
28
|
+
:phrase => "{class} has a long description.",
|
29
|
+
:score => INFO,
|
30
|
+
:max => 180
|
31
|
+
},
|
32
|
+
:implementation_word => {
|
33
|
+
:enabled => true,
|
34
|
+
:phrase => "Implementation word used: {word}.",
|
35
|
+
:score => INFO,
|
36
|
+
:words => ["page", "site", "url", "button", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen"]
|
37
|
+
},
|
38
|
+
:empty_feature => {
|
39
|
+
:enabled => true,
|
40
|
+
:phrase => "Feature file has no content.",
|
41
|
+
:score => WARNING,
|
42
|
+
},
|
43
|
+
:background_with_no_scenarios => {
|
44
|
+
:enabled => true,
|
45
|
+
:phrase => "Feature has a background with no scenarios.",
|
46
|
+
:score => WARNING,
|
47
|
+
},
|
48
|
+
:background_with_one_scenario => {
|
49
|
+
:enabled => true,
|
50
|
+
:phrase => "Feature has a background with one scenario.",
|
51
|
+
:score => WARNING,
|
52
|
+
},
|
53
|
+
:no_scenarios => {
|
54
|
+
:enabled => true,
|
55
|
+
:phrase => "Feature with no scenarios.",
|
56
|
+
:score => ERROR,
|
57
|
+
},
|
58
|
+
:too_many_scenarios => {
|
59
|
+
:enabled => true,
|
60
|
+
:phrase => "Feature with too many scenarios.",
|
61
|
+
:score => INFO,
|
62
|
+
:max => 10,
|
63
|
+
},
|
64
|
+
:too_many_steps => {
|
65
|
+
:enabled => true,
|
66
|
+
:phrase => "Scenario with too many steps.",
|
67
|
+
:score => WARNING,
|
68
|
+
:max => 7,
|
69
|
+
},
|
70
|
+
:out_of_order_steps => {
|
71
|
+
:enabled => true,
|
72
|
+
:phrase => "Scenario steps out of Given/When/Then order.",
|
73
|
+
:score => WARNING,
|
74
|
+
},
|
75
|
+
:invalid_first_step => {
|
76
|
+
:enabled => true,
|
77
|
+
:phrase => "Invalid first step. Began with And/But.",
|
78
|
+
:score => WARNING,
|
79
|
+
},
|
80
|
+
:asterisk_step => {
|
81
|
+
:enabled => true,
|
82
|
+
:phrase => "Step includes a * instead of Given/When/Then/And/But.",
|
83
|
+
:score => WARNING,
|
84
|
+
},
|
85
|
+
:commented_step => {
|
86
|
+
:enabled => true,
|
87
|
+
:phrase => "Commented step.",
|
88
|
+
:score => ERROR,
|
89
|
+
},
|
90
|
+
:commented_example => {
|
91
|
+
:enabled => true,
|
92
|
+
:phrase => "Commented example.",
|
93
|
+
:score => ERROR,
|
94
|
+
},
|
95
|
+
:no_examples => {
|
96
|
+
:enabled => true,
|
97
|
+
:phrase => "Scenario Outline with no examples.",
|
98
|
+
:score => FATAL,
|
99
|
+
},
|
100
|
+
:one_example => {
|
101
|
+
:enabled => true,
|
102
|
+
:phrase => "Scenario Outline with only one example.",
|
103
|
+
:score => WARNING,
|
104
|
+
},
|
105
|
+
:no_examples_table => {
|
106
|
+
:enabled => true,
|
107
|
+
:phrase => "Scenario Outline with no examples table.",
|
108
|
+
:score => FATAL,
|
109
|
+
},
|
110
|
+
:too_many_examples => {
|
111
|
+
:enabled => true,
|
112
|
+
:phrase => "Scenario Outline with too many examples.",
|
113
|
+
:score => WARNING,
|
114
|
+
:max => 10
|
115
|
+
},
|
116
|
+
:date_used => {
|
117
|
+
:enabled => true,
|
118
|
+
:phrase => "Date used.",
|
119
|
+
:score => INFO,
|
120
|
+
},
|
121
|
+
:no_steps => {
|
122
|
+
:enabled => true,
|
123
|
+
:phrase => "No steps in Scenario.",
|
124
|
+
:score => ERROR,
|
125
|
+
},
|
126
|
+
:one_word_step => {
|
127
|
+
:enabled => true,
|
128
|
+
:phrase => "Step that is only one word long.",
|
129
|
+
:score => ERROR,
|
130
|
+
},
|
131
|
+
:multiple_given_when_then => {
|
132
|
+
:enabled => true,
|
133
|
+
:phrase => "Given/When/Then used multiple times in the same scenario.",
|
134
|
+
:score => WARNING,
|
135
|
+
},
|
136
|
+
:no_code => {
|
137
|
+
:enabled => true,
|
138
|
+
:phrase => "No code in Step Definition.",
|
139
|
+
:score => ERROR,
|
140
|
+
},
|
141
|
+
:too_many_parameters => {
|
142
|
+
:enabled => true,
|
143
|
+
:phrase => "Too many parameters in Step Definition.",
|
144
|
+
:score => WARNING,
|
145
|
+
:max => 4
|
146
|
+
},
|
147
|
+
:nested_step => {
|
148
|
+
:enabled => true,
|
149
|
+
:phrase => "Nested step call.",
|
150
|
+
:score => INFO,
|
151
|
+
},
|
152
|
+
:recursive_nested_step => {
|
153
|
+
:enabled => true,
|
154
|
+
:phrase => "Recursive nested step call.",
|
155
|
+
:score => FATAL,
|
156
|
+
},
|
157
|
+
:commented_code => {
|
158
|
+
:enabled => true,
|
159
|
+
:phrase => "Commented code in Step Definition.",
|
160
|
+
:score => INFO,
|
161
|
+
},
|
162
|
+
:lazy_debugging => {
|
163
|
+
:enabled => true,
|
164
|
+
:phrase => "Lazy Debugging through puts, p, or print",
|
165
|
+
:score => WARNING,
|
166
|
+
},
|
167
|
+
:pending => {
|
168
|
+
:enabled => true,
|
169
|
+
:phrase => "Pending step definition. Implement or remove.",
|
170
|
+
:score => WARNING,
|
171
|
+
},
|
172
|
+
:small_sleep => {
|
173
|
+
:enabled => true,
|
174
|
+
:phrase => "Small sleeps used. Use a wait_until like method.",
|
175
|
+
:score => INFO,
|
176
|
+
:max => 2
|
177
|
+
},
|
178
|
+
:large_sleep => {
|
179
|
+
:enabled => true,
|
180
|
+
:phrase => "Large sleeps used. Use a wait_until like method.",
|
156
181
|
:score => INFO,
|
157
|
-
|
182
|
+
:min => 2
|
183
|
+
},
|
184
|
+
:todo => {
|
185
|
+
:enabled => true,
|
186
|
+
:phrase => "Todo found. Resolve it.",
|
187
|
+
:score => INFO,
|
188
|
+
},
|
158
189
|
}
|
159
190
|
|
160
191
|
end
|
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'roxml'
|
1
2
|
module CukeSniffer
|
2
3
|
class RulesEvaluator
|
3
|
-
|
4
|
+
include ROXML
|
5
|
+
xml_accessor :score, :location
|
6
|
+
xml_accessor :rules_hash, :as => {:key => "phrase", :value => "score"}, :in => "rules", :from => "rule"
|
4
7
|
|
5
8
|
def initialize(location)
|
6
9
|
@location = location
|
@@ -1,12 +1,13 @@
|
|
1
|
-
require 'cuke_sniffer/constants'
|
2
|
-
require 'cuke_sniffer/rule_config'
|
3
|
-
|
4
1
|
module CukeSniffer
|
5
2
|
class Scenario < FeatureRulesEvaluator
|
6
3
|
include CukeSniffer::Constants
|
7
4
|
include CukeSniffer::RuleConfig
|
8
|
-
|
9
|
-
|
5
|
+
|
6
|
+
xml_accessor :start_line
|
7
|
+
xml_accessor :steps, :as => [], :in => "steps"
|
8
|
+
xml_accessor :examples_table, :as => [], :in => "examples"
|
9
|
+
|
10
|
+
attr_accessor :type, :inline_tables
|
10
11
|
|
11
12
|
def initialize(location, scenario)
|
12
13
|
super(location)
|
@@ -81,9 +82,22 @@ module CukeSniffer
|
|
81
82
|
rule_commented_step
|
82
83
|
rule_implementation_words
|
83
84
|
rule_date_used_in_step
|
85
|
+
rule_one_word_step
|
86
|
+
rule_multiple_given_when_then
|
84
87
|
evaluate_outline_scores if type == "Scenario Outline"
|
85
88
|
end
|
86
89
|
|
90
|
+
def rule_multiple_given_when_then
|
91
|
+
step_order = get_step_order
|
92
|
+
%w(Given When Then).each { |type| store_rule(RULES[:multiple_given_when_then]) if step_order.count(type) > 1 }
|
93
|
+
end
|
94
|
+
|
95
|
+
def rule_one_word_step
|
96
|
+
@steps.each do |step|
|
97
|
+
store_rule(RULES[:one_word_step]) if step.split.count == 2
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
87
101
|
def evaluate_outline_scores
|
88
102
|
rule_no_examples_table
|
89
103
|
rule_no_examples
|
@@ -93,37 +107,37 @@ module CukeSniffer
|
|
93
107
|
end
|
94
108
|
|
95
109
|
def rule_empty_scenario
|
96
|
-
store_rule(
|
110
|
+
store_rule(RULES[:no_steps]) if @steps.empty?
|
97
111
|
end
|
98
112
|
|
99
113
|
def rule_too_many_steps
|
100
|
-
rule =
|
114
|
+
rule = RULES[:too_many_steps]
|
101
115
|
store_rule(rule) if @steps.size >= rule[:max]
|
102
116
|
end
|
103
117
|
|
104
118
|
def rule_step_order
|
105
119
|
step_order = get_step_order.uniq
|
106
120
|
%w(But * And).each { |type| step_order.delete(type) }
|
107
|
-
store_rule(
|
121
|
+
store_rule(RULES[:out_of_order_steps]) unless step_order == %w(Given When Then) or step_order == %w(When Then)
|
108
122
|
end
|
109
123
|
|
110
124
|
def rule_invalid_first_step
|
111
125
|
first_step = get_step_order.first
|
112
|
-
store_rule(
|
126
|
+
store_rule(RULES[:invalid_first_step]) if %w(And But).include?(first_step)
|
113
127
|
end
|
114
128
|
|
115
129
|
def rule_asterisk_step
|
116
|
-
get_step_order.count('*').times { store_rule(
|
130
|
+
get_step_order.count('*').times { store_rule(RULES[:asterisk_step]) }
|
117
131
|
end
|
118
132
|
|
119
133
|
def rule_commented_step
|
120
134
|
@steps.each do |step|
|
121
|
-
store_rule(
|
135
|
+
store_rule(RULES[:commented_step]) if is_comment?(step)
|
122
136
|
end
|
123
137
|
end
|
124
138
|
|
125
139
|
def rule_implementation_words
|
126
|
-
rule =
|
140
|
+
rule = RULES[:implementation_word]
|
127
141
|
@steps.each do |step|
|
128
142
|
next if is_comment?(step)
|
129
143
|
rule[:words].each do |word|
|
@@ -134,29 +148,29 @@ module CukeSniffer
|
|
134
148
|
|
135
149
|
def rule_date_used_in_step
|
136
150
|
@steps.each do |step|
|
137
|
-
store_rule(
|
151
|
+
store_rule(RULES[:date_used]) if step =~ DATE_REGEX
|
138
152
|
end
|
139
153
|
end
|
140
154
|
|
141
155
|
def rule_no_examples_table
|
142
|
-
store_rule(
|
156
|
+
store_rule(RULES[:no_examples_table]) if @examples_table.empty?
|
143
157
|
end
|
144
158
|
|
145
159
|
def rule_no_examples
|
146
|
-
store_rule(
|
160
|
+
store_rule(RULES[:no_examples]) if @examples_table.size == 1
|
147
161
|
end
|
148
162
|
|
149
163
|
def rule_one_example
|
150
|
-
store_rule(
|
164
|
+
store_rule(RULES[:one_example]) if @examples_table.size == 2 and !is_comment?(@examples_table[1])
|
151
165
|
end
|
152
166
|
|
153
167
|
def rule_too_many_examples
|
154
|
-
store_rule(
|
168
|
+
store_rule(RULES[:too_many_examples]) if (@examples_table.size - 1) >= 8
|
155
169
|
end
|
156
170
|
|
157
171
|
def rule_commented_example
|
158
172
|
@examples_table.each do |example|
|
159
|
-
store_rule(
|
173
|
+
store_rule(RULES[:commented_example]) if is_comment?(example)
|
160
174
|
end
|
161
175
|
end
|
162
176
|
|
@@ -1,15 +1,22 @@
|
|
1
|
+
require 'roxml'
|
1
2
|
module CukeSniffer
|
2
3
|
class StepDefinition < RulesEvaluator
|
3
4
|
include CukeSniffer::Constants
|
4
5
|
include CukeSniffer::RuleConfig
|
5
6
|
|
7
|
+
xml_accessor :start_line
|
8
|
+
xml_accessor :regex
|
9
|
+
xml_accessor :parameters, :as => [], :in => "parameters"
|
10
|
+
xml_accessor :nested_steps, :as => {:key => 'location', :value => 'call'}, :in => "nested_steps"
|
11
|
+
xml_accessor :calls, :as => {:key => 'location', :value => 'call'}, :in => "calls"
|
12
|
+
xml_accessor :code, :as => [], :in => "code"
|
13
|
+
|
6
14
|
SIMPLE_NESTED_STEP_REGEX = /steps\s"#{STEP_STYLES}(?<step_string>.*)"$/
|
7
|
-
|
8
|
-
|
15
|
+
START_COMPLEX_STEP_REGEX = /^steps\s%(q|Q)?\{\s*/
|
16
|
+
SAME_LINE_COMPLEX_STEP_REGEX = /#{START_COMPLEX_STEP_REGEX}#{STEP_STYLES}(?<step_string>.*)}$/
|
9
17
|
END_COMPLEX_STEP_REGEX = /}$/
|
10
|
-
START_COMPLEX_WITH_STEP_REGEX = /steps\s%Q?\{#{STEP_STYLES}(?<step_string>.*)$/
|
18
|
+
START_COMPLEX_WITH_STEP_REGEX = /steps\s%(q|Q)?\{#{STEP_STYLES}(?<step_string>.*)$/
|
11
19
|
END_COMPLEX_WITH_STEP_REGEX = /#{STEP_STYLES}(?<step_string>.*)}$/
|
12
|
-
attr_accessor :start_line, :regex, :code, :parameters, :calls, :nested_steps
|
13
20
|
|
14
21
|
def initialize(location, raw_code)
|
15
22
|
super(location)
|
@@ -17,7 +24,7 @@ module CukeSniffer
|
|
17
24
|
@parameters = []
|
18
25
|
@calls = {}
|
19
26
|
@nested_steps = {}
|
20
|
-
@start_line = location.match(/:(?<line>\d*)
|
27
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
21
28
|
|
22
29
|
end_match_index = (raw_code.size - 1) - raw_code.reverse.index("end")
|
23
30
|
@code = raw_code[1...end_match_index]
|
@@ -46,13 +53,26 @@ module CukeSniffer
|
|
46
53
|
case line
|
47
54
|
when SIMPLE_NESTED_STEP_REGEX
|
48
55
|
regex = SIMPLE_NESTED_STEP_REGEX
|
56
|
+
when START_COMPLEX_WITH_STEP_REGEX
|
57
|
+
if line =~ /\}$/
|
58
|
+
if line.include?('#{')
|
59
|
+
reversed_line = line.reverse
|
60
|
+
last_capture = reversed_line[0..reversed_line.index('#')].reverse
|
61
|
+
if last_capture =~ /{.*}$/
|
62
|
+
multi_line_step_flag = true
|
63
|
+
regex = START_COMPLEX_WITH_STEP_REGEX
|
64
|
+
else
|
65
|
+
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
66
|
+
end
|
67
|
+
else
|
68
|
+
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
69
|
+
end
|
70
|
+
else
|
71
|
+
multi_line_step_flag = true
|
72
|
+
regex = START_COMPLEX_WITH_STEP_REGEX
|
73
|
+
end
|
49
74
|
when SAME_LINE_COMPLEX_STEP_REGEX
|
50
75
|
regex = SAME_LINE_COMPLEX_STEP_REGEX
|
51
|
-
when START_COMPLEX_WITH_STEP_REGEX
|
52
|
-
multi_line_step_flag = true
|
53
|
-
regex = START_COMPLEX_WITH_STEP_REGEX
|
54
|
-
when START_COMPLEX_STEP_REGEX
|
55
|
-
multi_line_step_flag = true
|
56
76
|
when END_COMPLEX_WITH_STEP_REGEX
|
57
77
|
if line =~ /[#]{.*}$/ && multi_line_step_flag
|
58
78
|
regex = STEP_REGEX
|
@@ -60,6 +80,8 @@ module CukeSniffer
|
|
60
80
|
regex = END_COMPLEX_WITH_STEP_REGEX
|
61
81
|
multi_line_step_flag = false
|
62
82
|
end
|
83
|
+
when START_COMPLEX_STEP_REGEX
|
84
|
+
multi_line_step_flag = true
|
63
85
|
when STEP_REGEX
|
64
86
|
regex = STEP_REGEX if multi_line_step_flag
|
65
87
|
when END_COMPLEX_STEP_REGEX
|
@@ -89,7 +111,7 @@ module CukeSniffer
|
|
89
111
|
|
90
112
|
def condensed_call_list
|
91
113
|
condensed_list = {}
|
92
|
-
@calls.each{|call, step_string|
|
114
|
+
@calls.each { |call, step_string|
|
93
115
|
condensed_list[step_string] ||= []
|
94
116
|
condensed_list[step_string] << call
|
95
117
|
}
|
@@ -112,30 +134,67 @@ module CukeSniffer
|
|
112
134
|
rule_nested_steps
|
113
135
|
rule_recursive_nested_step
|
114
136
|
rule_commented_code
|
137
|
+
rule_lazy_debugging
|
138
|
+
rule_pending
|
139
|
+
rule_todo
|
140
|
+
sleep_rules
|
141
|
+
end
|
142
|
+
|
143
|
+
def rule_todo
|
144
|
+
code.each do |line|
|
145
|
+
store_rule(RULES[:todo]) if line =~ /\#(TODO|todo)/
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def sleep_rules
|
150
|
+
code.each do |line|
|
151
|
+
match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
|
152
|
+
unless match_data.nil?
|
153
|
+
sleep_value = match_data[:sleep_time].to_f
|
154
|
+
store_rule(RULES[:small_sleep]) if sleep_value <= RULES[:small_sleep][:max]
|
155
|
+
store_rule(RULES[:large_sleep]) if sleep_value > RULES[:large_sleep][:min]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def rule_pending
|
161
|
+
code.each do |line|
|
162
|
+
if line =~ /^\s*pending\s*$/
|
163
|
+
store_rule(RULES[:pending])
|
164
|
+
return
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def rule_lazy_debugging
|
170
|
+
code.each do |line|
|
171
|
+
next if is_comment?(line)
|
172
|
+
store_rule(RULES[:lazy_debugging]) if line.strip =~ /^(p|puts)( |\()('|"|%(q|Q)?\{)/
|
173
|
+
end
|
115
174
|
end
|
116
175
|
|
117
176
|
def rule_no_code
|
118
|
-
store_rule(
|
177
|
+
store_rule(RULES[:no_code]) if code.empty?
|
119
178
|
end
|
120
179
|
|
121
180
|
def rule_too_many_parameters
|
122
|
-
rule =
|
181
|
+
rule = RULES[:too_many_parameters]
|
123
182
|
store_rule(rule) if parameters.size >= rule[:max]
|
124
183
|
end
|
125
184
|
|
126
185
|
def rule_nested_steps
|
127
|
-
store_rule(
|
186
|
+
store_rule(RULES[:nested_step]) unless nested_steps.empty?
|
128
187
|
end
|
129
188
|
|
130
189
|
def rule_recursive_nested_step
|
131
190
|
nested_steps.each_value do |nested_step|
|
132
|
-
store_rule(
|
191
|
+
store_rule(RULES[:recursive_nested_step]) if nested_step =~ regex
|
133
192
|
end
|
134
193
|
end
|
135
194
|
|
136
195
|
def rule_commented_code
|
137
196
|
code.each do |line|
|
138
|
-
store_rule(
|
197
|
+
store_rule(RULES[:commented_code]) if is_comment?(line)
|
139
198
|
end
|
140
199
|
end
|
141
200
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuke_sniffer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,10 +11,26 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-
|
15
|
-
dependencies:
|
14
|
+
date: 2013-03-15 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: roxml
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
16
32
|
description: A ruby library used to root out smells in your cukes.
|
17
|
-
email:
|
33
|
+
email:
|
18
34
|
executables:
|
19
35
|
- cuke_sniffer.rb
|
20
36
|
extensions: []
|
@@ -43,18 +59,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
59
|
- - ! '>='
|
44
60
|
- !ruby/object:Gem::Version
|
45
61
|
version: '0'
|
46
|
-
segments:
|
47
|
-
- 0
|
48
|
-
hash: -320967053
|
49
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
63
|
none: false
|
51
64
|
requirements:
|
52
65
|
- - ! '>='
|
53
66
|
- !ruby/object:Gem::Version
|
54
67
|
version: '0'
|
55
|
-
segments:
|
56
|
-
- 0
|
57
|
-
hash: -320967053
|
58
68
|
requirements: []
|
59
69
|
rubyforge_project:
|
60
70
|
rubygems_version: 1.8.24
|