inspecstyle 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module InSpecStyle
7
7
  # Checks if deprecated method attribute is used.
8
8
  #
9
- # @example
9
+ # @example EnforcedStyle: InSpecStyle (default)
10
10
  # # Attributes have been deprecated for inputs
11
11
  # # https://github.com/inspec/inspec/issues/3802
12
12
  #
@@ -27,25 +27,25 @@ module RuboCop
27
27
 
28
28
  def on_send(node)
29
29
  return unless attribute?(node)
30
- add_offense(node, location: range(node))
30
+
31
+ add_offense(node, location: node.loc.selector)
32
+ end
33
+
34
+ def autocorrect(node)
35
+ lambda do |corrector|
36
+ corrector.replace(offense_range(node), preferred_replacement)
37
+ end
31
38
  end
32
39
 
33
40
  private
34
41
 
35
- def range(node)
36
- # Only highlights the method 'attribute'
37
- range_between(
38
- node.source_range.begin_pos,
39
- node.source_range.begin_pos+9
40
- )
42
+ def offense_range(node)
43
+ node.loc.selector
41
44
  end
42
45
 
43
- # def autocorrect
44
- # ->(corrector) do
45
- # corrector.insert_before(node.source_range, 'input')
46
- # corrector.remove(node.source_range, 'attribute')
47
- # end
48
- # end
46
+ def preferred_replacement
47
+ cop_config.fetch('PreferredReplacement')
48
+ end
49
49
  end
50
50
  end
51
51
  end
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'inspecstyle/first_cop'
3
3
  require_relative 'inspecstyle/deprecated_attributes'
4
+ require_relative 'inspecstyle/azure_generic_resource'
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module InSpecStyle
3
- VERSION = "0.1.2"
3
+ VERSION = "0.1.3"
4
4
  end
5
5
  end
@@ -0,0 +1,300 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+ require 'rubocop'
5
+
6
+ YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
7
+ task.files = ['lib/rubocop/cop/*/*.rb']
8
+ task.options = ['--no-output']
9
+ end
10
+
11
+ desc 'Generate docs of all cops departments'
12
+ task generate_cops_documentation: :yard_for_generate_documentation do
13
+ def cops_of_department(cops, department)
14
+ cops.with_department(department).sort!
15
+ end
16
+
17
+ # rubocop:disable Metrics/AbcSize
18
+ def cops_body(config, cop, description, examples_objects, pars)
19
+ content = h2(cop.cop_name)
20
+ content << required_ruby_version(cop)
21
+ content << properties(cop.new(config))
22
+ content << "#{description}\n"
23
+ content << examples(examples_objects) if examples_objects.count.positive?
24
+ content << configurations(pars)
25
+ content << references(config, cop)
26
+ content
27
+ end
28
+ # rubocop:enable Metrics/AbcSize
29
+
30
+ def examples(examples_object)
31
+ examples_object.each_with_object(h3('Examples').dup) do |example, content|
32
+ content << "\n" unless content.end_with?("\n\n")
33
+ content << h4(example.name) unless example.name == ''
34
+ content << code_example(example)
35
+ end
36
+ end
37
+
38
+ def required_ruby_version(cop)
39
+ return '' unless cop.respond_to?(:required_minimum_ruby_version)
40
+
41
+ "NOTE: Required Ruby version: #{cop.required_minimum_ruby_version}\n\n"
42
+ end
43
+
44
+ # rubocop:disable Metrics/MethodLength
45
+ def properties(cop_instance)
46
+ header = [
47
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
48
+ 'VersionChanged'
49
+ ]
50
+ autocorrect = if cop_instance.support_autocorrect?
51
+ "Yes#{' (Unsafe)' unless cop_instance.safe_autocorrect?}"
52
+ else
53
+ 'No'
54
+ end
55
+ cop_config = cop_instance.cop_config
56
+ content = [[
57
+ cop_status(cop_config.fetch('Enabled')),
58
+ cop_config.fetch('Safe', true) ? 'Yes' : 'No',
59
+ autocorrect,
60
+ cop_config.fetch('VersionAdded', '-'),
61
+ cop_config.fetch('VersionChanged', '-')
62
+ ]]
63
+ to_table(header, content) + "\n"
64
+ end
65
+ # rubocop:enable Metrics/MethodLength
66
+
67
+ def h2(title)
68
+ content = +"\n"
69
+ content << "== #{title}\n"
70
+ content << "\n"
71
+ content
72
+ end
73
+
74
+ def h3(title)
75
+ content = +"\n"
76
+ content << "=== #{title}\n"
77
+ content << "\n"
78
+ content
79
+ end
80
+
81
+ def h4(title)
82
+ content = +"==== #{title}\n"
83
+ content << "\n"
84
+ content
85
+ end
86
+
87
+ def code_example(ruby_code)
88
+ content = +"[source,ruby]\n----\n"
89
+ content << ruby_code.text.gsub('@good', '# good')
90
+ .gsub('@bad', '# bad').strip
91
+ content << "\n----\n"
92
+ content
93
+ end
94
+
95
+ def configurations(pars)
96
+ return '' if pars.empty?
97
+
98
+ header = ['Name', 'Default value', 'Configurable values']
99
+ configs = pars
100
+ .each_key
101
+ .reject { |key| key.start_with?('Supported') }
102
+ .reject { |key| key.start_with?('AllowMultipleStyles') }
103
+ content = configs.map do |name|
104
+ configurable = configurable_values(pars, name)
105
+ default = format_table_value(pars[name])
106
+ [name, default, configurable]
107
+ end
108
+
109
+ h3('Configurable attributes') + to_table(header, content)
110
+ end
111
+
112
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
113
+ def configurable_values(pars, name)
114
+ case name
115
+ when /^Enforced/
116
+ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
117
+ format_table_value(pars[supported_style_name])
118
+ when 'IndentationWidth'
119
+ 'Integer'
120
+ when 'Database'
121
+ format_table_value(pars['SupportedDatabases'])
122
+ else
123
+ case pars[name]
124
+ when String
125
+ 'String'
126
+ when Integer
127
+ 'Integer'
128
+ when Float
129
+ 'Float'
130
+ when true, false
131
+ 'Boolean'
132
+ when Array
133
+ 'Array'
134
+ else
135
+ ''
136
+ end
137
+ end
138
+ end
139
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
140
+
141
+ def to_table(header, content)
142
+ table = [
143
+ '|===',
144
+ "| #{header.join(' | ')}\n\n"
145
+ ].join("\n")
146
+ marked_contents = content.map do |plain_content|
147
+ plain_content.map { |c| "| #{c}" }.join("\n")
148
+ end
149
+ table << marked_contents.join("\n\n")
150
+ table << "\n|===\n"
151
+ end
152
+
153
+ def format_table_value(val)
154
+ value =
155
+ case val
156
+ when Array
157
+ if val.empty?
158
+ '`[]`'
159
+ else
160
+ val.map { |config| format_table_value(config) }.join(', ')
161
+ end
162
+ else
163
+ wrap_backtick(val.nil? ? '<none>' : val)
164
+ end
165
+ value.gsub("#{Dir.pwd}/", '').rstrip
166
+ end
167
+
168
+ def wrap_backtick(value)
169
+ if value.is_a?(String)
170
+ # Use `+` to prevent text like `**/*.gemspec` from being bold.
171
+ value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
172
+ else
173
+ "`#{value}`"
174
+ end
175
+ end
176
+
177
+ def references(config, cop)
178
+ cop_config = config.for_cop(cop)
179
+ urls = RuboCop::Cop::MessageAnnotator.new(
180
+ config, cop.name, cop_config, {}
181
+ ).urls
182
+ return '' if urls.empty?
183
+
184
+ content = h3('References')
185
+ content << urls.map { |url| "* #{url}" }.join("\n")
186
+ content << "\n"
187
+ content
188
+ end
189
+
190
+ def print_cops_of_department(cops, department, config)
191
+ selected_cops = cops_of_department(cops, department)
192
+ content = +"= #{department}\n"
193
+ selected_cops.each do |cop|
194
+ content << print_cop_with_doc(cop, config)
195
+ end
196
+ file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/cops_#{department.downcase}.adoc"
197
+ File.open(file_name, 'w') do |file|
198
+ puts "* generated #{file_name}"
199
+ file.write(content.strip + "\n")
200
+ end
201
+ end
202
+
203
+ def print_cop_with_doc(cop, config)
204
+ t = config.for_cop(cop)
205
+ non_display_keys = %w[
206
+ Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
207
+ VersionChanged
208
+ ]
209
+ pars = t.reject { |k| non_display_keys.include? k }
210
+ description = 'No documentation'
211
+ examples_object = []
212
+ cop_code(cop) do |code_object|
213
+ description = code_object.docstring unless code_object.docstring.blank?
214
+ examples_object = code_object.tags('example')
215
+ end
216
+ cops_body(config, cop, description, examples_object, pars)
217
+ end
218
+
219
+ def cop_code(cop)
220
+ YARD::Registry.all(:class).detect do |code_object|
221
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
222
+
223
+ yield code_object
224
+ end
225
+ end
226
+
227
+ def table_of_content_for_department(cops, department)
228
+ type_title = department[0].upcase + department[1..-1]
229
+ filename = "cops_#{department.downcase}.adoc"
230
+ content = +"=== Department xref:#{filename}[#{type_title}]\n\n"
231
+ cops_of_department(cops, department.to_sym).each do |cop|
232
+ anchor = cop.cop_name.sub('/', '').downcase
233
+ content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n"
234
+ end
235
+
236
+ content
237
+ end
238
+
239
+ def print_table_of_contents(cops)
240
+ path = "#{Dir.pwd}/docs/modules/ROOT/pages/cops.adoc"
241
+ original = File.read(path)
242
+ content = +"// START_COP_LIST\n\n"
243
+
244
+ content << table_contents(cops)
245
+
246
+ content << "\n// END_COP_LIST"
247
+
248
+ content = original.sub(
249
+ %r{// START_COP_LIST.+// END_COP_LIST}m, content
250
+ )
251
+ File.write(path, content)
252
+ end
253
+
254
+ def table_contents(cops)
255
+ cops
256
+ .departments
257
+ .map(&:to_s)
258
+ .sort
259
+ .map { |department| table_of_content_for_department(cops, department) }
260
+ .join("\n")
261
+ end
262
+
263
+ def cop_status(status)
264
+ return 'Disabled' unless status
265
+
266
+ status == 'pending' ? 'Pending' : 'Enabled'
267
+ end
268
+
269
+ def assert_docs_synchronized
270
+ # Do not print diff and yield whether exit code was zero
271
+ sh('git diff --quiet docs') do |outcome, _|
272
+ return if outcome
273
+
274
+ # Output diff before raising error
275
+ sh('GIT_PAGER=cat git diff docs')
276
+
277
+ warn 'The docs directory is out of sync. ' \
278
+ 'Run `rake generate_cops_documentation` and commit the results.'
279
+ exit!
280
+ end
281
+ end
282
+
283
+ def main
284
+ cops = RuboCop::Cop::Cop.registry
285
+ config = RuboCop::ConfigLoader.default_configuration
286
+
287
+ YARD::Registry.load!
288
+ cops.departments.sort!.each do |department|
289
+ print_cops_of_department(cops, department, config)
290
+ end
291
+
292
+ print_table_of_contents(cops)
293
+
294
+ assert_docs_synchronized if ENV['CI'] == 'true'
295
+ ensure
296
+ RuboCop::ConfigLoader.default_configuration = nil
297
+ end
298
+
299
+ main
300
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspecstyle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Schwaderer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-10 00:00:00.000000000 Z
11
+ date: 2020-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -46,8 +46,32 @@ files:
46
46
  - bin/console
47
47
  - bin/setup
48
48
  - config/default.yml
49
+ - doc/RuboCop.html
50
+ - doc/RuboCop/Cop.html
51
+ - doc/RuboCop/Cop/InSpecStyle.html
52
+ - doc/RuboCop/Cop/InSpecStyle/AzureGenericResource.html
53
+ - doc/RuboCop/Cop/InSpecStyle/DeprecatedAttributes.html
54
+ - doc/RuboCop/Cop/InSpecStyle/FirstCop.html
55
+ - doc/RuboCop/InSpecStyle.html
56
+ - doc/RuboCop/InSpecStyle/Error.html
57
+ - doc/RuboCop/InSpecStyle/Inject.html
58
+ - doc/_index.html
59
+ - doc/class_list.html
60
+ - doc/css/common.css
61
+ - doc/css/full_list.css
62
+ - doc/css/style.css
63
+ - doc/file.README.html
64
+ - doc/file_list.html
65
+ - doc/frames.html
66
+ - doc/index.html
67
+ - doc/js/app.js
68
+ - doc/js/full_list.js
69
+ - doc/js/jquery.js
70
+ - doc/method_list.html
71
+ - doc/top-level-namespace.html
49
72
  - inspecstyle.gemspec
50
73
  - lib/inspecstyle.rb
74
+ - lib/rubocop/cop/inspecstyle/azure_generic_resource.rb
51
75
  - lib/rubocop/cop/inspecstyle/deprecated_attributes.rb
52
76
  - lib/rubocop/cop/inspecstyle/first_cop.rb
53
77
  - lib/rubocop/cop/inspecstyle_cops.rb
@@ -55,6 +79,7 @@ files:
55
79
  - lib/rubocop/inspecstyle/inject.rb
56
80
  - lib/rubocop/inspecstyle/version.rb
57
81
  - notes-for-development.md
82
+ - tasks/cops_documentation.rake
58
83
  homepage: https://github.com/schwad/inspecstyle
59
84
  licenses:
60
85
  - MIT