foodcritic 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/foodcritic +7 -2
- data/lib/foodcritic.rb +3 -0
- data/lib/foodcritic/command_line.rb +67 -0
- data/lib/foodcritic/domain.rb +5 -3
- data/lib/foodcritic/dsl.rb +7 -0
- data/lib/foodcritic/helpers.rb +14 -4
- data/lib/foodcritic/linter.rb +9 -20
- data/lib/foodcritic/output.rb +70 -0
- data/lib/foodcritic/rules.rb +50 -16
- data/lib/foodcritic/version.rb +1 -1
- metadata +31 -18
data/bin/foodcritic
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require_relative '../lib/foodcritic'
|
3
|
-
|
4
|
-
|
3
|
+
module FoodCritic
|
4
|
+
cmd_line = CommandLine.new(ARGV)
|
5
|
+
review, status = Linter.check(cmd_line)
|
6
|
+
printer = cmd_line.show_context? ? ContextOutput.new : SummaryOutput.new
|
7
|
+
printer.output(review)
|
8
|
+
exit status.to_i
|
9
|
+
end
|
data/lib/foodcritic.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'chef'
|
2
2
|
require 'pry'
|
3
|
+
require 'rak'
|
4
|
+
require_relative 'foodcritic/command_line'
|
3
5
|
require_relative 'foodcritic/domain'
|
4
6
|
require_relative 'foodcritic/error_checker'
|
5
7
|
require_relative 'foodcritic/helpers'
|
6
8
|
require_relative 'foodcritic/dsl'
|
7
9
|
require_relative 'foodcritic/linter'
|
10
|
+
require_relative 'foodcritic/output'
|
8
11
|
require_relative 'foodcritic/version'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module FoodCritic
|
2
|
+
|
3
|
+
# Command line parsing.
|
4
|
+
class CommandLine
|
5
|
+
|
6
|
+
# Create a new instance of CommandLine
|
7
|
+
#
|
8
|
+
# @param [Array] args The command line arguments
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
@options = {}
|
12
|
+
@options[:fail_tags] = []; @options[:tags] = []
|
13
|
+
@parser = OptionParser.new do |opts|
|
14
|
+
opts.banner = 'foodcritic [cookbook_path]'
|
15
|
+
opts.on("-r", "--[no-]repl", "Drop into a REPL for interactive rule editing.") {|r|options[:repl] = r}
|
16
|
+
opts.on("-t", "--tags TAGS", "Only check against rules with the specified tags.") {|t|options[:tags] << t}
|
17
|
+
opts.on("-f", "--epic-fail TAGS", "Fail the build if any of the specified tags are matched.") {|t|options[:fail_tags] << t}
|
18
|
+
opts.on("-C", "--[no-]context", "Show lines matched against rather than the default summary.") {|c|options[:context] = c}
|
19
|
+
end
|
20
|
+
@parser.parse!(args) unless show_help?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Show the command help to the end user?
|
24
|
+
#
|
25
|
+
# @return [Boolean] True if help should be shown.
|
26
|
+
def show_help?
|
27
|
+
@args.length == 1 and @args.first == '--help'
|
28
|
+
end
|
29
|
+
|
30
|
+
# The help text.
|
31
|
+
#
|
32
|
+
# @return [String] Help text describing the command-line options available.
|
33
|
+
def help
|
34
|
+
@parser.help
|
35
|
+
end
|
36
|
+
|
37
|
+
# If the cookbook path provided is valid
|
38
|
+
#
|
39
|
+
# @return [Boolean] True if the path is a directory that exists.
|
40
|
+
def valid_path?
|
41
|
+
@args.length == 1 and Dir.exists?(@args[0])
|
42
|
+
end
|
43
|
+
|
44
|
+
# The cookbook path
|
45
|
+
#
|
46
|
+
# @return [String] Path to the cookbook(s) being checked.
|
47
|
+
def cookbook_path
|
48
|
+
@args[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
# If matches should be shown with context rather than the default summary display.
|
52
|
+
#
|
53
|
+
# @return [Boolean] True if matches should be shown with context.
|
54
|
+
def show_context?
|
55
|
+
@options[:context]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Parsed command-line options
|
59
|
+
#
|
60
|
+
# @return [Hash] The parsed command-line options.
|
61
|
+
def options
|
62
|
+
@options
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/foodcritic/domain.rb
CHANGED
@@ -19,13 +19,15 @@ module FoodCritic
|
|
19
19
|
# The collected warnings (if any) raised against a cookbook tree.
|
20
20
|
class Review
|
21
21
|
|
22
|
-
attr_reader :warnings
|
22
|
+
attr_reader :cookbook_path, :warnings
|
23
23
|
|
24
24
|
# Create a new review
|
25
25
|
#
|
26
|
+
# @param [String] cookbook_path The path this review was performed against
|
26
27
|
# @param [Array] warnings The warnings raised in this review
|
27
28
|
# @param [Boolean] is_failed Have warnings been raised that mean this should be considered failed?
|
28
|
-
def initialize(warnings, is_failed)
|
29
|
+
def initialize(cookbook_path, warnings, is_failed)
|
30
|
+
@cookbook_path = cookbook_path
|
29
31
|
@warnings = warnings
|
30
32
|
@is_failed = is_failed
|
31
33
|
end
|
@@ -49,7 +51,7 @@ module FoodCritic
|
|
49
51
|
|
50
52
|
# A rule to be matched against.
|
51
53
|
class Rule
|
52
|
-
attr_accessor :code, :name, :cookbook, :recipe, :provider, :tags
|
54
|
+
attr_accessor :code, :name, :cookbook, :recipe, :provider, :resource, :tags
|
53
55
|
|
54
56
|
# Create a new rule
|
55
57
|
#
|
data/lib/foodcritic/dsl.rb
CHANGED
@@ -34,6 +34,13 @@ module FoodCritic
|
|
34
34
|
rules.last.recipe = block
|
35
35
|
end
|
36
36
|
|
37
|
+
# Define a matcher that will be passed the AST with this method.
|
38
|
+
#
|
39
|
+
# @param [block] block Your implemented matcher that returns a match Hash.
|
40
|
+
def resource(&block)
|
41
|
+
rules.last.resource = block
|
42
|
+
end
|
43
|
+
|
37
44
|
# Define a matcher that will be passed the AST with this method.
|
38
45
|
#
|
39
46
|
# @param [block] block Your implemented matcher that returns a match Hash.
|
data/lib/foodcritic/helpers.rb
CHANGED
@@ -85,11 +85,13 @@ module FoodCritic
|
|
85
85
|
def attribute_access(ast, accessed_via, exclude_with_dots)
|
86
86
|
%w{node default override set normal}.map do |att_type|
|
87
87
|
if accessed_via == :vivified
|
88
|
-
|
88
|
+
calls = ast.xpath(%Q{//*[self::call or self::field][vcall/ident/@value='#{att_type}' or
|
89
89
|
var_ref/ident/@value='#{att_type}'][@value='.']})
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
calls.select do |call|
|
91
|
+
call.xpath("aref/args_add_block").size == 0 and (call.xpath("descendant::ident").size > 1 and
|
92
|
+
call.xpath("descendant::ident").first['value'] == att_type.to_s and
|
93
|
+
! dsl_methods.include?(call.xpath("ident/@value").to_s.to_sym))
|
94
|
+
end
|
93
95
|
else
|
94
96
|
accessed_via = 'tstring_content' if accessed_via == :string
|
95
97
|
expr = '//*[self::aref_field or self::aref][descendant::ident'
|
@@ -100,6 +102,14 @@ module FoodCritic
|
|
100
102
|
end.flatten.sort
|
101
103
|
end
|
102
104
|
|
105
|
+
# The set of methods in the Chef DSL
|
106
|
+
#
|
107
|
+
# @return [Array] Array of method symbols
|
108
|
+
def dsl_methods
|
109
|
+
(Chef::Node.public_instance_methods +
|
110
|
+
Chef::Mixin::RecipeDefinitionDSLCore.included_modules.map{|mixin| mixin.public_instance_methods}).flatten.sort.uniq
|
111
|
+
end
|
112
|
+
|
103
113
|
# Find Chef resources of the specified type.
|
104
114
|
# TODO: Include blockless resources
|
105
115
|
#
|
data/lib/foodcritic/linter.rb
CHANGED
@@ -13,25 +13,13 @@ module FoodCritic
|
|
13
13
|
#
|
14
14
|
# @param [Array] args The command-line arguments to parse
|
15
15
|
# @return [Array] Pair - the first item is string output, the second is the exit code.
|
16
|
-
def self.check(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
opts.banner = 'foodcritic [cookbook_path]'
|
21
|
-
opts.on("-r", "--[no-]repl", "Drop into a REPL for interactive rule editing.") {|r|options[:repl] = r}
|
22
|
-
opts.on("-t", "--tags TAGS", "Only check against rules with the specified tags.") {|t|options[:tags] << t}
|
23
|
-
opts.on("-f", "--epic-fail TAGS", "Fail the build if any of the specified tags are matched.") {|t|options[:fail_tags] << t}
|
24
|
-
end
|
25
|
-
|
26
|
-
return [parser.help, 0] if args.length == 1 and args.first == '--help'
|
27
|
-
|
28
|
-
parser.parse!(args)
|
29
|
-
|
30
|
-
if args.length == 1 and Dir.exists?(args[0])
|
31
|
-
review = FoodCritic::Linter.new.check(args[0], options)
|
16
|
+
def self.check(cmd_line)
|
17
|
+
return [cmd_line.help, 0] if cmd_line.show_help?
|
18
|
+
if cmd_line.valid_path?
|
19
|
+
review = FoodCritic::Linter.new.check(cmd_line.cookbook_path, cmd_line.options)
|
32
20
|
[review, review.failed? ? 3 : 0]
|
33
21
|
else
|
34
|
-
[
|
22
|
+
[cmd_line.help, 2]
|
35
23
|
end
|
36
24
|
end
|
37
25
|
|
@@ -59,6 +47,7 @@ module FoodCritic
|
|
59
47
|
@rules.select{|rule| tag_expr.eval(rule.tags)}.each do |rule|
|
60
48
|
rule_matches = matches(rule.recipe, ast, file)
|
61
49
|
rule_matches += matches(rule.provider, ast, file) if File.basename(File.dirname(file)) == 'providers'
|
50
|
+
rule_matches += matches(rule.resource, ast, file) if File.basename(File.dirname(file)) == 'resources'
|
62
51
|
rule_matches += matches(rule.cookbook, cookbook_dir) if last_dir != cookbook_dir
|
63
52
|
rule_matches.each do |match|
|
64
53
|
warnings << Warning.new(rule, {:filename => file}.merge(match))
|
@@ -68,7 +57,7 @@ module FoodCritic
|
|
68
57
|
last_dir = cookbook_dir
|
69
58
|
end
|
70
59
|
|
71
|
-
@review = Review.new(warnings, should_fail_build?(options[:fail_tags], matched_rule_tags))
|
60
|
+
@review = Review.new(cookbook_path, warnings, should_fail_build?(options[:fail_tags], matched_rule_tags))
|
72
61
|
|
73
62
|
binding.pry if options[:repl]
|
74
63
|
@review
|
@@ -112,8 +101,8 @@ module FoodCritic
|
|
112
101
|
# @return [Array] The files underneath the provided directory to be processed.
|
113
102
|
def files_to_process(dir)
|
114
103
|
return [dir] unless File.directory? dir
|
115
|
-
Dir.glob(File.join(dir, '{attributes,providers,recipes}/*.rb')) +
|
116
|
-
Dir.glob(File.join(dir, '*/{attributes,providers,recipes}/*.rb'))
|
104
|
+
Dir.glob(File.join(dir, '{attributes,providers,recipes,resources}/*.rb')) +
|
105
|
+
Dir.glob(File.join(dir, '*/{attributes,providers,recipes,resources}/*.rb'))
|
117
106
|
end
|
118
107
|
|
119
108
|
# Whether to fail the build.
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module FoodCritic
|
2
|
+
|
3
|
+
# Default output showing a summary view.
|
4
|
+
class SummaryOutput
|
5
|
+
# Output a summary view only listing the matching rules, file and line number.
|
6
|
+
#
|
7
|
+
# @param [Review] review The review to output.
|
8
|
+
def output(review)
|
9
|
+
puts review.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Display rule matches with surrounding context.
|
14
|
+
class ContextOutput
|
15
|
+
|
16
|
+
# Output the review showing matching lines with context.
|
17
|
+
#
|
18
|
+
# @param [Review] review The review to output.
|
19
|
+
def output(review)
|
20
|
+
unless review.respond_to?(:warnings)
|
21
|
+
puts review; return
|
22
|
+
end
|
23
|
+
|
24
|
+
# Cheating here and mis-using Rak (Ruby port of Ack) to generate pretty colourised context.
|
25
|
+
#
|
26
|
+
# Rak supports evaluating a custom expression as an alternative to a regex. Our expression consults a hash of the
|
27
|
+
# matches found and then we let Rak take care of the presentation.
|
28
|
+
line_lookup = key_by_file_and_line(review)
|
29
|
+
Rak.class_eval do
|
30
|
+
const_set(:RULE_COLOUR, "\033[1;36m")
|
31
|
+
@warnings = line_lookup
|
32
|
+
end
|
33
|
+
ARGV.replace(['--context', '--eval', %q{
|
34
|
+
# This code will be evaluated inline by Rak.
|
35
|
+
fn = fn.split("\n").first
|
36
|
+
if @warnings.key?(fn) and @warnings[fn].key?($.) # filename and line number
|
37
|
+
rule_name = "#{RULE_COLOUR if opt[:colour]}#{@warnings[fn][$.].to_a.join("\n")}#{CLEAR_COLOURS}"
|
38
|
+
if ! displayed_filename
|
39
|
+
fn = "#{fn}\n#{rule_name}"
|
40
|
+
else
|
41
|
+
puts rule_name
|
42
|
+
end
|
43
|
+
else
|
44
|
+
next
|
45
|
+
end
|
46
|
+
}, review.cookbook_path])
|
47
|
+
Rak.send(:remove_const, :VERSION) # Prevent duplicate VERSION warning
|
48
|
+
load Gem.bin_path('rak', 'rak') # Assumes Rubygems
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Build a hash lookup by filename and line number for warnings found in the specified review.
|
54
|
+
#
|
55
|
+
# @param [Review] review The review to convert.
|
56
|
+
# @return [Hash] Nested hashes keyed by filename and line number.
|
57
|
+
def key_by_file_and_line(review)
|
58
|
+
warn_hash = {}
|
59
|
+
review.warnings.each do |warning|
|
60
|
+
filename = Pathname.new(warning.match[:filename]).cleanpath.to_s; line_num = warning.match[:line].to_i
|
61
|
+
warn_hash[filename] = {} unless warn_hash.key?(filename)
|
62
|
+
warn_hash[filename][line_num] = Set.new unless warn_hash[filename].key?(line_num)
|
63
|
+
warn_hash[filename][line_num] << warning.rule
|
64
|
+
end
|
65
|
+
warn_hash
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/foodcritic/rules.rb
CHANGED
@@ -34,15 +34,14 @@ end
|
|
34
34
|
rule "FC005", "Avoid repetition of resource declarations" do
|
35
35
|
tags %w{style}
|
36
36
|
recipe do |ast|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
matches
|
37
|
+
resources = find_resources(ast).map{|res| resource_attributes(res).merge({:type => resource_type(res),
|
38
|
+
:ast => res})}.chunk{|res| res[:type]}.reject{|res| res[1].size < 3}
|
39
|
+
resources.map do |cont_res|
|
40
|
+
first_resource = cont_res[1][0][:ast]
|
41
|
+
# we have contiguous resources of the same type, but do they share the same attributes?
|
42
|
+
sorted_atts = cont_res[1].map{|atts| atts.delete_if{|k| k == :ast}.to_a.sort{|x,y| x.first.to_s <=> y.first.to_s}}
|
43
|
+
match(first_resource) if sorted_atts.all?{|att| (att - sorted_atts.inject{|atts,a| atts & a}).length == 1}
|
44
|
+
end.compact
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -148,6 +147,13 @@ rule "FC015", "Consider converting definition to a LWRP" do
|
|
148
147
|
end
|
149
148
|
end
|
150
149
|
|
150
|
+
rule "FC016", "LWRP does not declare a default action" do
|
151
|
+
tags %w{correctness lwrp}
|
152
|
+
resource do |ast, filename|
|
153
|
+
ast.xpath("//def/bodystmt/descendant::assign/var_field/ivar/@value='@action'") ? [] : [file_match(filename)]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
151
157
|
rule "FC017", "LWRP does not notify when updated" do
|
152
158
|
tags %w{correctness lwrp}
|
153
159
|
provider do |ast, filename|
|
@@ -171,14 +177,14 @@ rule "FC019", "Access node attributes in a consistent manner" do
|
|
171
177
|
tags %w{style attributes}
|
172
178
|
cookbook do |cookbook_dir|
|
173
179
|
asts = {}; files = Dir["#{cookbook_dir}/**/*.rb"].map{|file| {:path => file, :ast => read_file(file)}}
|
174
|
-
types = [:string, :symbol, :vivified].map{|type| {:access_type => type, :count => files.
|
175
|
-
|
176
|
-
asts[type] = {:ast => ast
|
177
|
-
}.
|
178
|
-
end}}.reject{|type| type[:count] == 0}
|
180
|
+
types = [:string, :symbol, :vivified].map{|type| {:access_type => type, :count => files.map do |file|
|
181
|
+
attribute_access(file[:ast], type, true).tap{|ast|
|
182
|
+
asts[type] = {:ast => ast, :path => file[:path]} if (! ast.empty?) and (! asts.has_key?(type))
|
183
|
+
}.size
|
184
|
+
end.inject(:+)}}.reject{|type| type[:count] == 0}
|
179
185
|
if asts.size > 1
|
180
186
|
least_used = asts[types.min{|a,b| a[:count] <=> b[:count]}[:access_type]]
|
181
|
-
|
187
|
+
least_used[:ast].map{|ast| match(ast).merge(:filename => least_used[:path])}
|
182
188
|
end
|
183
189
|
end
|
184
190
|
end
|
@@ -191,8 +197,36 @@ rule "FC020", "Conditional execution string attribute looks like Ruby" do
|
|
191
197
|
unless conditions.empty?
|
192
198
|
lines = File.readlines(filename) # go back and get the raw untokenized string
|
193
199
|
conditions.map do |condition|
|
194
|
-
{:match => condition, :raw_string => lines[(condition[:line].to_i) -1].strip.sub(/^(not|only)_if[\s+]"/, '').chop}
|
200
|
+
{:match => condition, :raw_string => lines[(condition[:line].to_i) -1].strip.sub(/^(not|only)_if[\s+]["']/, '').chop}
|
195
201
|
end.find_all{|cond| ruby_code?(cond[:raw_string]) and ! os_command?(cond[:raw_string])}.map{|cond| cond[:match]}
|
196
202
|
end
|
197
203
|
end
|
204
|
+
end
|
205
|
+
|
206
|
+
rule "FC021", "Resource condition in provider may not behave as expected" do
|
207
|
+
tags %w{correctness lwrp}
|
208
|
+
provider do |ast|
|
209
|
+
find_resources(ast).map do |resource|
|
210
|
+
condition = resource.xpath(%q{//method_add_block/descendant::ident[@value='not_if' or @value='only_if']/
|
211
|
+
ancestor::*[self::method_add_block or self::command][1][descendant::ident/@value='new_resource']/
|
212
|
+
ancestor::stmts_add[2]/method_add_block/command[count(descendant::string_embexpr) = 0]})
|
213
|
+
match(condition) unless condition.empty?
|
214
|
+
end.compact
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
rule "FC022", "Resource condition within loop may not behave as expected" do
|
219
|
+
tags %w{correctness}
|
220
|
+
recipe do |ast|
|
221
|
+
ast.xpath("//call[ident/@value='each']/../do_block").map do |loop|
|
222
|
+
block_vars = loop.xpath("block_var/params/child::*").map{|n| n.name.sub(/^ident/, '')}
|
223
|
+
find_resources(loop).map do |resource|
|
224
|
+
# if any of the parameters to the block are used in a condition then we have a match
|
225
|
+
unless (block_vars & (resource.xpath(%q{descendant::ident[@value='not_if' or @value='only_if']/
|
226
|
+
ancestor::*[self::method_add_block or self::command][1]/descendant::ident/@value}).map{|a| a.value})).empty?
|
227
|
+
match(resource) unless resource.xpath('command[count(descendant::string_embexpr) = 0]').empty?
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end.flatten.compact
|
231
|
+
end
|
198
232
|
end
|
data/lib/foodcritic/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foodcritic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156685440 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.10.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156685440
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156705560 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: 1.6.1
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *2156705560
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: gherkin
|
41
|
-
requirement: &
|
41
|
+
requirement: &2156702700 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: 2.7.1
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *2156702700
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: gist
|
52
|
-
requirement: &
|
52
|
+
requirement: &2156700200 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ~>
|
@@ -57,10 +57,10 @@ dependencies:
|
|
57
57
|
version: 2.0.4
|
58
58
|
type: :runtime
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *2156700200
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: nokogiri
|
63
|
-
requirement: &
|
63
|
+
requirement: &2156712640 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
@@ -68,10 +68,10 @@ dependencies:
|
|
68
68
|
version: 1.5.0
|
69
69
|
type: :runtime
|
70
70
|
prerelease: false
|
71
|
-
version_requirements: *
|
71
|
+
version_requirements: *2156712640
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: pry
|
74
|
-
requirement: &
|
74
|
+
requirement: &2156708060 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
77
77
|
- - ~>
|
@@ -79,10 +79,10 @@ dependencies:
|
|
79
79
|
version: 0.9.7.4
|
80
80
|
type: :runtime
|
81
81
|
prerelease: false
|
82
|
-
version_requirements: *
|
82
|
+
version_requirements: *2156708060
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: pry-doc
|
85
|
-
requirement: &
|
85
|
+
requirement: &2156721400 !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
88
88
|
- - ~>
|
@@ -90,7 +90,18 @@ dependencies:
|
|
90
90
|
version: 0.3.0
|
91
91
|
type: :runtime
|
92
92
|
prerelease: false
|
93
|
-
version_requirements: *
|
93
|
+
version_requirements: *2156721400
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rak
|
96
|
+
requirement: &2156718720 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '1.4'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: *2156718720
|
94
105
|
description: Lint tool for Opscode Chef cookbooks.
|
95
106
|
email:
|
96
107
|
executables:
|
@@ -98,11 +109,13 @@ executables:
|
|
98
109
|
extensions: []
|
99
110
|
extra_rdoc_files: []
|
100
111
|
files:
|
112
|
+
- lib/foodcritic/command_line.rb
|
101
113
|
- lib/foodcritic/domain.rb
|
102
114
|
- lib/foodcritic/dsl.rb
|
103
115
|
- lib/foodcritic/error_checker.rb
|
104
116
|
- lib/foodcritic/helpers.rb
|
105
117
|
- lib/foodcritic/linter.rb
|
118
|
+
- lib/foodcritic/output.rb
|
106
119
|
- lib/foodcritic/rules.rb
|
107
120
|
- lib/foodcritic/version.rb
|
108
121
|
- lib/foodcritic.rb
|
@@ -128,12 +141,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
141
|
version: '0'
|
129
142
|
segments:
|
130
143
|
- 0
|
131
|
-
hash: -
|
144
|
+
hash: -4091807695676040687
|
132
145
|
requirements: []
|
133
146
|
rubyforge_project:
|
134
147
|
rubygems_version: 1.8.10
|
135
148
|
signing_key:
|
136
149
|
specification_version: 3
|
137
|
-
summary: foodcritic-0.
|
150
|
+
summary: foodcritic-0.9.0
|
138
151
|
test_files: []
|
139
152
|
has_rdoc:
|