cuke_sniffer 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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