rubocop-solidus 0.1.3 → 0.2.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,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Solidus
6
+ # This cop finds existing_card_id occurrences and suggest using wallet_payment_source_id instead.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # {
12
+ # name: payment_method.name,
13
+ # existing_card_id: payment_source.id
14
+ # }
15
+ #
16
+ # # good
17
+ # {
18
+ # name: payment_method.name,
19
+ # wallet_payment_source_id: payment_source.wallet.wallet_payment_sources.first.id
20
+ # }
21
+ #
22
+ class ExistingCardIdDeprecated < Base
23
+ include TargetSolidusVersion
24
+ minimum_solidus_version 2.2
25
+
26
+ MSG = 'Use `wallet_payment_source_id` instead of `existing_card_id`.'
27
+
28
+ def_node_matcher :existing_card_id?, <<~PATTERN
29
+ (send ... :existing_card_id)
30
+ PATTERN
31
+
32
+ def on_send(node)
33
+ return unless existing_card_id?(node)
34
+
35
+ add_offense(node, severity: :warning)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -5,6 +5,23 @@ module RuboCop
5
5
  module Solidus
6
6
  # This cop finds reimbursement_success_hooks and reimbursement_failed_hooks calls and
7
7
  # asks to remove them and subscribe to reimbursement_reimbursed event instead.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # reimbursement_success_hooks.each { |h| h.call self }
13
+ # reimbursement_failed_hooks.each { |h| h.call self }
14
+ #
15
+ # # good
16
+ #
17
+ # @example
18
+ #
19
+ # # bad
20
+ # reimbursement_success_hooks.any?
21
+ # reimbursement_failed_hooks.any?
22
+ #
23
+ # # good
24
+ #
8
25
  class ReimbursementHookDeprecated < Base
9
26
  include TargetSolidusVersion
10
27
  minimum_solidus_version 2.11
@@ -6,6 +6,13 @@ module RuboCop
6
6
  # This cop finds Spree::Calculator::FreeShipping calls.
7
7
  # This cop is needed as they have been deprecated in future version.
8
8
  #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Spree::Calculator::FreeShipping
13
+ #
14
+ # # good
15
+ #
9
16
  class SpreeCalculatorFreeShippingDeprecated < Base
10
17
  MSG = 'Spree::Calculator::FreeShipping is deprecated.'
11
18
 
@@ -6,10 +6,18 @@ module RuboCop
6
6
  # This cop finds Spree::Calculator::PercentPerItem calls.
7
7
  # This cop is needed as they have been deprecated in future version.
8
8
  #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Spree::Calculator::PercentPerItem
13
+ #
14
+ # # good
15
+ # Spree::Calculator::PercentOnLineItem
16
+ #
9
17
  class SpreeCalculatorPercentPerItemDeprecated < Base
10
18
  extend AutoCorrector
11
19
 
12
- MSG = 'Spree::Calculator::PercentPerItem is deprecated.'
20
+ MSG = 'Spree::Calculator::PercentPerItem is deprecated. Use Spree::Calculator::PercentOnLineItem instead.'
13
21
 
14
22
  def_node_matcher :percent_per_item?, <<~PATTERN
15
23
  (send (... (... :Calculator) :PercentPerItem) $_)
@@ -6,6 +6,13 @@ module RuboCop
6
6
  # This cop finds Spree::Calculator::PriceSack calls.
7
7
  # This cop is needed as they have been deprecated in future version.
8
8
  #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Spree::Calculator::PriceSack
13
+ #
14
+ # # good
15
+ #
9
16
  class SpreeCalculatorPriceSackDeprecated < Base
10
17
  MSG = 'Spree::Calculator::PriceSack is deprecated.'
11
18
 
@@ -3,16 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Solidus
6
- # This cop finds user.default_credit_card suggest using user.wallet.default_wallet_payment_source
6
+ # This cop finds user.default_credit_card suggest using user.wallet.default_wallet_payment_source.
7
+ #
8
+ # @example
7
9
  #
8
- # @example EnforcedStyle:
9
10
  # # bad
10
11
  # user.default_credit_card
11
12
  #
12
13
  # # good
13
14
  # user.wallet.default_wallet_payment_source
14
15
  #
15
- #
16
16
  class SpreeDefaultCreditCardDeprecated < Base
17
17
  extend AutoCorrector
18
18
  include TargetSolidusVersion
@@ -20,7 +20,6 @@ module RuboCop
20
20
 
21
21
  MSG = 'user.default_credit_card is deprecated. Please use user.wallet.default_wallet_payment_source instead.'
22
22
 
23
- # @!method bad_method?(node)
24
23
  def_node_matcher :default_credit_card?, <<~PATTERN
25
24
  (send ... :default_credit_card)
26
25
  PATTERN
@@ -3,29 +3,20 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Solidus
6
- # This cop finds Spree::Gateway::Bogus calls and replaces them with the Spree::PaymentMethod::BogusCreditCard call
6
+ # This cop finds Spree::Gateway::Bogus calls and replaces them with the Spree::PaymentMethod::BogusCreditCard.
7
7
  # This cop is needed as the Spree::Gateway::Bogus has been deprecated in future version.
8
8
  #
9
- # @example EnforcedStyle:
9
+ # @example
10
10
  # # bad
11
11
  # Spree::Gateway::Bogus.new
12
- #
13
- # # good
14
- # Spree::PaymentMethod::BogusCreditCard.new
15
- #
16
- # # bad
17
12
  # Spree::Gateway::Bogus.create
18
- #
19
- # # good
20
- # Spree::PaymentMethod::BogusCreditCard.create
21
- #
22
- # # bad
23
13
  # Spree::Gateway::Bogus.create!
24
14
  #
25
15
  # # good
16
+ # Spree::PaymentMethod::BogusCreditCard.new
17
+ # Spree::PaymentMethod::BogusCreditCard.create
26
18
  # Spree::PaymentMethod::BogusCreditCard.create!
27
19
  #
28
- #
29
20
  class SpreeGatewayBogusDeprecated < Base
30
21
  extend AutoCorrector
31
22
  include TargetSolidusVersion
@@ -33,7 +24,6 @@ module RuboCop
33
24
 
34
25
  MSG = 'Spree::Gateway::Bogus is deprecated. Please use Spree::PaymentMethod::BogusCreditCard instead.'
35
26
 
36
- # @!method bad_method?(node)
37
27
  def_node_matcher :bad_class?, <<~PATTERN
38
28
  (send (... (... :Gateway) :Bogus) $_)
39
29
  PATTERN
@@ -3,16 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Solidus
6
- # This cop finds icon helper calls and suggest using solidus_icon
6
+ # This cop finds icon helper calls and suggest using solidus_icon.
7
+ #
8
+ # @example
7
9
  #
8
- # @example EnforcedStyle:
9
10
  # # bad
10
11
  # helper.icon('example')
11
12
  #
12
13
  # # good
13
14
  # helper.solidus_icon('example')
14
15
  #
15
- #
16
16
  class SpreeIconDeprecated < Base
17
17
  extend AutoCorrector
18
18
  include TargetSolidusVersion
@@ -4,7 +4,15 @@ module RuboCop
4
4
  module Cop
5
5
  module Solidus
6
6
  # This cop finds Spree::Refund.create(your: attributes) calls and
7
- # replaces them with the Spree::Refund.create(your: attributes, perform_after_create: false).perform! call
7
+ # replaces them with the Spree::Refund.create(your: attributes, perform_after_create: false).perform! call.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Spree::Refund.create(your: attributes)
13
+ #
14
+ # # good
15
+ # Spree::Refund.create(your: attributes, perform_after_create: false).perform!
8
16
  #
9
17
  class SpreeRefundCallPerform < Base
10
18
  include TargetSolidusVersion
@@ -16,7 +24,6 @@ module RuboCop
16
24
 
17
25
  RESTRICT_ON_SEND = %i[create].freeze
18
26
 
19
- # @!method bad_method?(node)
20
27
  def_node_matcher :create_refund?, <<~PATTERN
21
28
  (send (const (const nil? :Spree) :Refund) :create ...)
22
29
  PATTERN
@@ -3,43 +3,52 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Solidus
6
- # This cop finds Spree.t method calls and replaces them with the I18n,t method call
6
+ # This cop finds Spree.t method calls and replaces them with the I18n,t method call.
7
7
  # This cop is needed as the Spree.t version has been deprecated in future version.
8
8
  #
9
+ # @example
10
+ # # Without any parameters
9
11
  #
10
- # @example EnforcedStyle: bar (default)
11
12
  # # bad
12
13
  # Spree.t(:bar)
13
14
  #
14
15
  # # good
15
16
  # I18n.t(:bar, scope: :spree)
16
17
  #
18
+ # @example
19
+ # # With the scope parameter
20
+ #
17
21
  # # bad
18
22
  # Spree.t(:bar, scope: [:city])
19
23
  #
20
24
  # # good
21
25
  # I18n.t(:bar, scope: [:spree, :city])
22
26
  #
27
+ # @example
28
+ # # With the scope and other parameters
29
+ #
23
30
  # # bad
24
31
  # Spree.t(:bar, scope: [:city], email: email)
25
32
  #
26
33
  # # good
27
34
  # I18n.t(:bar, scope: [:spree, :city], email: email)
28
35
  #
36
+ # @example
37
+ # # With the scope parameter as a string
38
+ #
29
39
  # # bad
30
40
  # Spree.t('bar', scope: 'admin.city')
31
41
  #
32
42
  # # good
33
43
  # I18n.t('bar', scope: 'spree.admin.city')
34
44
  #
35
- #
36
45
  class SpreeTDeprecated < Base
37
46
  extend AutoCorrector
47
+ include IgnoredNode
38
48
  MSG = 'Use I18n.t instead of Spree.t which has been deprecated in future versions.'
39
49
 
40
50
  RESTRICT_ON_SEND = %i[t].freeze
41
51
 
42
- # @!method spree_t?(node)
43
52
  def_node_matcher :spree_t?, <<~PATTERN
44
53
  (send ($...) :t ...)
45
54
  PATTERN
@@ -50,8 +59,11 @@ module RuboCop
50
59
  return unless spree_t?(node).include?(:Spree)
51
60
 
52
61
  add_offense(node) do |corrector|
62
+ next if part_of_ignored_node?(node)
63
+
53
64
  corrector.replace(node, corrected_statement(node))
54
65
  end
66
+ ignore_node(node)
55
67
  end
56
68
 
57
69
  # rubocop:disable Metrics/MethodLength
@@ -3,6 +3,7 @@
3
3
  require_relative 'mixin/target_solidus_version'
4
4
 
5
5
  require_relative 'solidus/class_eval_decorator'
6
+ require_relative 'solidus/existing_card_id_deprecated'
6
7
  require_relative 'solidus/reimbursement_hook_deprecated'
7
8
  require_relative 'solidus/spree_calculator_free_shipping_deprecated'
8
9
  require_relative 'solidus/spree_calculator_percent_per_item_deprecated'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Solidus
5
- VERSION = '0.1.3'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -0,0 +1,5 @@
1
+ ### New features
2
+
3
+ * [#51](https://github.com/solidusio/rubocop-solidus/pull/51): Create automatic documentation based on the cop's descriptions. ([@MassimilianoLattanzio][])
4
+
5
+ [@MassimilianoLattanzio]: https://github.com/MassimilianoLattanzio
@@ -0,0 +1,9 @@
1
+ ### New features
2
+
3
+ * [#60](https://github.com/solidusio/rubocop-solidus/issues/60): Create new cop to check existing_card_id. ([@MassimilianoLattanzio][])
4
+
5
+ ### Bug fixes
6
+
7
+ * [#60](https://github.com/solidusio/rubocop-solidus/issues/60): Fix overridden add_offense method. ([@MassimilianoLattanzio][])
8
+
9
+ [@MassimilianoLattanzio]: https://github.com/MassimilianoLattanzio
@@ -19,7 +19,8 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.metadata['homepage_uri'] = spec.homepage
21
21
  spec.metadata['source_code_uri'] = 'https://www.github.com/solidusio/rubocop-solidus'
22
- spec.metadata['changelog_uri'] = 'https://www.github.com/solidusio/rubocop-solidus'
22
+ spec.metadata['changelog_uri'] = 'https://www.github.com/solidusio/rubocop-solidus/blob/main/CHANGELOG.md'
23
+ spec.metadata['documentation_uri'] = 'https://www.github.com/solidusio/rubocop-solidus/blob/main/docs/cops.md'
23
24
 
24
25
  # Specify which files should be added to the gem when it is released.
25
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
data/tasks/changelog.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  # Changelog utility
4
4
  class Changelog
5
5
  ENTRIES_PATH = 'changelog/'
6
- FIRST_HEADER = /#{Regexp.escape("## master (unreleased)\n")}/m.freeze
6
+ FIRST_HEADER = /#{Regexp.escape("## main (unreleased)\n")}/m.freeze
7
7
  ENTRIES_PATH_TEMPLATE = "#{ENTRIES_PATH}%<type>s_%<name>s.md"
8
8
  TYPE_REGEXP = /#{Regexp.escape(ENTRIES_PATH)}([a-z]+)_/.freeze
9
9
  TYPE_TO_HEADER = { new: 'New features', fix: 'Bug fixes', change: 'Changes' }.freeze
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+ require 'rubocop'
5
+ require 'rubocop-solidus'
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 << required_ruby_version(cop)
21
+ content << properties(config, cop)
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
+
29
+ def examples(examples_object)
30
+ examples_object.each_with_object(h3('Examples').dup) do |example, content|
31
+ content << h4(example.name) unless example.name == ''
32
+ content << code_example(example)
33
+ end
34
+ end
35
+
36
+ def required_ruby_version(cop)
37
+ return '' unless cop.respond_to?(:required_minimum_ruby_version)
38
+
39
+ <<~NOTE
40
+ !!! Note
41
+
42
+ Required Ruby version: #{cop.required_minimum_ruby_version}
43
+
44
+ NOTE
45
+ end
46
+
47
+ def properties(config, cop)
48
+ header = [
49
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
50
+ 'VersionChanged', 'Required Solidus Version'
51
+ ]
52
+ config = config.for_cop(cop)
53
+ safe_auto_correct = config.fetch('SafeAutoCorrect', true)
54
+ autocorrect = if cop.support_autocorrect?
55
+ "Yes #{'(Unsafe)' unless safe_auto_correct}"
56
+ else
57
+ 'No'
58
+ end
59
+ minimum_solidus_version = if cop.respond_to?(:required_minimum_solidus_version)
60
+ cop.required_minimum_solidus_version
61
+ else
62
+ '-'
63
+ end
64
+ content = [[
65
+ config.fetch('Enabled') ? 'Enabled' : 'Disabled',
66
+ config.fetch('Safe', true) ? 'Yes' : 'No',
67
+ autocorrect,
68
+ config.fetch('VersionAdded', '-'),
69
+ config.fetch('VersionChanged', '-'),
70
+ minimum_solidus_version
71
+ ]]
72
+ "#{to_table(header, content)}\n"
73
+ end
74
+
75
+ def h2(title)
76
+ content = +"\n"
77
+ content << "## #{title}\n"
78
+ content << "\n"
79
+ content
80
+ end
81
+
82
+ def h3(title)
83
+ content = +"\n"
84
+ content << "### #{title}\n"
85
+ content << "\n"
86
+ content
87
+ end
88
+
89
+ def h4(title)
90
+ content = +"#### #{title}\n"
91
+ content << "\n"
92
+ content
93
+ end
94
+
95
+ def code_example(ruby_code)
96
+ content = +"```ruby\n"
97
+ content << ruby_code.text
98
+ .gsub('@good', '# good').gsub('@bad', '# bad').strip
99
+ content << "\n```\n"
100
+ content
101
+ end
102
+
103
+ def configurations(pars)
104
+ return '' if pars.empty?
105
+
106
+ header = ['Name', 'Default value', 'Configurable values']
107
+ configs = pars.each_key.reject { |key| key.start_with?('Supported') }
108
+ content = configs.map do |name|
109
+ configurable = configurable_values(pars, name)
110
+ default = format_table_value(pars[name])
111
+ [name, default, configurable]
112
+ end
113
+
114
+ h3('Configurable attributes') + to_table(header, content)
115
+ end
116
+
117
+ # rubocop:disable Metrics/CyclomaticComplexity
118
+ def configurable_values(pars, name)
119
+ case name
120
+ when /^Enforced/
121
+ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
122
+ format_table_value(pars[supported_style_name])
123
+ when 'IndentationWidth'
124
+ 'Integer'
125
+ when 'Database'
126
+ format_table_value(pars['SupportedDatabases'])
127
+ else
128
+ case pars[name]
129
+ when String
130
+ 'String'
131
+ when Integer
132
+ 'Integer'
133
+ when Float
134
+ 'Float'
135
+ when true, false
136
+ 'Boolean'
137
+ when Array
138
+ 'Array'
139
+ else
140
+ ''
141
+ end
142
+ end
143
+ end
144
+ # rubocop:enable Metrics/CyclomaticComplexity
145
+
146
+ def to_table(header, content)
147
+ table = [
148
+ header.join(' | '),
149
+ Array.new(header.size, '---').join(' | ')
150
+ ]
151
+ table.concat(content.map { |c| c.join(' | ') })
152
+ "#{table.join("\n")}\n"
153
+ end
154
+
155
+ def format_table_value(val)
156
+ value =
157
+ case val
158
+ when Array
159
+ if val.empty?
160
+ '`[]`'
161
+ else
162
+ val.map { |config| format_table_value(config) }.join(', ')
163
+ end
164
+ else
165
+ "`#{val.nil? ? '<none>' : val}`"
166
+ end
167
+ value.gsub("#{Dir.pwd}/", '').rstrip
168
+ end
169
+
170
+ def references(config, cop)
171
+ cop_config = config.for_cop(cop)
172
+ urls = RuboCop::Cop::MessageAnnotator.new(
173
+ config, cop.name, cop_config, {}
174
+ ).urls
175
+ return '' if urls.empty?
176
+
177
+ content = h3('References')
178
+ content << urls.map { |url| "* [#{url}](#{url})" }.join("\n")
179
+ content << "\n"
180
+ content
181
+ end
182
+
183
+ def print_cops_of_department(cops, department, config)
184
+ selected_cops = cops_of_department(cops, department).select do |cop|
185
+ cop.to_s.start_with?('RuboCop::Cop::Solidus')
186
+ end
187
+ return if selected_cops.empty?
188
+
189
+ content = +"# #{department}\n"
190
+ selected_cops.each do |cop|
191
+ content << print_cop_with_doc(cop, config)
192
+ end
193
+ file_name = "#{Dir.pwd}/docs/cops_#{department.downcase}.md"
194
+ File.open(file_name, 'w') do |file|
195
+ puts "* generated #{file_name}"
196
+ file.write("#{content.strip}\n")
197
+ end
198
+ end
199
+
200
+ def print_cop_with_doc(cop, config)
201
+ t = config.for_cop(cop)
202
+ non_display_keys = %w[Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
203
+ VersionChanged]
204
+ pars = t.reject { |k| non_display_keys.include?(k) }
205
+ description = 'No documentation'
206
+ examples_object = []
207
+ YARD::Registry.all(:class).detect do |code_object|
208
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
209
+
210
+ description = code_object.docstring unless code_object.docstring.blank?
211
+ examples_object = code_object.tags('example')
212
+ end
213
+ cops_body(config, cop, description, examples_object, pars)
214
+ end
215
+
216
+ # rubocop:disable Metrics/AbcSize
217
+ def table_of_content_for_department(cops, department)
218
+ selected_cops = cops_of_department(cops, department.to_sym).select do |cop|
219
+ cop.to_s.start_with?('RuboCop::Cop::Solidus')
220
+ end
221
+ return if selected_cops.empty?
222
+
223
+ type_title = department[0].upcase + department[1..]
224
+ filename = "cops_#{department.downcase}.md"
225
+ content = +"#### Department [#{type_title}](#{filename})\n\n"
226
+ selected_cops.each do |cop|
227
+ anchor = cop.cop_name.sub('/', '').downcase
228
+ content << "* [#{cop.cop_name}](#{filename}##{anchor})\n"
229
+ end
230
+
231
+ content
232
+ end
233
+ # rubocop:enable Metrics/AbcSize
234
+
235
+ def print_table_of_contents(cops)
236
+ path = "#{Dir.pwd}/docs/cops.md"
237
+ original = File.read(path)
238
+ content = +"<!-- START_COP_LIST -->\n"
239
+
240
+ content << table_contents(cops)
241
+
242
+ content << "\n<!-- END_COP_LIST -->"
243
+
244
+ unless original.empty?
245
+ content = original.sub(
246
+ /<!-- START_COP_LIST -->.+<!-- END_COP_LIST -->/m, content
247
+ )
248
+ end
249
+ File.write(path, content)
250
+ end
251
+
252
+ def table_contents(cops)
253
+ cops
254
+ .departments
255
+ .map(&:to_s)
256
+ .sort
257
+ .map { |department| table_of_content_for_department(cops, department) }
258
+ .compact
259
+ .join("\n")
260
+ end
261
+
262
+ def assert_docs_synchronized
263
+ # Do not print diff and yield whether exit code was zero
264
+ sh('git diff --quiet docs') do |outcome, _|
265
+ return if outcome
266
+
267
+ # Output diff before raising error
268
+ sh('GIT_PAGER=cat git diff docs')
269
+
270
+ warn('The docs directory is out of sync. ' \
271
+ 'Run `rake generate_cops_documentation` and commit the results.')
272
+ exit!
273
+ end
274
+ end
275
+
276
+ def main
277
+ cops = RuboCop::Cop::Cop.registry
278
+ config = RuboCop::ConfigLoader.load_file('config/default.yml')
279
+
280
+ YARD::Registry.load!
281
+ cops.departments.sort!.each do |department|
282
+ print_cops_of_department(cops, department, config)
283
+ end
284
+
285
+ print_table_of_contents(cops)
286
+
287
+ assert_docs_synchronized if ENV['CI'] == 'true'
288
+ ensure
289
+ RuboCop::ConfigLoader.default_configuration = nil
290
+ end
291
+
292
+ main
293
+ end
294
+
295
+ desc('Syntax check for the documentation comments')
296
+ task documentation_syntax_check: :yard_for_generate_documentation do
297
+ require 'parser/ruby27'
298
+
299
+ ok = true
300
+ YARD::Registry.load!
301
+ cops = RuboCop::Cop::Cop.registry
302
+ cops.each do |cop|
303
+ examples = YARD::Registry.all(:class).find do |code_object|
304
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
305
+
306
+ break code_object.tags('example')
307
+ end
308
+
309
+ examples.to_a.each do |example|
310
+ buffer = Parser::Source::Buffer.new('<code>', 1)
311
+ buffer.source = example.text
312
+ parser = Parser::Ruby27.new(RuboCop::AST::Builder.new)
313
+ parser.diagnostics.all_errors_are_fatal = true
314
+ parser.parse(buffer)
315
+ rescue Parser::SyntaxError => e
316
+ path = example.object.file
317
+ puts "#{path}: Syntax Error in an example. #{e}"
318
+ ok = false
319
+ end
320
+ end
321
+ abort unless ok
322
+ end