rubocop-faker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ require_relative 'rubocop/faker'
6
+ require_relative 'rubocop/faker/version'
7
+ require_relative 'rubocop/faker/inject'
8
+
9
+ RuboCop::Faker::Inject.defaults!
10
+
11
+ require_relative 'rubocop/cop/faker_cops'
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Faker
6
+ #
7
+ # Checks that Faker arguments style is based on Faker 2.
8
+ # Use keyword arguments instead of positional arguments.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # Avatar.image(slug, size, format)
13
+ #
14
+ # # good
15
+ # Avatar.image(slug: slug, size: size, format: format)
16
+ #
17
+ class DeprecatedArguments < Cop
18
+ include RangeHelp
19
+
20
+ MSG = 'Passing `%<arg>s` with the %<index>s argument of ' \
21
+ '`%<class_name>s.%<method_name>s` is deprecated. ' \
22
+ 'Use keyword argument like `%<class_name>s.%<method_name>s' \
23
+ '(%<keyword>s: %<arg>s)` instead.'
24
+
25
+ def on_send(node)
26
+ return unless node.receiver
27
+
28
+ class_name = faker_class_name(node)
29
+
30
+ return unless (methods = argument_keywords[class_name])
31
+ return unless (keywords = methods[node.method_name.to_s])
32
+
33
+ node.arguments.each_with_index do |argument, index|
34
+ next if argument.hash_type?
35
+
36
+ message = format_message(
37
+ keyword: keywords[index], arg: argument.source,
38
+ class_name: class_name, index: index,
39
+ method_name: node.method_name
40
+ )
41
+
42
+ add_offense_for_arguments(node, argument, message)
43
+ end
44
+ end
45
+
46
+ def autocorrect(node)
47
+ methods = argument_keywords[faker_class_name(node)]
48
+ keywords = methods[node.method_name.to_s]
49
+
50
+ kwargs = build_kwargs_style(node, keywords)
51
+
52
+ lambda do |corrector|
53
+ corrector.replace(arguments_range(node), kwargs)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def format_message(keyword:, arg:, index:, class_name:, method_name:)
60
+ i = case index
61
+ when 0 then '1st'
62
+ when 1 then '2nd'
63
+ when 2 then '3rd'
64
+ else "#{index + 1}th"
65
+ end
66
+ format(
67
+ MSG,
68
+ keyword: keyword,
69
+ arg: arg,
70
+ index: i,
71
+ class_name: class_name,
72
+ method_name: method_name
73
+ )
74
+ end
75
+
76
+ def add_offense_for_arguments(node, argument, message)
77
+ add_offense(
78
+ node,
79
+ location: argument.source_range,
80
+ message: message
81
+ )
82
+ end
83
+
84
+ def build_kwargs_style(node, keywords)
85
+ node.arguments.map.with_index do |positional_argument, index|
86
+ if positional_argument.hash_type?
87
+ positional_argument.source
88
+ else
89
+ "#{keywords[index]}: #{positional_argument.source}"
90
+ end
91
+ end.join(', ')
92
+ end
93
+
94
+ def faker_class_name(node)
95
+ node.receiver.source
96
+ end
97
+
98
+ def arguments_range(node)
99
+ arguments = node.arguments
100
+
101
+ range_between(
102
+ arguments.first.source_range.begin_pos,
103
+ arguments.last.source_range.end_pos
104
+ )
105
+ end
106
+
107
+ def argument_keywords
108
+ cop_config.fetch('ArgumentKeywords', {})
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'faker/deprecated_arguments'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # RuboCop Faker project namespace
5
+ module Faker
6
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
7
+ CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
8
+ CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
9
+
10
+ private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Faker
5
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
6
+ # bit of our configuration.
7
+ module Inject
8
+ def self.defaults!
9
+ path = CONFIG_DEFAULT.to_s
10
+ hash = ConfigLoader.send(:load_yaml_configuration, path)
11
+ config = Config.new(hash, path)
12
+ puts "configuration from #{path}" if ConfigLoader.debug?
13
+ config = ConfigLoader.merge_with_default(config, path)
14
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Faker
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ <!-- START_COP_LIST -->
2
+ #### Department [Faker](cops_faker.md)
3
+
4
+ * [Faker/DeprecatedArguments](cops_faker.md#fakerdeprecatedarguments)
5
+
6
+ <!-- END_COP_LIST -->
@@ -0,0 +1,30 @@
1
+ # Faker
2
+
3
+ ## Faker/DeprecatedArguments
4
+
5
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
6
+ --- | --- | --- | --- | ---
7
+ Enabled | Yes | Yes | 0.1 | -
8
+
9
+ Checks that Faker arguments style is based on Faker 2.
10
+ Use keyword arguments instead of positional arguments.
11
+
12
+ ### Examples
13
+
14
+ ```ruby
15
+ # bad
16
+ Avatar.image(slug, size, format)
17
+
18
+ # good
19
+ Avatar.image(slug: slug, size: size, format: format)
20
+ ```
21
+
22
+ ### Configurable attributes
23
+
24
+ Name | Default value | Configurable values
25
+ --- | --- | ---
26
+ ArgumentKeywords | `{"Faker::Dune"=>{"quote"=>["character"], "saying"=>["source"]}, "Faker::Books::Lovecraft"=>{"fhtagn"=>["number"], "sentence"=>["word_count", "random_words_to_add"], "words"=>["number", "spaces_allowed"], "sentences"=>["number"], "paragraph"=>["sentence_count", "random_sentences_to_add"], "paragraphs"=>["number"], "paragraph_by_chars"=>["characters"]}, "Faker::Address"=>{"city"=>["options"], "street_address"=>["include_secondary"], "zip_code"=>["state_abbreviation"], "country_by_code"=>["code"], "country_name_to_code"=>["name"]}, "Faker::Alphanumeric"=>{"alpha"=>["number"], "alphanumeric"=>["number"]}, "Faker::App"=>{"semantic_version"=>["major", "minor", "patch"]}, "Faker::Avatar"=>{"image"=>["slug", "size", "format", "set", "bgset"]}, "Faker::Bank"=>{"account_number"=>["digits"], "iban"=>["country_code"]}, "Faker::Boolean"=>{"boolean"=>["true_ratio"]}, "Faker::ChileRut"=>{"rut"=>["min_rut", "fixed"], "full_rut"=>["min_rut", "fixed"]}, "Faker::Code"=>{"isbn"=>["base"], "ean"=>["base"], "nric"=>["min_age", "max_age"]}, "Faker::Commerce"=>{"promotion_code"=>["digits"], "department"=>["max", "fixed_amount"], "price"=>["range", "as_string"]}, "Faker::Company"=>{"polish_register_of_national_economy"=>["length"], "brazilian_company_number"=>["formatted"]}, "Faker::CryptoCoin"=>{"coin_name"=>["coin"], "acronym"=>["coin"], "url_logo"=>["coin"]}, "Faker::Date"=>{"between"=>["from", "to"], "between_except"=>["from", "to", "excepted"], "forward"=>["days"], "backward"=>["days"], "birthday"=>["min_age", "max_age"]}, "Faker::Demographic"=>{"height"=>["unit"]}, "Faker::DrivingLicence"=>{"british_driving_licence"=>["last_name", "initials", "gender", "date_of_birth"]}, "Faker::File"=>{"dir"=>["segment_count", "root", "directory_separator"], "file_name"=>["dir", "name", "ext", "directory_separator"]}, "Faker::Fillmurray"=>{"image"=>["grayscale", "width", "height"]}, "Faker::Finance"=>{"vat_number"=>["country"]}, "Faker::Hipster"=>{"words"=>["number", "supplemental", "spaces_allowed"], "sentence"=>["word_count", "supplemental", "random_words_to_add"], "sentences"=>["number", "supplemental"], "paragraph"=>["sentence_count", "supplemental", "random_sentences_to_add"], "paragraphs"=>["number", "supplemental"], "paragraph_by_chars"=>["characters", "supplemental"]}, "Faker::IDNumber"=>{"brazilian_citizen_number"=>["formatted"], "brazilian_id"=>["formatted"]}, "Faker::Internet"=>{"email"=>["name", "separators"], "free_email"=>["name"], "safe_email"=>["name"], "username"=>["specifier", "separators"], "password"=>["min_length", "max_length", "mix_case", "special_characters"], "domain_name"=>["subdomain"], "fix_umlauts"=>["string"], "mac_address"=>["prefix"], "url"=>["host", "path", "scheme"], "slug"=>["words", "glue"], "user_agent"=>["vendor"]}, "Faker::Invoice"=>{"amount_between"=>["from", "to"], "creditor_reference"=>["ref"], "reference"=>["ref"]}, "Faker::Json"=>{"shallow_json"=>["width", "options"], "add_depth_to_json"=>["json", "width", "options"]}, "Faker::Lorem"=>{"words"=>["number", "supplemental"], "characters"=>["number"], "sentence"=>["word_count", "supplemental", "random_words_to_add"], "sentences"=>["number", "supplemental"], "paragraph"=>["sentence_count", "supplemental", "random_sentences_to_add"], "paragraphs"=>["number", "supplemental"], "paragraph_by_chars"=>["number", "supplemental"], "question"=>["word_count", "supplemental", "random_words_to_add"], "questions"=>["number", "supplemental"]}, "Faker::LoremFlickr"=>{"image"=>["size", "search_terms", "match_all"], "grayscale_image"=>["size", "search_terms", "match_all"], "pixelated_image"=>["size", "search_terms", "match_all"], "colorized_image"=>["size", "color", "search_terms", "match_all"]}, "Faker::LoremPixel"=>{"image"=>["size", "is_gray", "category", "number", "text", "secure"]}, "Faker::Markdown"=>{"sandwich"=>["sentences", "repeat"]}, "Faker::Measurement"=>{"height"=>["amount"], "length"=>["amount"], "volume"=>["amount"], "weight"=>["amount"], "metric_height"=>["amount"], "metric_length"=>["amount"], "metric_volume"=>["amount"], "metric_weight"=>["amount"]}, "Faker::Name"=>{"initials"=>["number"]}, "Faker::NationalHealthService"=>{"check_digit"=>["number"]}, "Faker::Number"=>{"number"=>["digits"], "leading_zero_number"=>["digits"], "decimal_part"=>["digits"], "decimal"=>["l_digits", "r_digits"], "hexadecimal"=>["digits"], "normal"=>["mean", "standard_deviation"], "between"=>["from", "to"], "within"=>["range"], "positive"=>["from", "to"], "negative"=>["from", "to"]}, "Faker::Omniauth"=>{"google"=>["name", "email", "uid"], "facebook"=>["name", "email", "username", "uid"], "twitter"=>["name", "nickname", "uid"], "linkedin"=>["name", "email", "uid"], "github"=>["name", "email", "uid"]}, "Faker::PhoneNumber"=>{"subscriber_number"=>["length"]}, "Faker::Placeholdit"=>{"image"=>["size", "format", "background_color", "text_color", "text"]}, "Faker::Relationship"=>{"familial"=>["connection"]}, "Faker::Source"=>{"hello_world"=>["lang"], "print"=>["str", "lang"], "print_1_to_10"=>["lang"]}, "Faker::String"=>{"random"=>["length"]}, "Faker::Stripe"=>{"valid_card"=>["card_type"], "valid_token"=>["card_type"], "invalid_card"=>["card_error"], "ccv"=>["card_type"]}, "Faker::Time"=>{"between"=>["from", "to", "format"], "between_dates"=>["from", "to", "period", "format"], "forward"=>["days", "period", "format"], "backward"=>["days", "period", "format"]}, "Faker::Twitter"=>{"user"=>["include_status", "include_email"], "status"=>["include_user", "include_photo"], "status_entities"=>["include_photo"]}, "Faker::Types"=>{"rb_string"=>["words"], "rb_integer"=>["from", "to"], "rb_hash"=>["number", "type"], "complex_rb_hash"=>["number"], "rb_array"=>["len"]}, "Faker::Vehicle"=>{"model"=>["make_of_model"], "mileage"=>["min", "max"], "license_plate"=>["state_abreviation"]}, "Faker::WorldCup"=>{"group"=>["group"], "roster"=>["country", "type"]}, "Faker::Dota"=>{"quote"=>["hero"]}, "Faker::Movies::StarWars"=>{"quote"=>["character"]}}` |
27
+
28
+ ### References
29
+
30
+ * [https://github.com/faker-ruby/faker/blob/master/CHANGELOG.md#v20-2019-31-07](https://github.com/faker-ruby/faker/blob/master/CHANGELOG.md#v20-2019-31-07)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/rubocop/faker/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'rubocop-faker'
7
+ spec.version = RuboCop::Faker::VERSION
8
+ spec.authors = ['Koichi ITO']
9
+ spec.email = ['koic.ito@gmail.com']
10
+
11
+ spec.summary = 'A RuboCop extension for Faker'
12
+ spec.description = 'A RuboCop extension for Faker'
13
+ spec.homepage = 'https://github.com/koic/rubocop-faker'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ spec.add_runtime_dependency 'rubocop', '>= 0.74'
29
+ end
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+ require 'rubocop'
5
+ require 'rubocop-faker'
6
+
7
+ YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
8
+ task.files = ['lib/rubocop/cop/**/*.rb']
9
+ task.options = ['--no-output']
10
+ end
11
+
12
+ desc 'Generate docs of all cops departments'
13
+ task generate_cops_documentation: :yard_for_generate_documentation do
14
+ def cops_of_department(cops, department)
15
+ cops.with_department(department).sort!
16
+ end
17
+
18
+ def cops_body(config, cop, description, examples_objects, pars)
19
+ content = h2(cop.cop_name)
20
+ content << properties(config, cop)
21
+ content << "#{description}\n"
22
+ content << examples(examples_objects) if examples_objects.count.positive?
23
+ content << configurations(pars)
24
+ content << references(config, cop)
25
+ content
26
+ end
27
+
28
+ def examples(examples_object)
29
+ examples_object.each_with_object(h3('Examples').dup) do |example, content|
30
+ content << h4(example.name) unless example.name == ''
31
+ content << code_example(example)
32
+ end
33
+ end
34
+
35
+ # rubocop:disable Metrics/MethodLength
36
+ def properties(config, cop)
37
+ header = [
38
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
39
+ 'VersionChanged'
40
+ ]
41
+ config = config.for_cop(cop)
42
+ safe_auto_correct = config.fetch('SafeAutoCorrect', true)
43
+ autocorrect = if cop.new.support_autocorrect?
44
+ "Yes #{'(Unsafe)' unless safe_auto_correct}"
45
+ else
46
+ 'No'
47
+ end
48
+ content = [[
49
+ config.fetch('Enabled') ? 'Enabled' : 'Disabled',
50
+ config.fetch('Safe', true) ? 'Yes' : 'No',
51
+ autocorrect,
52
+ config.fetch('VersionAdded', '-'),
53
+ config.fetch('VersionChanged', '-')
54
+ ]]
55
+ to_table(header, content) + "\n"
56
+ end
57
+ # rubocop:enable Metrics/MethodLength
58
+
59
+ def h2(title)
60
+ content = +"\n"
61
+ content << "## #{title}\n"
62
+ content << "\n"
63
+ content
64
+ end
65
+
66
+ def h3(title)
67
+ content = +"\n"
68
+ content << "### #{title}\n"
69
+ content << "\n"
70
+ content
71
+ end
72
+
73
+ def h4(title)
74
+ content = +"#### #{title}\n"
75
+ content << "\n"
76
+ content
77
+ end
78
+
79
+ def code_example(ruby_code)
80
+ content = +"```ruby\n"
81
+ content << ruby_code.text
82
+ .gsub('@good', '# good').gsub('@bad', '# bad').strip
83
+ content << "\n```\n"
84
+ content
85
+ end
86
+
87
+ def configurations(pars)
88
+ return '' if pars.empty?
89
+
90
+ header = ['Name', 'Default value', 'Configurable values']
91
+ configs = pars.each_key.reject { |key| key.start_with?('Supported') }
92
+ content = configs.map do |name|
93
+ configurable = configurable_values(pars, name)
94
+ default = format_table_value(pars[name])
95
+ [name, default, configurable]
96
+ end
97
+
98
+ h3('Configurable attributes') + to_table(header, content)
99
+ end
100
+
101
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
102
+ def configurable_values(pars, name)
103
+ case name
104
+ when /^Enforced/
105
+ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
106
+ format_table_value(pars[supported_style_name])
107
+ when 'IndentationWidth'
108
+ 'Integer'
109
+ else
110
+ case pars[name]
111
+ when String
112
+ 'String'
113
+ when Integer
114
+ 'Integer'
115
+ when Float
116
+ 'Float'
117
+ when true, false
118
+ 'Boolean'
119
+ when Array
120
+ 'Array'
121
+ else
122
+ ''
123
+ end
124
+ end
125
+ end
126
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
127
+
128
+ def to_table(header, content)
129
+ table = [
130
+ header.join(' | '),
131
+ Array.new(header.size, '---').join(' | ')
132
+ ]
133
+ table.concat(content.map { |c| c.join(' | ') })
134
+ table.join("\n") + "\n"
135
+ end
136
+
137
+ def format_table_value(val)
138
+ value =
139
+ case val
140
+ when Array
141
+ if val.empty?
142
+ '`[]`'
143
+ else
144
+ val.map { |config| format_table_value(config) }.join(', ')
145
+ end
146
+ else
147
+ "`#{val.nil? ? '<none>' : val}`"
148
+ end
149
+ value.gsub("#{Dir.pwd}/", '').rstrip
150
+ end
151
+
152
+ def references(config, cop)
153
+ cop_config = config.for_cop(cop)
154
+ urls = RuboCop::Cop::MessageAnnotator.new(
155
+ config, cop.name, cop_config, {}
156
+ ).urls
157
+ return '' if urls.empty?
158
+
159
+ content = h3('References')
160
+ content << urls.map { |url| "* [#{url}](#{url})" }.join("\n")
161
+ content << "\n"
162
+ content
163
+ end
164
+
165
+ def print_cops_of_department(cops, department, config)
166
+ selected_cops = cops_of_department(cops, department).select do |cop|
167
+ cop.to_s.start_with?('RuboCop::Cop::Faker')
168
+ end
169
+ return if selected_cops.empty?
170
+
171
+ content = +"# #{department}\n"
172
+ selected_cops.each do |cop|
173
+ content << print_cop_with_doc(cop, config)
174
+ end
175
+ file_name = "#{Dir.pwd}/manual/cops_#{department.downcase}.md"
176
+ File.open(file_name, 'w') do |file|
177
+ puts "* generated #{file_name}"
178
+ file.write(content.strip + "\n")
179
+ end
180
+ end
181
+
182
+ def print_cop_with_doc(cop, config)
183
+ t = config.for_cop(cop)
184
+ non_display_keys = %w[
185
+ Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
186
+ VersionChanged
187
+ ]
188
+ pars = t.reject { |k| non_display_keys.include? k }
189
+ description = 'No documentation'
190
+ examples_object = []
191
+ YARD::Registry.all(:class).detect do |code_object|
192
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
193
+
194
+ description = code_object.docstring unless code_object.docstring.blank?
195
+ examples_object = code_object.tags('example')
196
+ end
197
+ cops_body(config, cop, description, examples_object, pars)
198
+ end
199
+
200
+ # rubocop:disable Metrics/AbcSize
201
+ def table_of_content_for_department(cops, department)
202
+ selected_cops = cops_of_department(cops, department.to_sym).select do |cop|
203
+ cop.to_s.start_with?('RuboCop::Cop::Faker')
204
+ end
205
+ return if selected_cops.empty?
206
+
207
+ type_title = department[0].upcase + department[1..-1]
208
+ filename = "cops_#{department.downcase}.md"
209
+ content = +"#### Department [#{type_title}](#{filename})\n\n"
210
+ selected_cops.each do |cop|
211
+ anchor = cop.cop_name.sub('/', '').downcase
212
+ content << "* [#{cop.cop_name}](#{filename}##{anchor})\n"
213
+ end
214
+
215
+ content
216
+ end
217
+ # rubocop:enable Metrics/AbcSize
218
+
219
+ def print_table_of_contents(cops)
220
+ path = "#{Dir.pwd}/manual/cops.md"
221
+ original = File.read(path)
222
+ content = +"<!-- START_COP_LIST -->\n"
223
+
224
+ content << table_contents(cops)
225
+
226
+ content << "\n<!-- END_COP_LIST -->"
227
+
228
+ content = if original.empty?
229
+ content
230
+ else
231
+ original.sub(
232
+ /<!-- START_COP_LIST -->.+<!-- END_COP_LIST -->/m, content
233
+ )
234
+ end
235
+ File.write(path, content)
236
+ end
237
+
238
+ def table_contents(cops)
239
+ cops
240
+ .departments
241
+ .map(&:to_s)
242
+ .sort
243
+ .map { |department| table_of_content_for_department(cops, department) }
244
+ .reject(&:nil?)
245
+ .join("\n")
246
+ end
247
+
248
+ def assert_manual_synchronized
249
+ # Do not print diff and yield whether exit code was zero
250
+ sh('git diff --quiet manual') do |outcome, _|
251
+ return if outcome
252
+
253
+ # Output diff before raising error
254
+ sh('GIT_PAGER=cat git diff manual')
255
+
256
+ warn 'The manual directory is out of sync. ' \
257
+ 'Run `rake generate_cops_documentation` and commit the results.'
258
+ exit!
259
+ end
260
+ end
261
+
262
+ def main
263
+ cops = RuboCop::Cop::Cop.registry
264
+ config = RuboCop::ConfigLoader.load_file('config/default.yml')
265
+
266
+ YARD::Registry.load!
267
+ cops.departments.sort!.each do |department|
268
+ print_cops_of_department(cops, department, config)
269
+ end
270
+
271
+ print_table_of_contents(cops)
272
+
273
+ assert_manual_synchronized if ENV['CI'] == 'true'
274
+ ensure
275
+ RuboCop::ConfigLoader.default_configuration = nil
276
+ end
277
+
278
+ main
279
+ end
280
+
281
+ desc 'Syntax check for the documentation comments'
282
+ task documentation_syntax_check: :yard_for_generate_documentation do
283
+ require 'parser/ruby25'
284
+
285
+ ok = true
286
+ YARD::Registry.load!
287
+ cops = RuboCop::Cop::Cop.registry
288
+ cops.each do |cop|
289
+ examples = YARD::Registry.all(:class).find do |code_object|
290
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
291
+
292
+ break code_object.tags('example')
293
+ end
294
+
295
+ examples.to_a.each do |example|
296
+ begin
297
+ buffer = Parser::Source::Buffer.new('<code>', 1)
298
+ buffer.source = example.text
299
+ parser = Parser::Ruby25.new(RuboCop::AST::Builder.new)
300
+ parser.diagnostics.all_errors_are_fatal = true
301
+ parser.parse(buffer)
302
+ rescue Parser::SyntaxError => e
303
+ path = example.object.file
304
+ puts "#{path}: Syntax Error in an example. #{e}"
305
+ ok = false
306
+ end
307
+ end
308
+ end
309
+ abort unless ok
310
+ end