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.
- data/bin/{cuke_sniffer.rb → cuke_sniffer} +4 -1
- data/lib/cuke_sniffer.rb +16 -15
- data/lib/cuke_sniffer/cli.rb +319 -110
- data/lib/cuke_sniffer/constants.rb +34 -22
- data/lib/cuke_sniffer/feature.rb +77 -22
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +115 -69
- data/lib/cuke_sniffer/hook.rb +160 -0
- data/lib/cuke_sniffer/report/markup.rhtml +266 -308
- data/lib/cuke_sniffer/rule_config.rb +192 -94
- data/lib/cuke_sniffer/rules_evaluator.rb +70 -53
- data/lib/cuke_sniffer/scenario.rb +238 -178
- data/lib/cuke_sniffer/step_definition.rb +239 -202
- metadata +6 -5
@@ -1,22 +1,34 @@
|
|
1
|
-
module CukeSniffer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
1
|
+
module CukeSniffer
|
2
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
3
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
4
|
+
# License:: Distributes under the MIT License
|
5
|
+
# A collection of constants that are used throughout the gem
|
6
|
+
module Constants
|
7
|
+
|
8
|
+
FILE_IGNORE_LIST = %w(. .. .svn) # :nodoc:
|
9
|
+
DATE_REGEX = /(?<date>\d{2}\/\d{2}\/\d{4})/ # :nodoc:
|
10
|
+
COMMENT_REGEX = /#?\s*/ # :nodoc:
|
11
|
+
TAG_REGEX = /(^|\s+)(?<tag>@\S*)/ # :nodoc:
|
12
|
+
SCENARIO_TITLE_STYLES = /^\s*\#*\s*(?<type>Background|Scenario|Scenario Outline|Scenario Template):\s*/ # :nodoc:
|
13
|
+
STEP_STYLES = /(?<style>Given|When|Then|And|Or|But|Transform|\*)\s+/ # :nodoc:
|
14
|
+
STEP_REGEX = /^#{COMMENT_REGEX}#{STEP_STYLES}(?<step_string>.*)/ # :nodoc:
|
15
|
+
STEP_DEFINITION_REGEX = /^#{STEP_STYLES}\/(?<step>.+)\/\sdo\s?(\|(?<parameters>.*)\|)?$/ # :nodoc:
|
16
|
+
HOOK_STYLES = /(?<type>Before|After|AfterConfiguration|at_exit|Around|AfterStep)/ # :nodoc:
|
17
|
+
HOOK_REGEX = /^#{HOOK_STYLES}(\((?<tags>.*)\)\sdo|\s+do)(\s\|(?<parameters>.*)\|)?/
|
18
|
+
|
19
|
+
# hash: Stores scores to compare against for determining if an object is good
|
20
|
+
# * Key: String of the object name
|
21
|
+
# Project, Feature, Scenario, StepDefinition
|
22
|
+
# * Value: Integer of the highest acceptable value an object can have
|
23
|
+
# Customizable for a projects level of acceptable score
|
24
|
+
# CukeSniffer::Constants::THRESHOLDS["Project"] = 95000
|
25
|
+
THRESHOLDS = {
|
26
|
+
"Project" => 1000,
|
27
|
+
"Feature" => 30,
|
28
|
+
"Scenario" => 30,
|
29
|
+
"StepDefinition" => 20,
|
30
|
+
"Hook" => 20
|
31
|
+
}
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/cuke_sniffer/feature.rb
CHANGED
@@ -1,30 +1,52 @@
|
|
1
1
|
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# Handles feature files and disassembles and evaluates
|
7
|
+
# its components.
|
8
|
+
# Extends CukeSniffer::FeatureRulesEvaluator
|
2
9
|
class Feature < FeatureRulesEvaluator
|
3
|
-
include CukeSniffer::Constants
|
4
|
-
include CukeSniffer::RuleConfig
|
5
|
-
include ROXML
|
6
10
|
|
7
11
|
xml_accessor :scenarios, :as => [CukeSniffer::FeatureRulesEvaluator], :in => "scenarios"
|
8
12
|
|
9
|
-
SCENARIO_TITLE_REGEX = /#{COMMENT_REGEX}#{SCENARIO_TITLE_STYLES}(?<name>.*)/
|
13
|
+
SCENARIO_TITLE_REGEX = /#{COMMENT_REGEX}#{SCENARIO_TITLE_STYLES}(?<name>.*)/ # :nodoc:
|
14
|
+
|
15
|
+
# Scenario: The background of a Feature, created as a Scenario object
|
16
|
+
attr_accessor :background
|
17
|
+
|
18
|
+
# Scenario array: A list of all scenarios contained in a feature file
|
19
|
+
attr_accessor :scenarios
|
10
20
|
|
11
|
-
|
21
|
+
# int: Total score from all of the scenarios contained in the feature
|
22
|
+
attr_accessor :scenarios_score
|
12
23
|
|
24
|
+
# int: Total score of the feature and its scenarios
|
25
|
+
attr_accessor :total_score
|
26
|
+
|
27
|
+
# file_name must be in the format of "file_path\file_name.feature"
|
13
28
|
def initialize(file_name)
|
14
29
|
super(file_name)
|
15
30
|
@scenarios = []
|
16
|
-
@RULES_hash = {}
|
17
31
|
@scenarios_score = 0
|
18
32
|
@total_score = 0
|
19
33
|
feature_lines = extract_feature_from_file(file_name)
|
20
34
|
if feature_lines == []
|
21
|
-
|
35
|
+
rule = RULES[:empty_feature]
|
36
|
+
store_rule(rule)
|
22
37
|
else
|
23
38
|
split_feature(file_name, feature_lines)
|
24
39
|
evaluate_score
|
25
40
|
end
|
26
41
|
end
|
27
42
|
|
43
|
+
def ==(comparison_object) # :nodoc:
|
44
|
+
super(comparison_object) &&
|
45
|
+
comparison_object.scenarios == scenarios
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
28
50
|
def extract_feature_from_file(file_name)
|
29
51
|
feature_lines = []
|
30
52
|
feature_file = File.open(file_name)
|
@@ -49,10 +71,20 @@ module CukeSniffer
|
|
49
71
|
index_of_title = nil
|
50
72
|
code_block = []
|
51
73
|
until index >= feature_lines.length
|
52
|
-
if scenario_title_found and
|
53
|
-
|
74
|
+
if scenario_title_found and feature_lines[index].match SCENARIO_TITLE_REGEX
|
75
|
+
not_our_code = []
|
76
|
+
code_block.reverse.each do |line|
|
77
|
+
break if line =~ /#{SCENARIO_TITLE_STYLES}|#{STEP_STYLES}|^\|.*\||Examples:/
|
78
|
+
not_our_code << line
|
79
|
+
end
|
80
|
+
|
81
|
+
if not_our_code.empty?
|
82
|
+
add_scenario_to_feature(code_block, index_of_title)
|
83
|
+
else
|
84
|
+
add_scenario_to_feature(code_block[0...(-1 * not_our_code.length)], index_of_title)
|
85
|
+
end
|
54
86
|
scenario_title_found = false
|
55
|
-
code_block =
|
87
|
+
code_block = not_our_code.reverse
|
56
88
|
end
|
57
89
|
code_block << feature_lines[index].strip
|
58
90
|
if feature_lines[index].match SCENARIO_TITLE_REGEX
|
@@ -67,6 +99,7 @@ module CukeSniffer
|
|
67
99
|
|
68
100
|
def add_scenario_to_feature(code_block, index_of_title)
|
69
101
|
scenario = CukeSniffer::Scenario.new(index_of_title, code_block)
|
102
|
+
feature_applied_scenario_rules(scenario)
|
70
103
|
if scenario.type == "Background"
|
71
104
|
@background = scenario
|
72
105
|
else
|
@@ -74,30 +107,51 @@ module CukeSniffer
|
|
74
107
|
end
|
75
108
|
end
|
76
109
|
|
77
|
-
def ==(comparison_object)
|
78
|
-
super(comparison_object)
|
79
|
-
comparison_object.scenarios == scenarios
|
80
|
-
end
|
81
|
-
|
82
110
|
def evaluate_score
|
83
111
|
super
|
84
112
|
rule_no_scenarios
|
85
113
|
rule_too_many_scenarios
|
86
114
|
rule_background_with_no_scenarios
|
87
115
|
rule_background_with_one_scenario
|
116
|
+
rule_scenario_same_tag
|
88
117
|
get_scenarios_score
|
89
118
|
@total_score = score + @scenarios_score
|
90
119
|
end
|
91
120
|
|
121
|
+
def feature_applied_scenario_rules(scenario)
|
122
|
+
rule_feature_same_tags(scenario)
|
123
|
+
end
|
124
|
+
|
125
|
+
def rule_feature_same_tags(scenario)
|
126
|
+
rule = RULES[:feature_same_tag]
|
127
|
+
tags.each do |tag|
|
128
|
+
scenario.store_rule(rule, rule[:phrase]) if scenario.tags.include?(tag)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def rule_scenario_same_tag
|
133
|
+
rule = RULES[:scenario_same_tag]
|
134
|
+
unless scenarios.empty?
|
135
|
+
base_tag_list = scenarios.first.tags.clone
|
136
|
+
scenarios.each do |scenario|
|
137
|
+
base_tag_list.each do |tag|
|
138
|
+
base_tag_list.delete(tag) unless scenario.tags.include?(tag)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
base_tag_list.count.times do
|
142
|
+
store_rule(rule, rule[:phrase])
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
92
147
|
def get_scenarios_score
|
93
148
|
@scenarios_score += @background.score unless @background.nil?
|
94
|
-
@scenarios.each
|
95
|
-
@scenarios_score += scenario.score
|
96
|
-
end
|
149
|
+
@scenarios.each { |scenario| @scenarios_score += scenario.score }
|
97
150
|
end
|
98
151
|
|
99
152
|
def rule_no_scenarios
|
100
|
-
|
153
|
+
rule = RULES[:no_scenarios]
|
154
|
+
store_rule(rule) if @scenarios.empty?
|
101
155
|
end
|
102
156
|
|
103
157
|
def rule_too_many_scenarios
|
@@ -106,12 +160,13 @@ module CukeSniffer
|
|
106
160
|
end
|
107
161
|
|
108
162
|
def rule_background_with_no_scenarios
|
109
|
-
|
163
|
+
rule = RULES[:background_with_no_scenarios]
|
164
|
+
store_rule(rule) if @scenarios.empty? and !@background.nil?
|
110
165
|
end
|
111
166
|
|
112
167
|
def rule_background_with_one_scenario
|
113
|
-
|
168
|
+
rule = RULES[:background_with_one_scenario]
|
169
|
+
store_rule(rule) if @scenarios.size == 1 and !@background.nil?
|
114
170
|
end
|
115
|
-
|
116
171
|
end
|
117
172
|
end
|
@@ -1,69 +1,115 @@
|
|
1
|
-
require 'cuke_sniffer/constants'
|
2
|
-
require 'cuke_sniffer/rule_config'
|
3
|
-
require 'cuke_sniffer/rules_evaluator'
|
4
|
-
|
5
|
-
module CukeSniffer
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
1
|
+
require 'cuke_sniffer/constants'
|
2
|
+
require 'cuke_sniffer/rule_config'
|
3
|
+
require 'cuke_sniffer/rules_evaluator'
|
4
|
+
|
5
|
+
module CukeSniffer
|
6
|
+
|
7
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
8
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
9
|
+
# License:: Distributes under the MIT License
|
10
|
+
# Parent class for Feature and Scenario objects
|
11
|
+
# holds shared attributes and rules.
|
12
|
+
# Extends CukeSniffer::RulesEvaluator
|
13
|
+
class FeatureRulesEvaluator < RulesEvaluator
|
14
|
+
|
15
|
+
# string array: Contains all tags attached to a Feature or Scenario
|
16
|
+
attr_accessor :tags
|
17
|
+
|
18
|
+
# string: Name of the Feature or Scenario
|
19
|
+
attr_accessor :name
|
20
|
+
|
21
|
+
# Location must be in the format of "file_path\file_name.rb:line_number"
|
22
|
+
def initialize(location)
|
23
|
+
@name = ""
|
24
|
+
@tags = []
|
25
|
+
super(location)
|
26
|
+
end
|
27
|
+
|
28
|
+
def == (comparison_object) # :nodoc:
|
29
|
+
super(comparison_object) &&
|
30
|
+
comparison_object.name == name &&
|
31
|
+
comparison_object.tags == tags
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_name(line, filter)
|
37
|
+
line.gsub!(/#{COMMENT_REGEX}#{filter}/, "")
|
38
|
+
line.strip!
|
39
|
+
@name += " " unless @name.empty? or line.empty?
|
40
|
+
@name += line
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_tag_list(line)
|
44
|
+
comment_start = (line =~ /([^@\w]#)|(^#)/)
|
45
|
+
|
46
|
+
if comment_start
|
47
|
+
line[0...comment_start].split.each { |single_tag| @tags << single_tag }
|
48
|
+
@tags << line[comment_start..line.length].strip
|
49
|
+
else
|
50
|
+
line.split.each { |single_tag| @tags << single_tag }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def evaluate_score
|
55
|
+
cls_name = self.class.to_s.gsub('CukeSniffer::', '')
|
56
|
+
rule_too_many_tags(cls_name)
|
57
|
+
rule_no_description(cls_name)
|
58
|
+
rule_numbers_in_name(cls_name)
|
59
|
+
rule_long_name(cls_name)
|
60
|
+
rule_commas_in_description(cls_name)
|
61
|
+
rule_comment_after_tag(cls_name)
|
62
|
+
rule_commented_tag(cls_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def rule_too_many_tags(type)
|
66
|
+
rule = RULES[:too_many_tags]
|
67
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
68
|
+
store_rule(rule, rule_phrase) if tags.size >= rule[:max]
|
69
|
+
end
|
70
|
+
|
71
|
+
def rule_no_description(type)
|
72
|
+
rule = RULES[:no_description]
|
73
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
74
|
+
store_rule(rule, rule_phrase) if name.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
def rule_numbers_in_name(type)
|
78
|
+
rule = RULES[:numbers_in_description]
|
79
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
80
|
+
store_rule(rule, rule_phrase) if name =~ /\d/
|
81
|
+
end
|
82
|
+
|
83
|
+
def rule_long_name(type)
|
84
|
+
rule = RULES[:long_name]
|
85
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
86
|
+
store_rule(rule, rule_phrase) if name.size >= rule[:max]
|
87
|
+
end
|
88
|
+
|
89
|
+
def rule_commas_in_description(type)
|
90
|
+
rule = RULES[:commas_in_description]
|
91
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
92
|
+
store_rule(rule, rule_phrase) if name.include?(',')
|
93
|
+
end
|
94
|
+
|
95
|
+
def rule_comment_after_tag(type)
|
96
|
+
rule = RULES[:comment_after_tag]
|
97
|
+
|
98
|
+
last_comment_index = tags.rindex { |single_tag| is_comment?(single_tag) }
|
99
|
+
if last_comment_index
|
100
|
+
comment_after_tag = tags[0...last_comment_index].any? { |single_tag| !is_comment?(single_tag) }
|
101
|
+
rule_phrase = rule[:phrase].gsub(/{.*}/, type)
|
102
|
+
store_rule(rule, rule_phrase) if comment_after_tag
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def rule_commented_tag(type)
|
107
|
+
rule = RULES[:commented_tag]
|
108
|
+
tags.each do |tag|
|
109
|
+
store_rule(rule, rule[:phrase].gsub(/{.*}/, type)) if is_comment?(tag) && tag.match(/@\S*/)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,160 @@
|
|
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 < RulesEvaluator
|
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, raw_code)
|
37
|
+
super(location)
|
38
|
+
|
39
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
40
|
+
@type = nil
|
41
|
+
@tags = []
|
42
|
+
@parameters = []
|
43
|
+
|
44
|
+
end_match_index = (raw_code.size - 1) - raw_code.reverse.index("end")
|
45
|
+
@code = raw_code[1...end_match_index]
|
46
|
+
|
47
|
+
raw_code.each do |line|
|
48
|
+
if line =~ HOOK_REGEX
|
49
|
+
matches = HOOK_REGEX.match(line)
|
50
|
+
@type = matches[:type]
|
51
|
+
hook_tag_regexp = /["']([^"']*)["']/
|
52
|
+
matches[:tags].scan(hook_tag_regexp).each { |tag| @tags << tag[0] } if matches[:tags]
|
53
|
+
@parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
evaluate_score
|
57
|
+
end
|
58
|
+
|
59
|
+
def ==(comparison_object) # :nodoc:
|
60
|
+
super(comparison_object) &&
|
61
|
+
comparison_object.type == type &&
|
62
|
+
comparison_object.tags == tags &&
|
63
|
+
comparison_object.parameters == parameters &&
|
64
|
+
comparison_object.code == code
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def evaluate_score
|
70
|
+
rule_empty_hook
|
71
|
+
rule_hook_not_in_hooks_file
|
72
|
+
rule_no_debugging
|
73
|
+
rule_all_comments
|
74
|
+
rule_conflicting_tags
|
75
|
+
rule_duplicate_tags
|
76
|
+
if @type == "Around"
|
77
|
+
rule_around_hook_without_2_parameters
|
78
|
+
rule_around_hook_no_block_call
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def rule_empty_hook
|
83
|
+
rule = RULES[:empty_hook]
|
84
|
+
store_rule(rule) if @code == []
|
85
|
+
end
|
86
|
+
|
87
|
+
def rule_hook_not_in_hooks_file
|
88
|
+
rule = RULES[:hook_not_in_hooks_file]
|
89
|
+
store_rule(rule) unless @location.include?(rule[:file])
|
90
|
+
end
|
91
|
+
|
92
|
+
def rule_around_hook_without_2_parameters
|
93
|
+
rule = RULES[:around_hook_without_2_parameters]
|
94
|
+
store_rule(rule) unless @parameters.count == 2
|
95
|
+
end
|
96
|
+
|
97
|
+
def rule_around_hook_no_block_call
|
98
|
+
return if rule_stored?(:around_hook_without_2_parameters)
|
99
|
+
rule = RULES[:around_hook_no_block_call]
|
100
|
+
block_call = "#{@parameters[1]}.call"
|
101
|
+
@code.each do |line|
|
102
|
+
return if line.include?(block_call)
|
103
|
+
end
|
104
|
+
store_rule(rule)
|
105
|
+
end
|
106
|
+
|
107
|
+
def rule_stored?(rule_symbol)
|
108
|
+
@rules_hash.keys.include?(RULES[rule_symbol][:phrase])
|
109
|
+
end
|
110
|
+
|
111
|
+
def rule_no_debugging
|
112
|
+
return if rule_stored?(:empty_hook)
|
113
|
+
rule = RULES[:hook_no_debugging]
|
114
|
+
begin_found = false
|
115
|
+
rescue_found = false
|
116
|
+
@code.each do |line|
|
117
|
+
begin_found = true if line.include?("begin")
|
118
|
+
rescue_found = true if line.include?("rescue")
|
119
|
+
break if begin_found and rescue_found
|
120
|
+
end
|
121
|
+
store_rule(rule) unless begin_found and rescue_found
|
122
|
+
end
|
123
|
+
|
124
|
+
def rule_all_comments
|
125
|
+
rule = RULES[:hook_all_comments]
|
126
|
+
@code.each do |line|
|
127
|
+
return unless is_comment?(line)
|
128
|
+
end
|
129
|
+
store_rule(rule)
|
130
|
+
end
|
131
|
+
|
132
|
+
def rule_conflicting_tags
|
133
|
+
rule = RULES[:hook_conflicting_tags]
|
134
|
+
all_tags = flatten_tags
|
135
|
+
|
136
|
+
all_tags.each do |single_tag|
|
137
|
+
tag = single_tag.gsub("~", "")
|
138
|
+
if all_tags.include?(tag) and all_tags.include?("~#{tag}")
|
139
|
+
store_rule(rule)
|
140
|
+
return
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def flatten_tags
|
146
|
+
all_tags = []
|
147
|
+
@tags.each { |single_tag| all_tags << single_tag.split(',') }
|
148
|
+
all_tags.flatten
|
149
|
+
end
|
150
|
+
|
151
|
+
def rule_duplicate_tags
|
152
|
+
rule = RULES[:hook_duplicate_tags]
|
153
|
+
all_tags = flatten_tags
|
154
|
+
unique_tags = all_tags.uniq
|
155
|
+
|
156
|
+
store_rule(rule) unless all_tags == unique_tags
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|