cuke_sniffer 0.0.7 → 0.0.8

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.
@@ -2,7 +2,7 @@ require 'erb'
2
2
 
3
3
  module CukeSniffer
4
4
  # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
5
- # Copyright:: Copyright (C) 2013 Robert Cochran
5
+ # Copyright:: Copyright (C) 2014 Robert Cochran
6
6
  # License:: Distributes under the MIT License
7
7
  # Mixins: CukeSniffer::Constants
8
8
  # Static class used to generate output for the CukeSniffer::CLI object.
@@ -1,77 +1,103 @@
1
- require 'roxml'
2
- module CukeSniffer
3
-
4
- # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
5
- # Copyright:: Copyright (C) 2013 Robert Cochran
6
- # License:: Distributes under the MIT License
7
- # Cucumber Hook class used for evaluating rules
8
- # Extends CukeSniffer::RulesEvaluator
9
- class Hook < RuleTarget
10
-
11
- xml_accessor :start_line
12
- xml_accessor :type
13
- xml_accessor :tags, :as => [], :in => "tags"
14
- xml_accessor :parameters, :as => [], :in => "parameters"
15
- xml_accessor :code, :as => [], :in => "code"
16
-
17
- # The type of the hook: AfterConfiguration, After, AfterStep, Around, Before, at_exit
18
- attr_accessor :type
19
-
20
- # The list of tags used as a filter for the hook
21
- attr_accessor :tags
22
-
23
- # The parameters that are declared on the hook
24
- attr_accessor :parameters
25
-
26
- # Integer of the line in which the hook was found
27
- attr_accessor :start_line
28
-
29
- # Array of strings that contain the code kept in the hook
30
- attr_accessor :code
31
-
32
-
33
- # location must be in the format of "file_path\file_name.rb:line_number"
34
- # raw_code is an array of strings that represents the step definition
35
- # must contain the hook declaration line and the pairing end
36
- def initialize(location, hook_block)
37
- super(location)
38
- @start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
39
- end_match_index = (hook_block.size - 1) - hook_block.reverse.index("end")
40
- @code = hook_block[1...end_match_index]
41
- initialize_hook_signature(hook_block)
42
- end
43
-
44
- def ==(comparison_object) # :nodoc:
45
- super(comparison_object) &&
46
- comparison_object.type == type &&
47
- comparison_object.tags == tags &&
48
- comparison_object.parameters == parameters &&
49
- comparison_object.code == code
50
- end
51
-
52
- private
53
-
54
- def initialize_hook_signature(hook_block)
55
- @type = nil
56
- @tags = []
57
- @parameters = []
58
-
59
- hook_signature = extract_hook_signature(hook_block)
60
- matches = HOOK_REGEX.match(hook_signature)
61
- @type = matches[:type]
62
- initialize_tags(matches[:tags]) if matches[:tags]
63
- @parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
64
- end
65
-
66
- def extract_hook_signature(hook_block)
67
- hook_block.each do |line|
68
- return line if line =~ HOOK_REGEX
69
- end
70
- end
71
-
72
- def initialize_tags(tag_list)
73
- hook_tag_regexp = /["']([^"']*)["']/
74
- tag_list.scan(hook_tag_regexp).each { |tag| @tags << tag[0] }
75
- end
76
- end
77
- end
1
+ module CukeSniffer
2
+
3
+ # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
4
+ # Copyright:: Copyright (C) 2014 Robert Cochran
5
+ # License:: Distributes under the MIT License
6
+ # Cucumber Hook class used for evaluating rules
7
+ # Extends CukeSniffer::RulesEvaluator
8
+ class Hook < RuleTarget
9
+
10
+ xml_accessor :start_line
11
+ xml_accessor :tags, :as => [], :in => "tags"
12
+ xml_accessor :parameters, :as => [], :in => "parameters"
13
+ xml_accessor :code, :as => [], :in => "code"
14
+
15
+ # The type of the hook: AfterConfiguration, After, AfterStep, Around, Before, at_exit
16
+ attr_accessor :type
17
+
18
+ # The list of tags used as a filter for the hook
19
+ attr_accessor :tags
20
+
21
+ # The parameters that are declared on the hook
22
+ attr_accessor :parameters
23
+
24
+ # Integer of the line in which the hook was found
25
+ attr_accessor :start_line
26
+
27
+ # Array of strings that contain the code kept in the hook
28
+ attr_accessor :code
29
+
30
+
31
+ # location must be in the format of "file_path\file_name.rb:line_number"
32
+ # raw_code is an array of strings that represents the step definition
33
+ # must contain the hook declaration line and the pairing end
34
+ def initialize(location, hook_block)
35
+ super(location)
36
+ @start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
37
+ end_match_index = (hook_block.size - 1) - hook_block.reverse.index("end")
38
+ @code = hook_block[1...end_match_index]
39
+ initialize_hook_signature(hook_block)
40
+ end
41
+
42
+ def ==(comparison_object) # :nodoc:
43
+ super(comparison_object) &&
44
+ comparison_object.type == type &&
45
+ comparison_object.tags == tags &&
46
+ comparison_object.parameters == parameters &&
47
+ comparison_object.code == code
48
+ end
49
+
50
+ def around?
51
+ type == 'Around'
52
+ end
53
+
54
+ def calls_block?
55
+ @code.join.to_s.include?("#{@parameters[1]}.call")
56
+ end
57
+
58
+ def conflicting_tags?
59
+ all_tags = get_indepentent_tags
60
+ all_tags.each do |single_tag|
61
+ tag = single_tag.gsub("~", "")
62
+ return true if all_tags.include?(tag) and all_tags.include?("~#{tag}")
63
+ end
64
+ false
65
+ end
66
+
67
+ def rescues?
68
+ @code.empty? or @code.join.to_s =~ /.*begin.*rescue.*/
69
+ end
70
+
71
+ private
72
+
73
+ def get_indepentent_tags
74
+ all_tags = []
75
+ @tags.each { |single_tag| all_tags << single_tag.split(',') }
76
+ all_tags.flatten!
77
+ all_tags
78
+ end
79
+
80
+ def initialize_hook_signature(hook_block)
81
+ @type = nil
82
+ @tags = []
83
+ @parameters = []
84
+
85
+ hook_signature = extract_hook_signature(hook_block)
86
+ matches = HOOK_REGEX.match(hook_signature)
87
+ @type = matches[:type]
88
+ initialize_tags(matches[:tags]) if matches[:tags]
89
+ @parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
90
+ end
91
+
92
+ def extract_hook_signature(hook_block)
93
+ hook_block.each do |line|
94
+ return line if line =~ HOOK_REGEX
95
+ end
96
+ end
97
+
98
+ def initialize_tags(tag_list)
99
+ hook_tag_regexp = /["']([^"']*)["']/
100
+ tag_list.scan(hook_tag_regexp).each { |tag| @tags << tag[0] }
101
+ end
102
+ end
103
+ end
@@ -60,11 +60,6 @@
60
60
  </td>
61
61
  </tr>
62
62
  <% end %>
63
- <tr>
64
- <td>
65
- <b>Reason: </b><%= rule.reason %>
66
- </td>
67
- </tr>
68
63
  </table>
69
64
  </td>
70
65
  </tr>
@@ -1,28 +1,27 @@
1
- require 'roxml'
2
- module CukeSniffer
3
-
4
- # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
5
- # Copyright:: Copyright (C) 2013 Robert Cochran
6
- # License:: Distributes under the MIT License
7
- # Single Rule object used for passing around rule data and serializing out to xml
8
- # Mixins: ROXML
9
- class Rule
10
- include ROXML
11
- xml_accessor :enabled
12
- xml_accessor :phrase
13
- xml_accessor :score
14
- xml_accessor :conditions, :as => {:key => "name", :value => "value"}, :in => "conditions", :from => "condition"
15
- xml_accessor :targets, :in => "targets"
16
- xml_accessor :reason
17
-
18
- def initialize
19
- @enabled = false
20
- @phrase = ""
21
- @score = 0
22
- @conditions = {}
23
- @targets = []
24
- @reason = ""
25
- end
26
- end
27
-
1
+ module CukeSniffer
2
+
3
+ # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
4
+ # Copyright:: Copyright (C) 2014 Robert Cochran
5
+ # License:: Distributes under the MIT License
6
+ # Single Rule object used for passing around rule data and serializing out to xml
7
+ # Mixins: ROXML
8
+ class Rule
9
+ include ROXML
10
+ xml_accessor :enabled
11
+ xml_accessor :phrase
12
+ xml_accessor :score
13
+ xml_accessor :conditions, :as => {:key => "name", :value => "value"}, :in => "conditions", :from => "condition"
14
+ xml_accessor :targets, :in => "targets"
15
+ xml_accessor :reason
16
+
17
+ def initialize
18
+ @enabled = false
19
+ @phrase = ""
20
+ @score = 0
21
+ @conditions = {}
22
+ @targets = []
23
+ @reason = ""
24
+ end
25
+ end
26
+
28
27
  end
@@ -21,54 +21,54 @@ module CukeSniffer
21
21
  :phrase => "Scenario Outline with no examples.",
22
22
  :score => FATAL,
23
23
  :targets => ["Scenario"],
24
- :reason => "object.type == \"Scenario Outline\" and object.examples_table.size == 1"
24
+ :reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.size == 1}
25
25
  },
26
26
  :no_examples_table => {
27
27
  :enabled => true,
28
28
  :phrase => "Scenario Outline with no examples table.",
29
29
  :score => FATAL,
30
30
  :targets => ["Scenario"],
31
- :reason => "object.type == \"Scenario Outline\" and object.examples_table.empty?"
31
+ :reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.empty?}
32
32
  },
33
33
  :recursive_nested_step => {
34
34
  :enabled => true,
35
35
  :phrase => "Recursive nested step call.",
36
36
  :score => FATAL,
37
37
  :targets => ["StepDefinition"],
38
- :reason => "object.nested_steps.each_value {|nested_step| store_rule(object, rule) if nested_step =~ object.regex}"
38
+ :reason => lambda { |step_definition, rule| step_definition.store_rule_many_times(rule, step_definition.recursive_nested_steps.size)}
39
39
  },
40
40
  :background_with_tag => {
41
41
  :enabled => true,
42
42
  :phrase => "There is a background with a tag. This feature file cannot run!",
43
43
  :score => FATAL,
44
44
  :targets => ["Background"],
45
- :reason => "object.tags.size > 0"
45
+ :reason => lambda { |background, rule| background.tags.size > 0}
46
46
  },
47
47
  :comment_after_tag => {
48
48
  :enabled => true,
49
49
  :phrase => "Comment comes between tag and properly executing line. This feature file cannot run!",
50
50
  :score => FATAL,
51
51
  :targets => ["Feature", "Scenario"],
52
- :reason => "flag = false
53
- unless object.tags.empty?
54
- object.tags[1..-1].each do | tags |
55
- if tags =~ /^\\s*\\#.*$/
56
- flag = true
57
- break
58
- end
59
- end
60
- end
61
- flag"
52
+ :reason =>
53
+ lambda { |feature_rule_target, rule|
54
+ tokens = feature_rule_target.tags.collect { |line| line.split }.flatten
55
+
56
+ tokens.each_with_index do |token, index|
57
+ if feature_rule_target.is_comment?(token) && tokens[0...index].any? { |x| x =~ /\A@/ }
58
+ return feature_rule_target.store_rule(rule)
59
+ end
60
+ end
61
+ }
62
62
  },
63
63
  :universal_nested_step => {
64
64
  :enabled => true,
65
65
  :phrase => "A nested step should not universally match all step definitions. Dead steps cannot be correctly cataloged.",
66
66
  :score => FATAL,
67
67
  :targets => ["StepDefinition"],
68
- :reason => "object.nested_steps.each_value do | step_value |
69
- modified_step = step_value.gsub(/\\\#{[^}]*}/, '.*')
70
- store_rule(object, rule) if modified_step == '.*'
71
- end"
68
+ :reason => lambda { |step_definition, rule| step_definition.nested_steps.each_value do | step_value |
69
+ modified_step = step_value.gsub(/\#{[^}]*}/, '.*')
70
+ step_definition.store_rule(rule) if modified_step == '.*'
71
+ end}
72
72
  }
73
73
  }
74
74
 
@@ -78,83 +78,72 @@ module CukeSniffer
78
78
  :phrase => "{class} has no description.",
79
79
  :score => ERROR,
80
80
  :targets => ["Feature", "Scenario"],
81
- :reason => "object.name.empty?"
81
+ :reason => lambda { |feature_rule_target, rule| feature_rule_target.name.empty?}
82
82
  },
83
83
  :no_scenarios => {
84
84
  :enabled => true,
85
85
  :phrase => "Feature with no scenarios.",
86
86
  :score => ERROR,
87
87
  :targets => ["Feature"],
88
- :reason => "object.scenarios.empty?"
88
+ :reason => lambda { |feature, rule| feature.scenarios.empty?}
89
89
  },
90
90
  :commented_step => {
91
91
  :enabled => true,
92
92
  :phrase => "Commented step.",
93
93
  :score => ERROR,
94
94
  :targets => ["Scenario", "Background"],
95
- :reason => "object.steps.each do |step|
96
- store_rule(object, rule) if is_comment?(step)
97
- end"
95
+ :reason => lambda { |scenario, rule| scenario.steps.each do |step|
96
+ scenario.store_rule(rule) if scenario.is_comment?(step)
97
+ end}
98
98
  },
99
99
  :commented_example => {
100
100
  :enabled => true,
101
101
  :phrase => "Commented example.",
102
102
  :score => ERROR,
103
103
  :targets => ["Scenario"],
104
- :reason => "if object.type == 'Scenario Outline'
105
- object.examples_table.each {|example| store_rule(object, rule) if is_comment?(example)}
106
- end"
104
+ :reason => lambda { |scenario, rule| scenario.store_rule_many_times(rule, scenario.commented_examples.size) }
107
105
  },
108
106
  :no_steps => {
109
107
  :enabled => true,
110
108
  :phrase => "No steps in Scenario.",
111
109
  :score => ERROR,
112
110
  :targets => ["Scenario", "Background"],
113
- :reason => "object.steps.empty?"
111
+ :reason => lambda { |scenario, rule| scenario.steps.empty?}
114
112
  },
115
113
  :one_word_step => {
116
114
  :enabled => true,
117
115
  :phrase => "Step that is only one word long.",
118
116
  :score => ERROR,
119
117
  :targets => ["Scenario", "Background"],
120
- :reason => "object.steps.each {|step| store_rule(object, rule) if step.split.count == 2}"
118
+ :reason => lambda { |scenario, rule| scenario.steps.each {|step| scenario.store_rule(rule) if step.split.count == 2}}
121
119
  },
122
120
  :no_code => {
123
121
  :enabled => true,
124
122
  :phrase => "No code in Step Definition.",
125
123
  :score => ERROR,
126
124
  :targets => ["StepDefinition"],
127
- :reason => "object.code.empty?"
125
+ :reason => lambda { |step_definition, rule| step_definition.code.empty?}
128
126
  },
129
127
  :around_hook_without_2_parameters => {
130
128
  :enabled => true,
131
129
  :phrase => "Around hook without 2 parameters for Scenario and Block.",
132
130
  :score => ERROR,
133
131
  :targets => ["Hook"],
134
- :reason => "object.type == \"Around\" and object.parameters.count != 2"
132
+ :reason => lambda { |hook, rule| hook.around? and hook.parameters.count != 2}
135
133
  },
136
134
  :around_hook_no_block_call => {
137
135
  :enabled => true,
138
136
  :phrase => "Around hook does not call its block.",
139
137
  :score => ERROR,
140
138
  :targets => ["Hook"],
141
- :reason => "flag = true
142
- flag = false if object.type != 'Around'
143
- block_call = \"\#{object.parameters[1]}.call\"
144
- object.code.each do |line|
145
- if line.include?(block_call)
146
- flag = false
147
- break
148
- end
149
- end
150
- flag"
139
+ :reason => lambda { |hook, rule| hook.around? and !hook.calls_block?}
151
140
  },
152
141
  :hook_no_debugging => {
153
142
  :enabled => true,
154
143
  :phrase => "Hook without a begin/rescue. Reduced visibility when debugging.",
155
144
  :score => ERROR,
156
145
  :targets => ["Hook"],
157
- :reason => "(object.code.empty? != true and object.code.join.match(/.*begin.*rescue.*/).nil?)"
146
+ :reason => lambda { |hook, rule| !hook.rescues?}
158
147
 
159
148
  },
160
149
  :hook_conflicting_tags => {
@@ -162,19 +151,7 @@ module CukeSniffer
162
151
  :phrase => "Hook that both expects and ignores the same tag. This hook will not function as expected.",
163
152
  :score => ERROR,
164
153
  :targets => ["Hook"],
165
- :reason => "all_tags = []
166
- object.tags.each { |single_tag| all_tags << single_tag.split(',') }
167
- all_tags.flatten!
168
- flag = false
169
- all_tags.each do |single_tag|
170
- tag = single_tag.gsub(\"~\", \"\")
171
- if all_tags.include?(tag) and all_tags.include?(\"~\#{tag}\")
172
- flag = true
173
- break
174
- end
175
- end
176
- flag
177
- "
154
+ :reason => lambda { |hook, rule| hook.conflicting_tags? }
178
155
  },
179
156
  }
180
157
 
@@ -184,28 +161,28 @@ module CukeSniffer
184
161
  :phrase => "{class} has numbers in the description.",
185
162
  :score => WARNING,
186
163
  :targets => ["Feature", "Scenario", "Background"],
187
- :reason => "!(object.name =~ /\\d+/).nil?"
164
+ :reason => lambda { |feature_rule_target, rule| !(feature_rule_target.name =~ /\d+/).nil?}
188
165
  },
189
166
  :empty_feature => {
190
167
  :enabled => true,
191
168
  :phrase => "Feature file has no content.",
192
169
  :score => WARNING,
193
170
  :targets => ["Feature"],
194
- :reason => "object.feature_lines == []"
171
+ :reason => lambda { |feature, rule| feature.feature_lines == []}
195
172
  },
196
173
  :background_with_no_scenarios => {
197
174
  :enabled => true,
198
175
  :phrase => "Feature has a background with no scenarios.",
199
176
  :score => WARNING,
200
177
  :targets => ["Feature"],
201
- :reason => "object.scenarios.empty? and !object.background.nil?"
178
+ :reason => lambda { |feature, rule| feature.scenarios.empty? and !feature.background.nil?}
202
179
  },
203
180
  :background_with_one_scenario => {
204
181
  :enabled => true,
205
182
  :phrase => "Feature has a background with one scenario.",
206
183
  :score => WARNING,
207
184
  :targets => ["Feature"],
208
- :reason => "object.scenarios.size == 1 and !object.background.nil?"
185
+ :reason => lambda { |feature, rule| feature.scenarios.size == 1 and !feature.background.nil?}
209
186
  },
210
187
  :too_many_steps => {
211
188
  :enabled => true,
@@ -213,18 +190,18 @@ module CukeSniffer
213
190
  :score => WARNING,
214
191
  :max => 7,
215
192
  :targets => ["Scenario", "Background"],
216
- :reason => "object.steps.count > rule.conditions[:max]"
193
+ :reason => lambda { |scenario, rule| scenario.steps.count > rule.conditions[:max]}
217
194
  },
218
195
  :out_of_order_steps => {
219
196
  :enabled => true,
220
197
  :phrase => "Scenario steps out of Given/When/Then order.",
221
198
  :score => WARNING,
222
199
  :targets => ["Scenario"],
223
- :reason => 'step_order = object.get_step_order
200
+ :reason => lambda { |scenario, rule| step_order = scenario.get_step_order
224
201
  ["But", "*", "And"].each { |type| step_order.delete(type) }
225
202
  if(step_order != %w(Given When Then) and step_order != %w(When Then))
226
- store_rule(object, rule)
227
- end'
203
+ scenario.store_rule(rule)
204
+ end}
228
205
 
229
206
  },
230
207
  :invalid_first_step => {
@@ -232,24 +209,22 @@ module CukeSniffer
232
209
  :phrase => "Invalid first step. Began with And/But.",
233
210
  :score => WARNING,
234
211
  :targets => ["Scenario", "Background"],
235
- :reason => "!(object.steps.first =~ /^\\s*(And|But).*$/).nil?"
212
+ :reason => lambda { |scenario, rule| !(scenario.steps.first =~ /^\s*(And|But).*$/).nil?}
236
213
  },
237
214
  :asterisk_step => {
238
215
  :enabled => true,
239
216
  :phrase => "Step includes a * instead of Given/When/Then/And/But.",
240
217
  :score => WARNING,
241
218
  :targets => ["Scenario", "Background"],
242
- :reason => "object.steps.each do | step |
243
- store_rule(object, rule) if( step =~ /^\\s*[*].*$/)
244
- end
245
- "
219
+ :reason => lambda { |scenario, rule| scenario.store_rule_many_times(rule, scenario.get_steps("*").size)
220
+ }
246
221
  },
247
222
  :one_example => {
248
223
  :enabled => true,
249
224
  :phrase => "Scenario Outline with only one example.",
250
225
  :score => WARNING,
251
226
  :targets => ["Scenario"],
252
- :reason => "object.type == 'Scenario Outline' and object.examples_table.size == 2 and !is_comment?(object.examples_table[1])"
227
+ :reason => lambda { |scenario, rule| scenario.outline? and scenario.examples_table.size == 2}
253
228
  },
254
229
  :too_many_examples => {
255
230
  :enabled => true,
@@ -257,17 +232,18 @@ module CukeSniffer
257
232
  :score => WARNING,
258
233
  :max => 10,
259
234
  :targets => ["Scenario"],
260
- :reason => "object.type == 'Scenario Outline' and (object.examples_table.size - 1) >= rule.conditions[:max]"
235
+ :reason => lambda { |scenario, rule| scenario.outline? and (scenario.examples_table.size - 1) >= rule.conditions[:max]}
261
236
  },
262
237
  :multiple_given_when_then => {
263
238
  :enabled => true,
264
239
  :phrase => "Given/When/Then used multiple times in the same {class}.",
265
240
  :score => WARNING,
266
241
  :targets => ["Scenario", "Background"],
267
- :reason => "
268
- step_order = object.get_step_order
269
- phrase = rule.phrase.gsub('{class}', type)
270
- ['Given', 'When', 'Then'].each {|step_start| store_rule(object, rule, phrase) if step_order.count(step_start) > 1}"
242
+ :reason => lambda { |scenario, rule|
243
+ phrase = rule.phrase.gsub('{class}', scenario.type)
244
+ ['Given', 'When', 'Then'].each do |step_start|
245
+ scenario.store_rule(rule, phrase) if scenario.get_steps(step_start).size > 1
246
+ end}
271
247
  },
272
248
  :too_many_parameters => {
273
249
  :enabled => true,
@@ -275,7 +251,7 @@ module CukeSniffer
275
251
  :score => WARNING,
276
252
  :max => 4,
277
253
  :targets => ["StepDefinition"],
278
- :reason => "object.parameters.size > rule.conditions[:max]"
254
+ :reason => lambda { |step_definition, rule| step_definition.parameters.size > rule.conditions[:max]}
279
255
 
280
256
  },
281
257
  :lazy_debugging => {
@@ -283,32 +259,32 @@ module CukeSniffer
283
259
  :phrase => "Lazy Debugging through puts, p, or print",
284
260
  :score => WARNING,
285
261
  :targets => ["StepDefinition"],
286
- :reason => "object.code.each {|line| store_rule(object, rule) if line.strip =~ /^(p|puts)( |\\()('|\\\"|%(q|Q)?\\{)/}"
262
+ :reason => lambda { |step_definition, rule| step_definition.code.each {|line| step_definition.store_rule(rule) if line.strip =~ /^(p|puts)( |\()('|"|%(q|Q)?\{)/}}
287
263
  },
288
264
  :pending => {
289
265
  :enabled => true,
290
266
  :phrase => "Pending step definition. Implement or remove.",
291
267
  :score => WARNING,
292
268
  :targets => ["StepDefinition"],
293
- :reason => "object.code.each {|line|
294
- if line =~ /^\\s*pending(\\(.*\\))?(\\s*[#].*)?$/
295
- store_rule(object, rule)
269
+ :reason => lambda { |step_definition, rule| step_definition.code.each {|line|
270
+ if line =~ /^\s*pending(\(.*\))?(\s*[#].*)?$/
271
+ step_definition.store_rule(rule)
296
272
  break
297
273
  end
298
- }"
274
+ }}
299
275
  },
300
276
  :feature_same_tag => {
301
277
  :enabled => true,
302
278
  :phrase => "Same tag appears on Feature.",
303
279
  :score => WARNING,
304
280
  :targets => ["Feature"],
305
- :reason => 'if(object.scenarios.count >= 2)
306
- object.scenarios[1..-1].each do |scenario|
307
- object.scenarios.first.tags.each do |tag|
308
- store_rule(object, rule) if scenario.tags.include?(tag)
281
+ :reason => lambda { |feature, rule| if(feature.scenarios.count >= 2)
282
+ feature.scenarios[1..-1].each do |scenario|
283
+ feature.scenarios.first.tags.each do |tag|
284
+ feature.store_rule(rule) if scenario.tags.include?(tag)
309
285
  end
310
286
  end
311
- end'
287
+ end}
312
288
  },
313
289
  :scenario_same_tag => {
314
290
  :enabled => true,
@@ -316,60 +292,61 @@ module CukeSniffer
316
292
  :score => WARNING,
317
293
  :targets => ["Feature"],
318
294
  #TODO really hacky
319
- :reason => "unless object.scenarios.empty?
320
- base_tag_list = object.scenarios.first.tags.clone
321
- object.scenarios.each do |scenario|
295
+ :reason => lambda { |feature, rule| unless feature.scenarios.empty?
296
+ base_tag_list = feature.scenarios.first.tags.clone
297
+ feature.scenarios.each do |scenario|
322
298
  base_tag_list.each do |tag|
323
299
  base_tag_list.delete(tag) unless scenario.tags.include?(tag)
324
300
  end
325
301
  end
326
- base_tag_list.count.times { store_rule(object, rule) }
327
- end"
302
+ base_tag_list.count.times { feature.store_rule(rule) }
303
+ end}
328
304
  },
329
305
  :commas_in_description => {
330
306
  :enabled => true,
331
307
  :phrase => "There are commas in the description, creating possible multirunning scenarios or features.",
332
308
  :score => WARNING,
333
309
  :targets => ["Feature", "Scenario"],
334
- :reason => 'object.name.include?(",")'
310
+ :reason => lambda { |rule_target, rule| rule_target.name.include?(",")}
335
311
  },
336
312
  :commented_tag => {
337
313
  :enabled => true,
338
314
  :phrase => "{class} has a commented out tag",
339
315
  :score => WARNING,
340
316
  :targets => ["Feature", "Scenario"],
341
- :reason => 'object.tags.each do | tag |
342
- store_rule(object, rule, rule.phrase.gsub("{class}", type)) if is_comment?(tag)
343
- end'
317
+ :reason => lambda { |feature_rule_target, rule| feature_rule_target.tags.each do | tag |
318
+ feature_rule_target.store_rule(rule, rule.phrase.gsub("{class}", feature_rule_target.type)) if feature_rule_target.is_comment?(tag)
319
+ end}
344
320
  },
345
321
  :empty_hook => {
346
322
  :enabled => true,
347
323
  :phrase => "Hook with no content.",
348
324
  :score => WARNING,
349
325
  :targets => ["Hook"],
350
- :reason => "object.code == []"
326
+ :reason => lambda { |hook, rule| hook.code == []}
351
327
  },
352
328
  :hook_all_comments => {
353
329
  :enabled => true,
354
330
  :phrase => "Hook is only comments.",
355
331
  :score => WARNING,
356
332
  :targets => ["Hook"],
357
- :reason => "flag = true
358
- object.code.each do |line|
359
- flag = false if line.match(/^\\s*\\#.*$/).nil?
333
+ :reason => lambda { |hook, rule| flag = true
334
+ hook.code.each do |line|
335
+ flag = false if line.match(/^\s*#.*$/).nil?
360
336
  end
361
- flag"
337
+ flag}
362
338
  },
363
339
  :hook_duplicate_tags => {
364
340
  :enabled => true,
365
341
  :phrase => "Hook has duplicate tags.",
366
342
  :score => WARNING,
367
343
  :targets => ["Hook"],
368
- :reason => "all_tags = []
369
- object.tags.each { |single_tag| all_tags << single_tag.split(',') }
344
+ :reason => lambda { |hook, rule|
345
+ all_tags = []
346
+ hook.tags.each { |single_tag| all_tags << single_tag.split(',') }
370
347
  all_tags.flatten!
371
348
  unique_tags = all_tags.uniq
372
- true unless all_tags == unique_tags"
349
+ true unless all_tags == unique_tags}
373
350
  }
374
351
  }
375
352
 
@@ -380,7 +357,7 @@ module CukeSniffer
380
357
  :score => INFO,
381
358
  :max => 8,
382
359
  :targets => ["Feature", "Scenario"],
383
- :reason => "object.tags.size >= rule.conditions[:max]"
360
+ :reason => lambda { |feature_rule_target, rule| feature_rule_target.tags.size >= rule.conditions[:max]}
384
361
  },
385
362
  :long_name => {
386
363
  :enabled => true,
@@ -388,21 +365,21 @@ module CukeSniffer
388
365
  :score => INFO,
389
366
  :max => 180,
390
367
  :targets => ["Feature", "Scenario", "Background"],
391
- :reason => "object.name.length >= rule.conditions[:max]"
368
+ :reason => lambda { |feature_rule_target, rule| feature_rule_target.name.length >= rule.conditions[:max]}
392
369
  },
393
370
  :implementation_word => {
394
371
  :enabled => true,
395
372
  :phrase => "Implementation word used: {word}.",
396
373
  :score => INFO,
397
- :words => ["page", "site", "url", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen", "tab", "database", "DB"],
374
+ :words => ["page", "site", "url", "drop down", "dropdown", "select list", "click", "text box", "radio button", "check box", "xml", "window", "pop up", "pop-up", "screen", "database", "DB"],
398
375
  :targets => ["Scenario", "Background"],
399
- :reason => "object.steps.each do |step|
400
- next if is_comment?(step)
376
+ :reason => lambda { |scenario, rule| scenario.steps.each do |step|
377
+ next if scenario.is_comment?(step)
401
378
  rule.conditions[:words].each do |word|
402
379
  new_phrase = rule.phrase.gsub(/{.*}/, word)
403
- store_rule(object, rule, new_phrase) if step.include?(word)
380
+ scenario.store_rule(rule, new_phrase) if step.include?(word)
404
381
  end
405
- end"
382
+ end}
406
383
 
407
384
  },
408
385
  :implementation_word_button => {
@@ -410,41 +387,51 @@ module CukeSniffer
410
387
  :phrase => "Implementation word used: button.",
411
388
  :score => INFO,
412
389
  :targets => ["Scenario"],
413
- :reason => "object.steps.each do |step|
414
- matches = step.match(/(?<prefix>\\w+)\\sbutton/i)
390
+ :reason => lambda { |scenario, rule| scenario.steps.each do |step|
391
+ matches = step.match(/(?<prefix>\w+)\sbutton/i)
415
392
  if(!matches.nil? and matches[:prefix].downcase != 'radio')
416
- store_rule(object, rule)
393
+ scenario.store_rule(rule)
417
394
  end
418
- end"
395
+ end}
419
396
 
420
- },:too_many_scenarios => {
397
+ },
398
+ :implementation_word_tab => {
399
+ :enabled => true,
400
+ :phrase => "Implementation word used: tab.",
401
+ :score => INFO,
402
+ :targets => ["Scenario"],
403
+ :reason => lambda { |scenario, rule| scenario.steps.each do |step|
404
+ scenario.store_rule(rule) if (step.split.include?("tab"))
405
+ end}
406
+ },
407
+ :too_many_scenarios => {
421
408
  :enabled => true,
422
409
  :phrase => "Feature with too many scenarios.",
423
410
  :score => INFO,
424
411
  :max => 10,
425
412
  :targets => ["Feature"],
426
- :reason => "object.scenarios.size >= rule.conditions[:max]"
413
+ :reason => lambda { |feature, rule| feature.scenarios.size >= rule.conditions[:max]}
427
414
  },
428
415
  :date_used => {
429
416
  :enabled => true,
430
417
  :phrase => "Date used.",
431
418
  :score => INFO,
432
419
  :targets => ["Scenario", "Background"],
433
- :reason => "object.steps.each {|step| store_rule(object, rule) if step =~ DATE_REGEX}"
420
+ :reason => lambda { |scenario, rule| scenario.steps.each {|step| scenario.store_rule(rule) if step =~ CukeSniffer::Constants::DATE_REGEX}}
434
421
  },
435
422
  :nested_step => {
436
423
  :enabled => true,
437
424
  :phrase => "Nested step call.",
438
425
  :score => INFO,
439
426
  :targets => ["StepDefinition"],
440
- :reason => "!object.nested_steps.empty?"
427
+ :reason => lambda { |step_definition, rule| !step_definition.nested_steps.empty?}
441
428
  },
442
429
  :commented_code => {
443
430
  :enabled => true,
444
431
  :phrase => "Commented code in Step Definition.",
445
432
  :score => INFO,
446
433
  :targets => ["StepDefinition"],
447
- :reason => "object.code.each {|line| store_rule(object, rule) if is_comment?(line)}"
434
+ :reason => lambda { |step_definition, rule| step_definition.code.each {|line| step_definition.store_rule(rule) if step_definition.is_comment?(line)}}
448
435
  },
449
436
  :small_sleep => {
450
437
  :enabled => true,
@@ -452,13 +439,13 @@ module CukeSniffer
452
439
  :score => INFO,
453
440
  :max => 2,
454
441
  :targets => ["StepDefinition"],
455
- :reason => "object.code.each do |line|
456
- match_data = line.match /^\\s*sleep(\\s|\\()(?<sleep_time>.*)\\)?/
442
+ :reason => lambda { |step_definition, rule| step_definition.code.each do |line|
443
+ match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
457
444
  if match_data
458
445
  sleep_value = match_data[:sleep_time].to_f
459
- store_rule(object, rule) if sleep_value < rule.conditions[:max]
446
+ step_definition.store_rule(rule) if sleep_value < rule.conditions[:max]
460
447
  end
461
- end"
448
+ end}
462
449
  },
463
450
  :large_sleep => {
464
451
  :enabled => true,
@@ -466,21 +453,20 @@ module CukeSniffer
466
453
  :score => INFO,
467
454
  :min => 2,
468
455
  :targets => ["StepDefinition"],
469
- :reason => "object.code.each do |line|
470
- match_data = line.match /^\\s*sleep(\\s|\\()(?<sleep_time>.*)\\)?/
456
+ :reason => lambda { |step_definition, rule| step_definition.code.each do |line|
457
+ match_data = line.match /^\s*sleep(\s|\()(?<sleep_time>.*)\)?/
471
458
  if match_data
472
459
  sleep_value = match_data[:sleep_time].to_f
473
- store_rule(object, rule) if sleep_value > rule.conditions[:min]
460
+ step_definition.store_rule(rule) if sleep_value > rule.conditions[:min]
474
461
  end
475
- end"
462
+ end}
476
463
  },
477
464
  :todo => {
478
465
  :enabled => true,
479
466
  :phrase => "Todo found. Resolve it.",
480
467
  :score => INFO,
481
468
  :targets => ["StepDefinition"],
482
- :reason => "object.code.each {|line| store_rule(object, rule) if line =~ /\\#(TODO|todo)/}
483
- false"
469
+ :reason => lambda { |step_definition, rule| step_definition.store_rule_many_times(rule, step_definition.todo.size)}
484
470
  },
485
471
  :hook_not_in_hooks_file => {
486
472
  :enabled => true,
@@ -488,7 +474,7 @@ module CukeSniffer
488
474
  :score => INFO,
489
475
  :file => "hooks.rb",
490
476
  :targets => ["Hook"],
491
- :reason => "object.location.include?(rule.conditions[:file]) != true"
477
+ :reason => lambda { |hook, rule| hook.location.include?(rule.conditions[:file]) != true}
492
478
  },
493
479
  }
494
480