foodcritic 3.0.3 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +6 -14
  2. data/CHANGELOG.md +65 -0
  3. data/README.md +1 -1
  4. data/chef_dsl_metadata/chef_11.10.0.json +10272 -0
  5. data/chef_dsl_metadata/chef_11.10.2.json +10272 -0
  6. data/chef_dsl_metadata/chef_11.10.4.json +10272 -0
  7. data/chef_dsl_metadata/chef_11.6.2.json +9566 -0
  8. data/chef_dsl_metadata/chef_11.8.0.json +10074 -0
  9. data/chef_dsl_metadata/chef_11.8.2.json +10074 -0
  10. data/features/001_check_node_access.feature +60 -0
  11. data/features/003_check_for_chef_server.feature +5 -0
  12. data/features/006_check_file_mode.feature +1 -0
  13. data/features/022_check_for_dodgy_conditions_within_loop.feature +10 -0
  14. data/features/040_check_raw_git_usage.feature +6 -0
  15. data/features/047_check_for_attribute_assignment_without_precedence.feature +2 -0
  16. data/features/build_framework_support.feature +10 -0
  17. data/features/exclude_paths_to_lint.feature +19 -0
  18. data/features/show_lines_matched.feature +4 -4
  19. data/features/sort_warnings.feature +1 -1
  20. data/features/step_definitions/cookbook_steps.rb +117 -24
  21. data/features/support/command_helpers.rb +45 -12
  22. data/features/support/env.rb +5 -0
  23. data/lib/foodcritic/api.rb +122 -99
  24. data/lib/foodcritic/ast.rb +6 -7
  25. data/lib/foodcritic/chef.rb +24 -23
  26. data/lib/foodcritic/command_line.rb +49 -41
  27. data/lib/foodcritic/domain.rb +12 -10
  28. data/lib/foodcritic/dsl.rb +4 -7
  29. data/lib/foodcritic/error_checker.rb +0 -3
  30. data/lib/foodcritic/linter.rb +45 -43
  31. data/lib/foodcritic/notifications.rb +32 -32
  32. data/lib/foodcritic/output.rb +3 -6
  33. data/lib/foodcritic/rake_task.rb +9 -10
  34. data/lib/foodcritic/rules.rb +278 -240
  35. data/lib/foodcritic/template.rb +6 -13
  36. data/lib/foodcritic/version.rb +1 -1
  37. data/lib/foodcritic/xml.rb +1 -3
  38. data/man/foodcritic.1 +6 -2
  39. data/man/foodcritic.1.ronn +4 -1
  40. data/spec/foodcritic/linter_spec.rb +2 -2
  41. data/spec/regression/expected-output.txt +296 -1
  42. metadata +160 -138
@@ -1,22 +1,21 @@
1
1
  module FoodCritic
2
2
  module AST
3
-
4
3
  private
5
4
 
6
5
  def ast_hash_node?(node)
7
- node.first.respond_to?(:first) and node.first.first == :assoc_new
6
+ node.first.respond_to?(:first) && node.first.first == :assoc_new
8
7
  end
9
8
 
10
9
  def ast_node_has_children?(node)
11
- node.respond_to?(:first) and ! node.respond_to?(:match)
10
+ node.respond_to?(:first) && !node.respond_to?(:match)
12
11
  end
13
12
 
14
13
  # If the provided node is the line / column information.
15
14
  def position_node?(node)
16
- node.respond_to?(:length) and node.length == 2 and
17
- node.respond_to?(:all?) and node.all?{|child| child.respond_to?(:to_i)}
15
+ node.respond_to?(:length) &&
16
+ node.length == 2 &&
17
+ node.respond_to?(:all?) &&
18
+ node.all? { |child| child.respond_to?(:to_i) }
18
19
  end
19
-
20
20
  end
21
-
22
21
  end
@@ -1,8 +1,6 @@
1
1
  module FoodCritic
2
-
3
2
  # Encapsulates functions that previously were calls to the Chef gem.
4
3
  module Chef
5
-
6
4
  def chef_dsl_methods
7
5
  load_metadata
8
6
  @dsl_metadata[:dsl_methods].map(&:to_sym)
@@ -25,7 +23,7 @@ module FoodCritic
25
23
 
26
24
  # Is this a valid Lucene query?
27
25
  def valid_query?(query)
28
- raise ArgumentError, "Query cannot be nil or empty" if query.to_s.empty?
26
+ fail ArgumentError, 'Query cannot be nil or empty' if query.to_s.empty?
29
27
 
30
28
  # Attempt to create a search query parser
31
29
  search = FoodCritic::Chef::Search.new
@@ -48,23 +46,27 @@ module FoodCritic
48
46
  # The DSL metadata doesn't necessarily reflect the version of Chef in the
49
47
  # local user gemset.
50
48
  def load_metadata
51
- version = self.respond_to?(:chef_version) ? chef_version : Linter::DEFAULT_CHEF_VERSION
49
+ version = if self.respond_to?(:chef_version)
50
+ chef_version
51
+ else
52
+ Linter::DEFAULT_CHEF_VERSION
53
+ end
52
54
  metadata_path = [version, version.sub(/\.[a-z].*/, ''),
53
- Linter::DEFAULT_CHEF_VERSION].map do |version|
54
- metadata_path(version)
55
- end.find{|m| File.exists?(m)}
55
+ Linter::DEFAULT_CHEF_VERSION].map do |version|
56
+ metadata_path(version)
57
+ end.find { |m| File.exist?(m) }
56
58
  @dsl_metadata ||= Yajl::Parser.parse(IO.read(metadata_path),
57
- :symbolize_keys => true)
59
+ symbolize_keys: true)
58
60
  end
59
61
 
60
62
  def metadata_path(chef_version)
61
63
  File.join(File.dirname(__FILE__), '..', '..',
62
- "chef_dsl_metadata/chef_#{chef_version}.json")
64
+ "chef_dsl_metadata/chef_#{chef_version}.json")
63
65
  end
64
66
 
65
67
  def resource_check?(key, resource_type, field)
66
68
  if resource_type.to_s.empty? || field.to_s.empty?
67
- raise ArgumentError, "Arguments cannot be nil or empty."
69
+ fail ArgumentError, 'Arguments cannot be nil or empty.'
68
70
  end
69
71
 
70
72
  load_metadata
@@ -80,10 +82,10 @@ module FoodCritic
80
82
  end
81
83
 
82
84
  class Search
83
-
84
85
  # The search grammars that ship with any Chef gems installed locally.
85
86
  # These are returned in descending version order (a newer Chef version
86
87
  # could break our ability to load the grammar).
88
+ # Grammars are not available from Chef 11+.
87
89
  def chef_search_grammars
88
90
  Gem.path.map do |gem_path|
89
91
  Dir["#{gem_path}/gems/chef-*/**/lucene.treetop"]
@@ -92,16 +94,17 @@ module FoodCritic
92
94
 
93
95
  # Create the search parser from the first loadable grammar.
94
96
  def create_parser(grammar_paths)
95
- @search_parser ||= grammar_paths.inject(nil) do |parser,lucene_grammar|
96
- begin
97
- break parser unless parser.nil?
98
- # Don't instantiate custom nodes
99
- Treetop.load_from_string(
100
- IO.read(lucene_grammar).gsub(/<[^>]+>/, ''))
101
- LuceneParser.new
102
- rescue
103
- # Silently swallow and try the next grammar
104
- end
97
+ @search_parser ||=
98
+ grammar_paths.inject(nil) do |parser, lucene_grammar|
99
+ begin
100
+ break parser unless parser.nil?
101
+ # Don't instantiate custom nodes
102
+ Treetop.load_from_string(
103
+ IO.read(lucene_grammar).gsub(/<[^>]+>/, ''))
104
+ LuceneParser.new
105
+ rescue
106
+ # Silently swallow and try the next grammar
107
+ end
105
108
  end
106
109
  end
107
110
 
@@ -114,8 +117,6 @@ module FoodCritic
114
117
  def parser
115
118
  @search_parser
116
119
  end
117
-
118
120
  end
119
121
  end
120
-
121
122
  end
@@ -1,8 +1,6 @@
1
1
  module FoodCritic
2
-
3
2
  # Command line parsing.
4
3
  class CommandLine
5
-
6
4
  # Create a new instance of CommandLine
7
5
  #
8
6
  # @param [Array] args The command line arguments
@@ -10,59 +8,69 @@ module FoodCritic
10
8
  @args = args
11
9
  @original_args = args.dup
12
10
  @options = {
13
- :fail_tags => [],
14
- :tags => [],
15
- :include_rules => [],
16
- :cookbook_paths => [],
17
- :role_paths => [],
18
- :environment_paths => []
11
+ fail_tags: [],
12
+ tags: [],
13
+ include_rules: [],
14
+ cookbook_paths: [],
15
+ role_paths: [],
16
+ environment_paths: [],
17
+ exclude_paths: []
19
18
  }
20
19
  @parser = OptionParser.new do |opts|
21
20
  opts.banner = 'foodcritic [cookbook_paths]'
22
- opts.on("-t", "--tags TAGS",
23
- "Only check against rules with the specified tags.") do |t|
21
+ opts.on('-t', '--tags TAGS',
22
+ 'Check against (or exclude ~) rules with the '\
23
+ 'specified tags.') do |t|
24
24
  @options[:tags] << t
25
25
  end
26
- opts.on("-f", "--epic-fail TAGS",
27
- "Fail the build if any of the specified tags are matched ('any' -> fail on any match).") do |t|
26
+ opts.on('-f', '--epic-fail TAGS',
27
+ "Fail the build based on tags. Use 'any' to fail "\
28
+ 'on all warnings.') do |t|
28
29
  @options[:fail_tags] << t
29
30
  end
30
- opts.on("-c", "--chef-version VERSION",
31
- "Only check against rules valid for this version of Chef.") do |c|
31
+ opts.on('-c', '--chef-version VERSION',
32
+ 'Only check against rules valid for this version '\
33
+ 'of Chef.') do |c|
32
34
  @options[:chef_version] = c
33
35
  end
34
- opts.on("-B", "--cookbook-path PATH",
35
- "Cookbook path(s) to check.") do |b|
36
+ opts.on('-B', '--cookbook-path PATH',
37
+ 'Cookbook path(s) to check.') do |b|
36
38
  @options[:cookbook_paths] << b
37
39
  end
38
- opts.on("-C", "--[no-]context",
39
- "Show lines matched against rather than the default summary.") do |c|
40
+ opts.on('-C', '--[no-]context',
41
+ 'Show lines matched against rather than the '\
42
+ 'default summary.') do |c|
40
43
  @options[:context] = c
41
44
  end
42
- opts.on("-E", "--environment-path PATH",
43
- "Environment path(s) to check.") do |e|
45
+ opts.on('-E', '--environment-path PATH',
46
+ 'Environment path(s) to check.') do |e|
44
47
  @options[:environment_paths] << e
45
48
  end
46
- opts.on("-I", "--include PATH",
47
- "Additional rule file path(s) to load.") do |i|
49
+ opts.on('-I', '--include PATH',
50
+ 'Additional rule file path(s) to load.') do |i|
48
51
  @options[:include_rules] << i
49
52
  end
50
- opts.on("-G", "--search-gems",
51
- "Search rubygems for rule files with the path foodcritic/rules/**/*.rb") do |g|
53
+ opts.on('-G', '--search-gems',
54
+ 'Search rubygems for rule files with the path '\
55
+ 'foodcritic/rules/**/*.rb') do |g|
52
56
  @options[:search_gems] = true
53
57
  end
54
- opts.on("-R", "--role-path PATH",
55
- "Role path(s) to check.") do |r|
58
+ opts.on('-R', '--role-path PATH',
59
+ 'Role path(s) to check.') do |r|
56
60
  @options[:role_paths] << r
57
61
  end
58
- opts.on("-S", "--search-grammar PATH",
59
- "Specify grammar to use when validating search syntax.") do |s|
62
+ opts.on('-S', '--search-grammar PATH',
63
+ 'Specify grammar to use when validating search syntax.') do |s|
60
64
  @options[:search_grammar] = s
61
65
  end
62
- opts.on("-V", "--version",
63
- "Display the foodcritic version.") do |v|
66
+ opts.on('-V', '--version',
67
+ 'Display the foodcritic version.') do |v|
64
68
  @options[:version] = true
65
69
  end
70
+ opts.on('-X', '--exclude PATH',
71
+ 'Exclude path(s) from being linted.') do |e|
72
+ options[:exclude_paths] << e
73
+ end
66
74
  end
67
75
  # -v is not implemented but OptionParser gives the Foodcritic's version
68
76
  # if that flag is passed
@@ -81,7 +89,7 @@ module FoodCritic
81
89
  #
82
90
  # @return [Boolean] True if help should be shown.
83
91
  def show_help?
84
- @args.length == 1 and @args.first == '--help'
92
+ @args.length == 1 && @args.first == '--help'
85
93
  end
86
94
 
87
95
  # The help text.
@@ -111,7 +119,7 @@ module FoodCritic
111
119
  def valid_paths?
112
120
  paths = options[:cookbook_paths] + options[:role_paths] +
113
121
  options[:environment_paths]
114
- paths.any? && paths.all?{|path| File.exists?(path) }
122
+ paths.any? && paths.all? { |path| File.exist?(path) }
115
123
  end
116
124
 
117
125
  # Is the search grammar specified valid?
@@ -120,7 +128,7 @@ module FoodCritic
120
128
  # loaded.
121
129
  def valid_grammar?
122
130
  return true unless options.key?(:search_grammar)
123
- return false unless File.exists?(options[:search_grammar])
131
+ return false unless File.exist?(options[:search_grammar])
124
132
  search = FoodCritic::Chef::Search.new
125
133
  search.create_parser([options[:search_grammar]])
126
134
  search.parser?
@@ -142,7 +150,7 @@ module FoodCritic
142
150
 
143
151
  # The environment paths to check
144
152
  #
145
- # @return [Array<String>] Path(s) to the environment directories being checked.
153
+ # @return [Array<String>] Path(s) to the environment directories checked.
146
154
  def environment_paths
147
155
  Array(@options[:environment_paths])
148
156
  end
@@ -159,11 +167,13 @@ module FoodCritic
159
167
  #
160
168
  # @return [Hash] The parsed command-line options.
161
169
  def options
162
- original_options.merge({
163
- :cookbook_paths => cookbook_paths,
164
- :role_paths => role_paths,
165
- :environment_paths => environment_paths,
166
- })
170
+ original_options.merge(
171
+ {
172
+ cookbook_paths: cookbook_paths,
173
+ role_paths: role_paths,
174
+ environment_paths: environment_paths,
175
+ }
176
+ )
167
177
  end
168
178
 
169
179
  # The original command-line options
@@ -172,7 +182,5 @@ module FoodCritic
172
182
  def original_options
173
183
  @options
174
184
  end
175
-
176
185
  end
177
-
178
186
  end
@@ -1,7 +1,6 @@
1
1
  require 'gherkin/tag_expression'
2
2
 
3
3
  module FoodCritic
4
-
5
4
  # A warning of a possible issue
6
5
  class Warning
7
6
  attr_reader :rule, :match, :is_failed
@@ -11,9 +10,13 @@ module FoodCritic
11
10
  # Warning.new(rule, :filename => 'foo/recipes.default.rb',
12
11
  # :line => 5, :column=> 40)
13
12
  #
14
- def initialize(rule, match={}, options={})
13
+ def initialize(rule, match = {}, options = {})
15
14
  @rule, @match = rule, match
16
- @is_failed = options[:fail_tags].empty? ? false : rule.matches_tags?(options[:fail_tags])
15
+ @is_failed = if options[:fail_tags].empty?
16
+ false
17
+ else
18
+ rule.matches_tags?(options[:fail_tags])
19
+ end
17
20
  end
18
21
 
19
22
  # If this warning has failed or not.
@@ -24,7 +27,6 @@ module FoodCritic
24
27
 
25
28
  # The collected warnings (if any) raised against a cookbook tree.
26
29
  class Review
27
-
28
30
  attr_reader :cookbook_paths, :warnings
29
31
 
30
32
  def initialize(cookbook_paths, warnings)
@@ -51,23 +53,24 @@ module FoodCritic
51
53
  @warnings.map do |w|
52
54
  ["#{w.rule.code}: #{w.rule.name}: #{w.match[:filename]}",
53
55
  w.match[:line].to_i]
54
- end.sort do |x,y|
56
+ end.sort do |x, y|
55
57
  x.first == y.first ? x[1] <=> y[1] : x.first <=> y.first
56
- end.map{|w|"#{w.first}:#{w[1]}"}.uniq.join("\n")
58
+ end.map { |w|"#{w.first}:#{w[1]}" }.uniq.join("\n")
57
59
  end
58
60
  end
59
61
 
60
62
  # A rule to be matched against.
61
63
  class Rule
62
64
  attr_accessor :code, :name, :applies_to, :cookbook, :attributes, :recipe,
63
- :provider, :resource, :metadata, :library, :template, :role, :environment
65
+ :provider, :resource, :metadata, :library, :template, :role,
66
+ :environment
64
67
 
65
68
  attr_writer :tags
66
69
 
67
70
  def initialize(code, name)
68
71
  @code, @name = code, name
69
72
  @tags = [code]
70
- @applies_to = Proc.new {|version| true}
73
+ @applies_to = Proc.new { |version| true }
71
74
  end
72
75
 
73
76
  # The tags associated with this rule. Rule is always tagged with the tag
@@ -76,7 +79,7 @@ module FoodCritic
76
79
  ['any'] + @tags
77
80
  end
78
81
 
79
- # Checks the rule's tags to see if they match a Gherkin (Cucumber) expression
82
+ # Checks the rule tags to see if they match a Gherkin (Cucumber) expression
80
83
  def matches_tags?(tag_expr)
81
84
  Gherkin::TagExpression.new(tag_expr).evaluate(tags.map do |t|
82
85
  Gherkin::Formatter::Model::Tag.new(t, 1)
@@ -88,5 +91,4 @@ module FoodCritic
88
91
  "#{@code}: #{@name}"
89
92
  end
90
93
  end
91
-
92
94
  end
@@ -1,7 +1,6 @@
1
1
  require 'pathname'
2
2
 
3
3
  module FoodCritic
4
-
5
4
  # The DSL methods exposed for defining rules. A minimal example rule:
6
5
  #
7
6
  # rule "FC123", "My rule name" do
@@ -27,7 +26,7 @@ module FoodCritic
27
26
 
28
27
  include Api
29
28
 
30
- def initialize(chef_version=Linter::DEFAULT_CHEF_VERSION)
29
+ def initialize(chef_version = Linter::DEFAULT_CHEF_VERSION)
31
30
  @chef_version = chef_version
32
31
  end
33
32
 
@@ -38,8 +37,8 @@ module FoodCritic
38
37
  yield self
39
38
  end
40
39
 
41
- # Add tags to the rule which can be used by the end user to filter the rules
42
- # to be applied.
40
+ # Add tags to the rule which can be used by the end user to filter the
41
+ # rules to be applied.
43
42
  def tags(tags)
44
43
  rules.last.tags += tags
45
44
  end
@@ -73,7 +72,7 @@ module FoodCritic
73
72
  rule_block :role
74
73
 
75
74
  # Load the ruleset(s).
76
- def self.load(paths, chef_version=Linter::DEFAULT_CHEF_VERSION)
75
+ def self.load(paths, chef_version = Linter::DEFAULT_CHEF_VERSION)
77
76
  dsl = RuleDsl.new(chef_version)
78
77
  paths.map do |path|
79
78
  File.directory?(path) ? Dir["#{path}/**/*.rb"].sort : path
@@ -82,7 +81,5 @@ module FoodCritic
82
81
  end
83
82
  dsl.rules
84
83
  end
85
-
86
84
  end
87
-
88
85
  end
@@ -1,8 +1,6 @@
1
1
  module FoodCritic
2
-
3
2
  # Expose if any errors are found in parsing
4
3
  class ErrorChecker < Ripper::SexpBuilder
5
-
6
4
  # Create a new instance of ErrorChecker
7
5
  #
8
6
  # @see Ripper::SexpBuilder#initialize
@@ -25,6 +23,5 @@ module FoodCritic
25
23
  end
26
24
 
27
25
  self.register_error_handlers
28
-
29
26
  end
30
27
  end
@@ -6,12 +6,11 @@ require 'set'
6
6
  module FoodCritic
7
7
  # The main entry point for linting your Chef cookbooks.
8
8
  class Linter
9
-
10
9
  include FoodCritic::Api
11
10
 
12
11
  # The default version that will be used to determine relevant rules. This
13
12
  # can be over-ridden at the command line with the `--chef-version` option.
14
- DEFAULT_CHEF_VERSION = "11.4.0"
13
+ DEFAULT_CHEF_VERSION = '11.10.4'
15
14
  attr_reader :chef_version
16
15
 
17
16
  # Perform a lint check. This method is intended for use by the command-line
@@ -21,7 +20,7 @@ module FoodCritic
21
20
  # The first item is the string output, the second is exit code.
22
21
  return [cmd_line.help, 0] if cmd_line.show_help?
23
22
  return [cmd_line.version, 0] if cmd_line.show_version?
24
- if ! cmd_line.valid_grammar?
23
+ if !cmd_line.valid_grammar?
25
24
  [cmd_line.help, 4]
26
25
  elsif cmd_line.valid_paths?
27
26
  review = FoodCritic::Linter.new.check(cmd_line.options)
@@ -45,7 +44,6 @@ module FoodCritic
45
44
  # * `:exclude_paths` - Paths to exclude from linting
46
45
  #
47
46
  def check(options = {})
48
-
49
47
  options = setup_defaults(options)
50
48
  @options = options
51
49
  @chef_version = options[:chef_version] || DEFAULT_CHEF_VERSION
@@ -58,33 +56,34 @@ module FoodCritic
58
56
  files_to_process(paths).each do |p|
59
57
 
60
58
  relevant_tags = if options[:tags].any?
61
- options[:tags]
62
- else
63
- cookbook_tags(p[:filename])
64
- end
59
+ options[:tags]
60
+ else
61
+ cookbook_tags(p[:filename])
62
+ end
65
63
 
66
64
  active_rules(relevant_tags).each do |rule|
67
65
 
68
66
  state = {
69
- :path_type => p[:path_type],
70
- :file => p[:filename],
71
- :ast => read_ast(p[:filename]),
72
- :rule => rule,
73
- :last_dir => last_dir
67
+ path_type: p[:path_type],
68
+ file: p[:filename],
69
+ ast: read_ast(p[:filename]),
70
+ rule: rule,
71
+ last_dir: last_dir
74
72
  }
75
73
 
76
74
  matches = if p[:path_type] == :cookbook
77
- cookbook_matches(state)
78
- else
79
- other_matches(state)
80
- end
75
+ cookbook_matches(state)
76
+ else
77
+ other_matches(state)
78
+ end
81
79
 
82
80
  matches = remove_ignored(matches, state[:rule], state[:file])
83
81
 
84
82
  # Convert the matches into warnings
85
83
  matches.each do |match|
86
84
  warnings << Warning.new(state[:rule],
87
- {:filename => state[:file]}.merge(match), options)
85
+ { filename: state[:file] }.merge(match),
86
+ options)
88
87
  matched_rule_tags << state[:rule].tags
89
88
  end
90
89
  end
@@ -133,8 +132,8 @@ module FoodCritic
133
132
  private
134
133
 
135
134
  def rule_files_in_gems
136
- Gem::Specification.latest_specs(true).map do |spec|
137
- spec.matches_for_glob('foodcritic/rules/**/*.rb')
135
+ Gem::Specification.latest_specs(true).map do |spec|
136
+ spec.matches_for_glob('foodcritic/rules/**/*.rb')
138
137
  end.flatten
139
138
  end
140
139
 
@@ -142,14 +141,14 @@ module FoodCritic
142
141
  matches.reject do |m|
143
142
  matched_file = m[:filename] || file
144
143
  (line = m[:line]) && File.exist?(matched_file) &&
145
- ignore_line_match?(File.readlines(matched_file)[line-1], rule)
144
+ ignore_line_match?(File.readlines(matched_file)[line - 1], rule)
146
145
  end
147
146
  end
148
147
 
149
148
  def ignore_line_match?(line, rule)
150
149
  ignores = line.to_s[/\s+#\s*(.*)/, 1]
151
- if ignores and ignores.include?('~')
152
- ! rule.matches_tags?(ignores.split(/[ ,]/))
150
+ if ignores && ignores.include?('~')
151
+ !rule.matches_tags?(ignores.split(/[ ,]/))
153
152
  else
154
153
  false
155
154
  end
@@ -176,18 +175,17 @@ module FoodCritic
176
175
 
177
176
  def active_rules(tags)
178
177
  @rules.select do |rule|
179
- rule.matches_tags?(tags) and
180
- applies_to_version?(rule, chef_version)
178
+ rule.matches_tags?(tags) && applies_to_version?(rule, chef_version)
181
179
  end
182
180
  end
183
181
 
184
182
  def cookbook_dir(file)
185
183
  Pathname.new(File.join(File.dirname(file),
186
- case File.basename(file)
187
- when 'metadata.rb' then ''
188
- when /\.erb$/ then '../..'
189
- else '..'
190
- end)).cleanpath
184
+ case File.basename(file)
185
+ when 'metadata.rb' then ''
186
+ when /\.erb$/ then '../..'
187
+ else '..'
188
+ end)).cleanpath
191
189
  end
192
190
 
193
191
  def dsl_method_for_file(file)
@@ -208,26 +206,31 @@ module FoodCritic
208
206
  # Return the files within a cookbook tree that we are interested in trying
209
207
  # to match rules against.
210
208
  def files_to_process(paths)
211
- paths.reject{|type, _| type == :exclude}.map do |path_type, dirs|
209
+ paths.reject { |type, _| type == :exclude }.map do |path_type, dirs|
212
210
  dirs.map do |dir|
213
211
  exclusions = []
212
+
214
213
  unless paths[:exclude].empty?
215
- exclusions = Dir.glob(paths[:exclude].map{|p| File.join(dir, p)})
214
+ exclusions = Dir.glob(paths[:exclude].map do |p|
215
+ File.join(dir, p, '**/**')
216
+ end)
216
217
  end
217
218
 
218
219
  if File.directory?(dir)
219
220
  glob = if path_type == :cookbook
220
- '{metadata.rb,{attributes,definitions,libraries,providers,recipes,resources}/*.rb,templates/*/*.erb}'
221
- else
222
- '*.rb'
223
- end
221
+ '{metadata.rb,{attributes,definitions,libraries,'\
222
+ 'providers,recipes,resources}/*.rb,templates/*/*.erb}'
223
+ else
224
+ '*.rb'
225
+ end
226
+
224
227
  (Dir.glob(File.join(dir, glob)) +
225
228
  Dir.glob(File.join(dir, "*/#{glob}")) - exclusions)
226
229
  else
227
230
  dir unless exclusions.include?(dir)
228
231
  end
229
232
  end.compact.flatten.map do |filename|
230
- {:filename => filename, :path_type => path_type}
233
+ { filename: filename, path_type: path_type }
231
234
  end
232
235
  end.flatten
233
236
  end
@@ -243,7 +246,7 @@ module FoodCritic
243
246
  if m.respond_to?(:node_name)
244
247
  match(m)
245
248
  elsif m.respond_to?(:xpath)
246
- m.to_a.map{|m| match(m)}
249
+ m.to_a.map { |m| match(m) }
247
250
  else
248
251
  m
249
252
  end
@@ -259,8 +262,8 @@ module FoodCritic
259
262
  [key, Array(value)] if key.to_s.end_with?('paths')
260
263
  end.compact]
261
264
 
262
- unless paths.find{|k, v| k != :exclude_paths and ! v.empty?}
263
- raise ArgumentError, "A cookbook path or role path must be specified"
265
+ unless paths.find { |k, v| k != :exclude_paths && !v.empty? }
266
+ fail ArgumentError, 'A cookbook path or role path must be specified'
264
267
  end
265
268
 
266
269
  Hash[paths.map do |key, value|
@@ -269,9 +272,8 @@ module FoodCritic
269
272
  end
270
273
 
271
274
  def setup_defaults(options)
272
- {:tags => [], :fail_tags => [], :include_rules => [], :exclude_paths => [],
273
- :cookbook_paths => [], :role_paths => []}.merge(options)
275
+ { tags: [], fail_tags: [], include_rules: [], exclude_paths: [],
276
+ cookbook_paths: [], role_paths: [] }.merge(options)
274
277
  end
275
-
276
278
  end
277
279
  end