cuke_sniffer 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
3
+
2
4
  require 'cuke_sniffer'
3
5
 
4
6
  help_cmd_txt = "Welcome to CukeSniffer!
@@ -19,7 +21,8 @@ if ARGV.include? "-h" or ARGV.include? "--help"
19
21
  end
20
22
 
21
23
  cuke_sniffer = nil
22
- if (ARGV[0] != nil and File.directory?(ARGV[0])) and (ARGV[1] != nil and File.directory?(ARGV[1]))
24
+ if (ARGV[0] != nil and File.directory?(ARGV[0])) and (ARGV[1] != nil and File.directory?
25
+ (ARGV[1]))
23
26
  cuke_sniffer = CukeSniffer::CLI.new(ARGV[0], ARGV[1])
24
27
  else
25
28
  cuke_sniffer = CukeSniffer::CLI.new
data/lib/cuke_sniffer.rb CHANGED
@@ -1,15 +1,16 @@
1
- require 'nokogiri'
2
- require 'roxml'
3
-
4
- require 'cuke_sniffer/constants'
5
- require 'cuke_sniffer/rule_config'
6
- require 'cuke_sniffer/rules_evaluator'
7
- require 'cuke_sniffer/feature_rules_evaluator'
8
- require 'cuke_sniffer/feature'
9
- require 'cuke_sniffer/scenario'
10
- require 'cuke_sniffer/step_definition'
11
- require 'cuke_sniffer/cli'
12
-
13
- module CukeSniffer
14
-
15
- end
1
+ require 'nokogiri'
2
+ require 'roxml'
3
+
4
+ require 'cuke_sniffer/constants'
5
+ require 'cuke_sniffer/rule_config'
6
+ require 'cuke_sniffer/rules_evaluator'
7
+ require 'cuke_sniffer/feature_rules_evaluator'
8
+ require 'cuke_sniffer/feature'
9
+ require 'cuke_sniffer/scenario'
10
+ require 'cuke_sniffer/step_definition'
11
+ require 'cuke_sniffer/hook'
12
+ require 'cuke_sniffer/cli'
13
+
14
+ module CukeSniffer
15
+
16
+ end
@@ -2,6 +2,11 @@ require 'erb'
2
2
  require 'roxml'
3
3
 
4
4
  module CukeSniffer
5
+
6
+ # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
7
+ # Copyright:: Copyright (C) 2013 Robert Cochran
8
+ # License:: Distributes under the MIT License
9
+ # Mixins: CukeSniffer::Constants, ROXML
5
10
  class CLI
6
11
  include CukeSniffer::Constants
7
12
  include ROXML
@@ -14,26 +19,80 @@ module CukeSniffer
14
19
  xml_accessor :good
15
20
  xml_accessor :bad
16
21
  xml_accessor :threshold
17
- end
22
+ end # :nodoc:
18
23
 
19
24
  xml_name "cuke_sniffer"
20
25
  xml_accessor :features_summary, :as => SummaryNode
21
26
  xml_accessor :scenarios_summary, :as => SummaryNode
22
27
  xml_accessor :step_definitions_summary, :as => SummaryNode
23
- xml_accessor :improvement_list, :as => {:key => "rule", :value => "total"}, :in => "improvement_list", :from => "improvement"
28
+ xml_accessor :hooks_summary, :as => SummaryNode
29
+ xml_accessor :improvement_list, :as => {:key => "rule", :value => "total"}, :in => "improvement_list", :from => "improvement"
24
30
  xml_accessor :features, :as => [CukeSniffer::Feature], :in => "features"
25
31
  xml_accessor :step_definitions, :as => [CukeSniffer::StepDefinition], :in => "step_definitions"
32
+ xml_accessor :hooks, :as => [CukeSniffer::Hook], :in => "hooks"
33
+
34
+
35
+ # Feature array: All Features gathered from the specified folder
36
+ attr_accessor :features
37
+
38
+ # StepDefinition Array: All StepDefinitions objects gathered from the specified folder
39
+ attr_accessor :step_definitions
40
+
41
+ # Hash: Summary objects and improvement lists
42
+ # * Key: symbol, :total_score, :features, :step_definitions, :improvement_list
43
+ # * Value: hash or array
44
+ attr_accessor :summary
45
+
46
+ # string: Location of the feature file or root folder that was searched in
47
+ attr_accessor :features_location
26
48
 
27
- attr_accessor :summary, :features_location, :step_definitions_location, :scenarios
49
+ # string: Location of the step definition file or root folder that was searched in
50
+ attr_accessor :step_definitions_location
28
51
 
29
- def initialize(features_location = Dir.getwd, step_definitions_location = Dir.getwd)
52
+ # string: Location of the hook file or root folder that was searched in
53
+ attr_accessor :hooks_location
54
+
55
+ # Scenario array: All Scenarios found in the features from the specified folder
56
+ attr_accessor :scenarios
57
+
58
+ # Hook array: All Hooks found in the current directory
59
+ attr_accessor :hooks
60
+
61
+
62
+ # Does analysis against the passed features and step definition locations
63
+ #
64
+ # Can be called in several ways.
65
+ #
66
+ #
67
+ # No argument(assumes current directory is the project)
68
+ # cuke_sniffer = CukeSniffer::CLI.new
69
+ #
70
+ # Against single files
71
+ # cuke_sniffer = CukeSniffer::CLI.new("my_feature.feature", nil)
72
+ # Or
73
+ # cuke_sniffer = CukeSniffer::CLI.new(nil, "my_steps.rb")
74
+ #
75
+ #
76
+ # Against folders
77
+ # cuke_sniffer = CukeSniffer::CLI.new("my_features_directory\", "my_steps_directory\")
78
+ #
79
+ # You can mix and match all of the above examples
80
+ #
81
+ # Displays the sequence and a . indicator for each new loop in that process.
82
+ # Handles creation of all Feature and StepDefinition objects
83
+ # Then catalogs all step definition calls to be used for rules and identification
84
+ # of dead steps.
85
+ def initialize(features_location = Dir.getwd, step_definitions_location = Dir.getwd, hooks_location = Dir.getwd)
30
86
  @features_location = features_location
31
87
  @step_definitions_location = step_definitions_location
88
+ @hooks_location = hooks_location
32
89
  @features = []
33
90
  @scenarios = []
34
91
  @step_definitions = []
92
+ @hooks = []
35
93
 
36
94
  puts "\nFeatures:"
95
+ #extract this to a method that accepts a block and yields for the build pattern
37
96
  unless features_location.nil?
38
97
  if File.file?(features_location)
39
98
  @features = [CukeSniffer::Feature.new(features_location)]
@@ -58,12 +117,26 @@ module CukeSniffer
58
117
  }
59
118
  end
60
119
  end
61
-
62
120
  @step_definitions.flatten!
121
+
122
+ puts("\nHooks:")
123
+ unless hooks_location.nil?
124
+ if File.file?(hooks_location)
125
+ @hooks = [build_hooks(hooks_location)]
126
+ else
127
+ build_file_list_from_folder(hooks_location, ".rb").each { |location|
128
+ @hooks << build_hooks(location)
129
+ print '.'
130
+ }
131
+ end
132
+ end
133
+ @hooks.flatten!
134
+
63
135
  @summary = {
64
136
  :total_score => 0,
65
137
  :features => {},
66
138
  :step_definitions => {},
139
+ :hooks => {},
67
140
  :improvement_list => {}
68
141
  }
69
142
  puts "\nCataloging Step Calls: "
@@ -74,6 +147,165 @@ module CukeSniffer
74
147
  @features_summary = load_summary_data(@summary[:features])
75
148
  @scenarios_summary = load_summary_data(@summary[:scenarios])
76
149
  @step_definitions_summary = load_summary_data(@summary[:step_definitions])
150
+ @hooks_summary = load_summary_data(@summary[:hooks])
151
+ end
152
+
153
+ # Returns the status of the overall project based on a comparison of the score to the threshold score
154
+ def good?
155
+ @summary[:total_score] <= Constants::THRESHOLDS["Project"]
156
+ end
157
+
158
+ # Calculates the score to threshold percentage of an object
159
+ # Return: Float
160
+ def problem_percentage
161
+ @summary[:total_score].to_f / Constants::THRESHOLDS["Project"].to_f
162
+ end
163
+
164
+ # Prints out a summary of the results and the list of improvements to be made
165
+ def output_results
166
+ feature_results = @summary[:features]
167
+ step_definition_results = @summary[:step_definitions]
168
+ hooks_results = @summary[:hooks]
169
+ output = "Suite Summary
170
+ Total Score: #{@summary[:total_score]}
171
+ Features (#@features_location)
172
+ Min: #{feature_results[:min]} (#{feature_results[:min_file]})
173
+ Max: #{feature_results[:max]} (#{feature_results[:max_file]})
174
+ Average: #{feature_results[:average]}
175
+ Step Definitions (#@step_definitions_location)
176
+ Min: #{step_definition_results[:min]} (#{step_definition_results[:min_file]})
177
+ Max: #{step_definition_results[:max]} (#{step_definition_results[:max_file]})
178
+ Average: #{step_definition_results[:average]}
179
+ Hooks (#@hooks_location)
180
+ Min: #{hooks_results[:min]} (#{hooks_results[:min_file]})
181
+ Max: #{hooks_results[:max]} (#{hooks_results[:max_file]})
182
+ Average: #{hooks_results[:average]}
183
+ Improvements to make:"
184
+ create_improvement_list.each { |item| output << "\n #{item}" }
185
+ output
186
+ end
187
+
188
+ # Creates a html file with the collected project details
189
+ # file_name defaults to "cuke_sniffer_results.html" unless specified
190
+ # Second parameter used for passing into the markup.
191
+ # cuke_sniffer.output_html
192
+ # Or
193
+ # cuke_sniffer.output_html("results01-01-0001.html")
194
+ def output_html(file_name = "cuke_sniffer_results.html", cuke_sniffer = self)
195
+ @features = @features.sort_by { |feature| feature.total_score }.reverse
196
+ @step_definitions = @step_definitions.sort_by { |step_definition| step_definition.score }.reverse
197
+ @hooks = @hooks.sort_by { |hook| hook.score }.reverse
198
+
199
+ markup_erb = ERB.new extract_markup
200
+ output = markup_erb.result(binding)
201
+ File.open(file_name, 'w') do |f|
202
+ f.write(output)
203
+ end
204
+ end
205
+
206
+ # Creates a xml file with the collected project details
207
+ # file_name defaults to "cuke_sniffer.xml" unless specified
208
+ # cuke_sniffer.output_xml
209
+ # Or
210
+ # cuke_sniffer.output_xml("cuke_sniffer01-01-0001.xml")
211
+ def output_xml(file_name = "cuke_sniffer.xml")
212
+ doc = Nokogiri::XML::Document.new
213
+ doc.root = self.to_xml
214
+ open(file_name, "w") do |file|
215
+ file << doc.serialize
216
+ end
217
+ end
218
+
219
+ # Gathers all StepDefinitions that have no calls
220
+ # Returns a hash that has two different types of records
221
+ # 1: String of the file with a dead step with an array of the line and regex of each dead step
222
+ # 2: Symbol of :total with an integer that is the total number of dead steps
223
+ def get_dead_steps
224
+ dead_steps_hash = {}
225
+ @step_definitions.each do |step_definition|
226
+ location_match = step_definition.location.match(/(?<file>.*).rb:(?<line>\d+)/)
227
+ file_name = location_match[:file]
228
+ regex = step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex]
229
+ dead_steps_hash[file_name] ||= []
230
+ dead_steps_hash[file_name] << "#{location_match[:line]}: /#{regex}/" if step_definition.calls.empty?
231
+ end
232
+ total = 0
233
+ dead_steps_hash.each_key do |key|
234
+ unless dead_steps_hash[key] == []
235
+ total += dead_steps_hash[key].size
236
+ dead_steps_hash[key].sort_by! { |row| row[/^\d+/].to_i }
237
+ else
238
+ dead_steps_hash.delete(key)
239
+ end
240
+ end
241
+ dead_steps_hash[:total] = total
242
+ dead_steps_hash
243
+ end
244
+
245
+ # Determines all normal and nested step calls and assigns them to the corresponding step definition.
246
+ # Does direct and fuzzy matching
247
+ def catalog_step_calls
248
+ steps = get_all_steps
249
+ @step_definitions.each do |step_definition|
250
+ print '.'
251
+ calls = steps.find_all { |location, step| step.gsub(STEP_STYLES, "") =~ step_definition.regex }
252
+ calls.each { |call| step_definition.add_call(call[0], call[1].gsub(STEP_STYLES, "")) }
253
+ end
254
+
255
+ converted_steps = convert_steps_with_expressions(get_steps_with_expressions(steps))
256
+ catalog_possible_dead_steps(converted_steps)
257
+ end
258
+
259
+ private
260
+
261
+ def extract_variables_from_example(example)
262
+ example = example[example.index('|')..example.length]
263
+ example.split(/\s*\|\s*/) - [""]
264
+ end
265
+
266
+ def assess_score
267
+ @summary[:features] = assess_array(@features, "Feature")
268
+ @summary[:scenarios] = assess_array(@scenarios, "Scenario")
269
+ @summary[:step_definitions] = assess_array(@step_definitions, "StepDefinition")
270
+ @summary[:hooks] = assess_array(@hooks, "Hook")
271
+ sort_improvement_list
272
+ end
273
+
274
+ def get_all_steps
275
+ feature_steps = extract_steps_from_features
276
+ step_definition_steps = extract_steps_from_step_definitions
277
+ feature_steps.merge step_definition_steps
278
+ end
279
+
280
+ def get_steps_with_expressions(steps)
281
+ steps_with_expressions = {}
282
+ steps.each do |step_location, step_value|
283
+ if step_value =~ /\#{.*}/
284
+ steps_with_expressions[step_location] = step_value
285
+ end
286
+ end
287
+ steps_with_expressions
288
+ end
289
+
290
+ def catalog_possible_dead_steps(steps_with_expressions)
291
+ @step_definitions.each do |step_definition|
292
+ next unless step_definition.calls.empty?
293
+ regex_as_string = step_definition.regex.to_s.gsub(/\(\?-mix:\^?/, "").gsub(/\$\)$/, "")
294
+ steps_with_expressions.each do |step_location, step_value|
295
+ if regex_as_string =~ step_value
296
+ step_definition.add_call(step_location, step_value)
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ def convert_steps_with_expressions(steps_with_expressions)
303
+ step_regexs = {}
304
+ steps_with_expressions.each do |step_location, step_value|
305
+ modified_step = step_value.gsub(/\#{[^}]*}/, '.*')
306
+ step_regexs[step_location] = Regexp.new('^' + modified_step + '$')
307
+ end
308
+ step_regexs
77
309
  end
78
310
 
79
311
  def load_summary_data(summary_hash)
@@ -87,14 +319,6 @@ module CukeSniffer
87
319
  summary_node
88
320
  end
89
321
 
90
- def good?
91
- @summary[:total_score] <= Constants::THRESHOLDS["Project"]
92
- end
93
-
94
- def problem_percentage
95
- @summary[:total_score].to_f / Constants::THRESHOLDS["Project"].to_f
96
- end
97
-
98
322
  def build_file_list_from_folder(folder_name, extension)
99
323
  list = []
100
324
  Dir.entries(folder_name).each_entry do |file_name|
@@ -129,7 +353,7 @@ module CukeSniffer
129
353
  step_code << step_file_lines[counter].strip
130
354
  counter+=1
131
355
  end
132
- step_definitions << CukeSniffer::StepDefinition.new("#{file_name}:#{counter+1}", step_code) unless step_code.empty? or !found_first_step
356
+ step_definitions << CukeSniffer::StepDefinition.new("#{file_name}:#{counter+1 -step_code.count}", step_code) unless step_code.empty? or !found_first_step
133
357
  step_definitions
134
358
  end
135
359
 
@@ -139,22 +363,24 @@ module CukeSniffer
139
363
  good = 0
140
364
  bad = 0
141
365
  total_score = 0
142
- array.each do |node|
143
- score = node.score
144
- @summary[:total_score] += score
145
- total_score += score
146
- node.rules_hash.each_key do |key|
147
- @summary[:improvement_list][key] ||= 0
148
- @summary[:improvement_list][key] += node.rules_hash[key]
149
- end
150
- min, min_file = score, node.location if (min.nil? or score < min)
151
- max, max_file = score, node.location if (max.nil? or score > max)
152
- if node.good?
153
- good += 1
154
- else
155
- bad += 1
366
+ unless array.empty?
367
+ array.each do |node|
368
+ score = node.score
369
+ @summary[:total_score] += score
370
+ total_score += score
371
+ node.rules_hash.each_key do |key|
372
+ @summary[:improvement_list][key] ||= 0
373
+ @summary[:improvement_list][key] += node.rules_hash[key]
374
+ end
375
+ min, min_file = score, node.location if (min.nil? or score < min)
376
+ max, max_file = score, node.location if (max.nil? or score > max)
377
+ if node.good?
378
+ good += 1
379
+ else
380
+ bad += 1
381
+ end
382
+ total += score
156
383
  end
157
- total += score
158
384
  end
159
385
  {
160
386
  :total => array.count,
@@ -170,13 +396,6 @@ module CukeSniffer
170
396
  }
171
397
  end
172
398
 
173
- def assess_score
174
- @summary[:features] = assess_array(@features, "Feature")
175
- @summary[:scenarios] = assess_array(@scenarios, "Scenario")
176
- @summary[:step_definitions] = assess_array(@step_definitions, "StepDefinition") unless @step_definitions.empty?
177
- sort_improvement_list
178
- end
179
-
180
399
  def get_all_scenarios(features)
181
400
  scenarios = []
182
401
  features.each do |feature|
@@ -194,31 +413,28 @@ module CukeSniffer
194
413
  }
195
414
  end
196
415
 
197
- def output_results
198
- feature_results = @summary[:features]
199
- step_definition_results = @summary[:step_definitions]
200
- output = "Suite Summary
201
- Total Score: #{@summary[:total_score]}
202
- Features (#@features_location)
203
- Min: #{feature_results[:min]} (#{feature_results[:min_file]})
204
- Max: #{feature_results[:max]} (#{feature_results[:max_file]})
205
- Average: #{feature_results[:average]}
206
- Step Definitions (#@step_definitions_location)
207
- Min: #{step_definition_results[:min]} (#{step_definition_results[:min_file]})
208
- Max: #{step_definition_results[:max]} (#{step_definition_results[:max_file]})
209
- Average: #{step_definition_results[:average]}
210
- Improvements to make:"
211
- create_improvement_list.each { |item| output << "\n #{item}" }
212
- output
213
- end
214
-
215
416
  def create_improvement_list
216
417
  output = []
217
418
  @summary[:improvement_list].each_key { |improvement| output << "(#{summary[:improvement_list][improvement]})#{improvement}" }
218
419
  output
219
420
  end
220
421
 
221
- def extract_steps_hash(scenario)
422
+ def extract_steps_from_features
423
+ steps = {}
424
+ @features.each do |feature|
425
+ steps.merge! extract_scenario_steps(feature.background) unless feature.background.nil?
426
+ feature.scenarios.each do |scenario|
427
+ if scenario.type == "Scenario Outline"
428
+ steps.merge! extract_scenario_outline_steps(scenario)
429
+ else
430
+ steps.merge! extract_scenario_steps(scenario)
431
+ end
432
+ end
433
+ end
434
+ steps
435
+ end
436
+
437
+ def extract_scenario_steps(scenario)
222
438
  steps_hash = {}
223
439
  counter = 1
224
440
  scenario.steps.each do |step|
@@ -229,57 +445,46 @@ module CukeSniffer
229
445
  steps_hash
230
446
  end
231
447
 
232
- def get_all_steps
448
+ def extract_scenario_outline_steps(scenario)
233
449
  steps = {}
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
239
- feature.scenarios.each do |scenario|
240
- scenario_steps = extract_steps_hash(scenario)
241
- scenario_steps.each_key { |key| steps[key] = scenario_steps[key] }
242
- end
243
- end
244
- @step_definitions.each do |definition|
245
- definition.nested_steps.each_key do |key|
246
- steps[key] = definition.nested_steps[key]
450
+ examples = scenario.examples_table
451
+ return {} if examples.empty?
452
+ variable_list = extract_variables_from_example(examples.first)
453
+ (1...examples.size).each do |example_counter|
454
+ #TODO Abstraction needed for this regex matcher (constants?)
455
+ next if examples[example_counter] =~ /^\#.*$/
456
+ row_variables = extract_variables_from_example(examples[example_counter])
457
+ step_counter = 1
458
+ scenario.steps.each do |step|
459
+ step_line = scenario.start_line + step_counter
460
+ location = "#{scenario.location.gsub(/\d+$/, step_line.to_s)}(Example #{example_counter})"
461
+ steps[location] = build_updated_step_from_example(step, variable_list, row_variables)
462
+ step_counter += 1
247
463
  end
248
464
  end
249
465
  steps
250
466
  end
251
467
 
252
- def catalog_step_calls
253
- steps = get_all_steps
254
- @step_definitions.each do |step_definition|
255
- print '.'
256
- calls = steps.find_all { |location, step| step.gsub(STEP_STYLES, "") =~ step_definition.regex }
257
- calls.each { |call|
258
- step_definition.add_call(call[0], call[1].gsub(STEP_STYLES, ""))
259
- }
468
+ def build_updated_step_from_example(step, variable_list, row_variables)
469
+ new_step = step.dup
470
+ variable_list.each do |variable|
471
+ if step.include? variable
472
+ table_variable_to_insert = row_variables[variable_list.index(variable)]
473
+ table_variable_to_insert ||= ""
474
+ new_step.gsub!("<#{variable}>", table_variable_to_insert)
475
+ end
260
476
  end
477
+ new_step
261
478
  end
262
479
 
263
- def get_dead_steps
264
- dead_steps_hash = {}
265
- @step_definitions.each do |step_definition|
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?
271
- end
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)
480
+ def extract_steps_from_step_definitions
481
+ steps = {}
482
+ @step_definitions.each do |definition|
483
+ definition.nested_steps.each_key do |key|
484
+ steps[key] = definition.nested_steps[key]
279
485
  end
280
486
  end
281
- dead_steps_hash[:total] = total
282
- dead_steps_hash
487
+ steps
283
488
  end
284
489
 
285
490
  def extract_markup
@@ -291,24 +496,28 @@ module CukeSniffer
291
496
  markup
292
497
  end
293
498
 
294
- def output_html(file_name = "cuke_sniffer_results.html", cuke_sniffer = self)
295
- @features = @features.sort_by { |feature| feature.total_score }.reverse
296
- @step_definitions = @step_definitions.sort_by { |step_definition| step_definition.score }.reverse
499
+ def build_hooks(file_name)
500
+ hooks_file_lines = []
501
+ hooks_file = File.open(file_name)
502
+ hooks_file.each_line { |line| hooks_file_lines << line }
503
+ hooks_file.close
297
504
 
298
- markup_erb = ERB.new extract_markup
299
- output = markup_erb.result(binding)
300
- File.open(file_name, 'w') do |f|
301
- f.write(output)
505
+ counter = 0
506
+ hooks_code = []
507
+ hooks = []
508
+ found_first_hook = false
509
+ until counter >= hooks_file_lines.length
510
+ if hooks_file_lines[counter] =~ HOOK_REGEX and !hooks_code.empty? and found_first_hook
511
+ hooks << CukeSniffer::Hook.new("#{file_name}:#{counter+1 - hooks_code.count}", hooks_code)
512
+ hooks_code = []
513
+ end
514
+ found_first_hook = true if hooks_file_lines[counter] =~ HOOK_REGEX
515
+ hooks_code << hooks_file_lines[counter].strip
516
+ counter+=1
302
517
  end
518
+ hooks << CukeSniffer::Hook.new("#{file_name}:#{counter+1 -hooks_code.count}", hooks_code) unless hooks_code.empty? or !found_first_hook
519
+ hooks
303
520
  end
304
521
 
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
313
522
  end
314
523
  end