rubocop-rspec 1.24.0 → 1.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -2
- data/README.md +7 -4
- data/Rakefile +18 -3
- data/config/default.yml +25 -0
- data/lib/rubocop-rspec.rb +3 -0
- data/lib/rubocop/cop/rspec/be.rb +35 -0
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +34 -0
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_example_group.rb +3 -3
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -2
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +148 -0
- data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +1 -3
- data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +3 -3
- data/lib/rubocop/cop/rspec/instance_variable.rb +2 -2
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +6 -3
- data/lib/rubocop/cop/rspec/pending.rb +71 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +11 -13
- data/lib/rubocop/cop/rspec/return_from_stub.rb +9 -16
- data/lib/rubocop/cop/rspec/shared_examples.rb +76 -0
- data/lib/rubocop/cop/rspec_cops.rb +4 -0
- data/lib/rubocop/rspec/example.rb +1 -1
- data/lib/rubocop/rspec/node.rb +19 -0
- data/lib/rubocop/rspec/top_level_describe.rb +3 -6
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +6 -1
- data/spec/rubocop/cop/rspec/be_spec.rb +33 -0
- data/spec/rubocop/cop/rspec/capybara/feature_methods_spec.rb +75 -18
- data/spec/rubocop/cop/rspec/cop_spec.rb +0 -4
- data/spec/rubocop/cop/rspec/described_class_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/example_without_description_spec.rb +8 -0
- data/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb +140 -0
- data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +11 -1
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +15 -0
- data/spec/rubocop/cop/rspec/pending_spec.rb +162 -0
- data/spec/rubocop/cop/rspec/predicate_matcher_spec.rb +13 -9
- data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +9 -0
- data/spec/rubocop/cop/rspec/shared_examples_spec.rb +93 -0
- data/spec/spec_helper.rb +1 -1
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c195bc91134a73125f33d0675230a01fd467747690f3113ff3a924559d7c748c
|
4
|
+
data.tar.gz: 3f9fcaedd22ab9f67542b083ef72a6ab466df04a758c84f3e244176b781a6109
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be3574c7d021a099bdd2869d47a908f4ac5c3ea9e12823030db025a92d24fd3d8008373b422b72e7e666cfefda0a983b3ae6d5f57e62c2dd14f99dc416d48ac3
|
7
|
+
data.tar.gz: 8bcad630c6244f19a896c061c15c94dbe9611f651d72306642bb980c2aa082b0d78d54f54e3b32544b475c4cbbb8a18dbe8631105cdbec4f6d12e0b81851b8b2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 1.25.0 (2018-04-07)
|
6
|
+
|
7
|
+
* Add `RSpec/SharedExamples` cop to enforce consistent usage of string to titleize shared examples. ([@anthony-robin][])
|
8
|
+
* Add `RSpec/Be` cop to enforce passing argument to the generic `be` matcher. ([@Darhazer][])
|
9
|
+
* Fix false positives in `StaticAttributeDefinedDynamically` and `ReturnFromStub` when a const is used in an array or hash. ([@Darhazer][])
|
10
|
+
* Add `RSpec/Pending` cop to enforce no existing pending or skipped examples. This is disabled by default. ([@patrickomatic][])
|
11
|
+
* Fix `RSpec/NestedGroups` cop support --auto-gen-config. ([@walf443][])
|
12
|
+
* Fix false positives in `Capybara/FeatureMethods` when feature methods are used as property names in a factory. ([@Darhazer][])
|
13
|
+
* Allow configuring enabled methods in `Capybara/FeatureMethods`. ([@Darhazer][])
|
14
|
+
* Add `FactoryBot/CreateList` cop. ([@Darhazer][])
|
15
|
+
|
5
16
|
## 1.24.0 (2018-03-06)
|
6
17
|
|
7
18
|
* Compatibility with RuboCop v0.53.0. ([@bquorning][])
|
@@ -316,3 +327,4 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
316
327
|
[@anthony-robin]: https://github.com/anthony-robin
|
317
328
|
[@jojos003]: https://github.com/jojos003
|
318
329
|
[@abrom]: https://github.com/abrom
|
330
|
+
[@patrickomatic]: https://github.com/patrickomatic
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,10 +2,9 @@
|
|
2
2
|
|
3
3
|
[![Join the chat at https://gitter.im/rubocop-rspec/Lobby](https://badges.gitter.im/rubocop-rspec/Lobby.svg)](https://gitter.im/rubocop-rspec/Lobby)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/rubocop-rspec.svg)](https://rubygems.org/gems/rubocop-rspec)
|
5
|
-
[![
|
6
|
-
[![
|
7
|
-
[![
|
8
|
-
[![Code Climate](https://codeclimate.com/github/backus/rubocop-rspec/badges/gpa.svg)](https://codeclimate.com/github/backus/rubocop-rspec)
|
5
|
+
[![CircleCI](https://circleci.com/gh/rubocop-rspec/rubocop-rspec.svg?style=svg)](https://circleci.com/gh/rubocop-rspec/rubocop-rspec)
|
6
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/f6254deb61671e357f30/test_coverage)](https://codeclimate.com/github/rubocop-rspec/rubocop-rspec/test_coverage)
|
7
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/f6254deb61671e357f30/maintainability)](https://codeclimate.com/github/rubocop-rspec/rubocop-rspec/maintainability)
|
9
8
|
|
10
9
|
RSpec-specific analysis for your projects, as an extension to
|
11
10
|
[RuboCop](https://github.com/bbatsov/rubocop).
|
@@ -60,6 +59,10 @@ end
|
|
60
59
|
|
61
60
|
rubocop-rspec is available on Code Climate as part of the rubocop engine. [Learn More](https://codeclimate.com/changelog/55a433bbe30ba00852000fac).
|
62
61
|
|
62
|
+
## Documentation
|
63
|
+
|
64
|
+
You can read more about RuboCop-RSpec in its [official manual](http://rubocop-rspec.readthedocs.io).
|
65
|
+
|
63
66
|
## Inspecting files that don't end with `_spec.rb`
|
64
67
|
|
65
68
|
By default, `rubocop-rspec` only inspects code within paths ending in `_spec.rb` or including `spec/`. You can override this setting in your config file by specifying one or more patterns:
|
data/Rakefile
CHANGED
@@ -12,6 +12,9 @@ rescue Bundler::BundlerError => e
|
|
12
12
|
end
|
13
13
|
|
14
14
|
require 'rspec/core/rake_task'
|
15
|
+
|
16
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
17
|
+
|
15
18
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
16
19
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
17
20
|
end
|
@@ -20,8 +23,6 @@ desc 'Run RSpec with code coverage'
|
|
20
23
|
task :coverage do
|
21
24
|
ENV['COVERAGE'] = 'true'
|
22
25
|
Rake::Task['spec'].execute
|
23
|
-
|
24
|
-
sh('codeclimate-test-reporter') if ENV['CI']
|
25
26
|
end
|
26
27
|
|
27
28
|
desc 'Run RuboCop over this gem'
|
@@ -44,7 +45,21 @@ task confirm_config: :build_config do
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
|
48
|
+
desc 'Confirm documentation is up to date'
|
49
|
+
task confirm_documentation: :generate_cops_documentation do
|
50
|
+
_, _, _, process =
|
51
|
+
Open3.popen3('git diff --exit-code manual/')
|
52
|
+
|
53
|
+
unless process.value.success?
|
54
|
+
raise 'manual is out of sync, please add manual/ to the commit'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
task default: %i[build_config coverage
|
59
|
+
internal_investigation
|
60
|
+
confirm_config
|
61
|
+
documentation_syntax_check
|
62
|
+
confirm_documentation]
|
48
63
|
|
49
64
|
desc 'Generate a new cop template'
|
50
65
|
task :new_cop, [:cop] do |_task, args|
|
data/config/default.yml
CHANGED
@@ -29,6 +29,11 @@ RSpec/AlignRightLetBrace:
|
|
29
29
|
Enabled: false
|
30
30
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace
|
31
31
|
|
32
|
+
RSpec/Be:
|
33
|
+
Description: Check for expectations where `be` is used without argument.
|
34
|
+
Enabled: true
|
35
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be
|
36
|
+
|
32
37
|
RSpec/BeEql:
|
33
38
|
Description: Check for expectations where `be(...)` can replace `eql(...)`.
|
34
39
|
Enabled: true
|
@@ -289,6 +294,11 @@ RSpec/OverwritingSetup:
|
|
289
294
|
Description: Checks if there is a let/subject that overwrites an existing one.
|
290
295
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup
|
291
296
|
|
297
|
+
RSpec/Pending:
|
298
|
+
Enabled: false
|
299
|
+
Description: Checks for any pending or skipped examples.
|
300
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending
|
301
|
+
|
292
302
|
RSpec/RepeatedDescription:
|
293
303
|
Enabled: true
|
294
304
|
Description: Check for repeated description strings in example groups.
|
@@ -313,6 +323,11 @@ RSpec/SharedContext:
|
|
313
323
|
Enabled: true
|
314
324
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext
|
315
325
|
|
326
|
+
RSpec/SharedExamples:
|
327
|
+
Description: Enforces use of string to titleize shared examples.
|
328
|
+
Enabled: true
|
329
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples
|
330
|
+
|
316
331
|
RSpec/SingleArgumentMessageChain:
|
317
332
|
Description: Checks that chains of messages contain more than one element.
|
318
333
|
Enabled: true
|
@@ -362,8 +377,18 @@ Capybara/CurrentPathExpectation:
|
|
362
377
|
Capybara/FeatureMethods:
|
363
378
|
Description: Checks for consistent method usage in feature specs.
|
364
379
|
Enabled: true
|
380
|
+
EnabledMethods: []
|
365
381
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
|
366
382
|
|
383
|
+
FactoryBot/CreateList:
|
384
|
+
Description: Checks for create_list usage.
|
385
|
+
Enabled: true
|
386
|
+
EnforcedStyle: create_list
|
387
|
+
SupportedStyles:
|
388
|
+
- create_list
|
389
|
+
- n_times
|
390
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/CreateList
|
391
|
+
|
367
392
|
FactoryBot/DynamicAttributeDefinedStatically:
|
368
393
|
Description: Prefer declaring dynamic attribute values in a block.
|
369
394
|
Enabled: true
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -6,6 +6,7 @@ require 'rubocop'
|
|
6
6
|
require_relative 'rubocop/rspec'
|
7
7
|
require_relative 'rubocop/rspec/version'
|
8
8
|
require_relative 'rubocop/rspec/inject'
|
9
|
+
require_relative 'rubocop/rspec/node'
|
9
10
|
require_relative 'rubocop/rspec/top_level_describe'
|
10
11
|
require_relative 'rubocop/rspec/wording'
|
11
12
|
require_relative 'rubocop/rspec/util'
|
@@ -38,3 +39,5 @@ module RuboCop
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
42
|
+
|
43
|
+
RuboCop::AST::Node.include(RuboCop::RSpec::Node)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module RSpec
|
4
|
+
# Check for expectations where `be` is used without argument.
|
5
|
+
#
|
6
|
+
# The `be` matcher is too generic, as it pass on everything that is not
|
7
|
+
# nil or false. If that is the exact intend, use `be_truthy`. In all other
|
8
|
+
# cases it's better to specify what exactly is the expected value.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# expect(foo).to be
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# expect(foo).to be_truthy
|
17
|
+
# expect(foo).to be 1.0
|
18
|
+
# expect(foo).to be(true)
|
19
|
+
#
|
20
|
+
class Be < Cop
|
21
|
+
MSG = 'Don\'t use `be` without an argument.'.freeze
|
22
|
+
|
23
|
+
def_node_matcher :be_without_args, <<-PATTERN
|
24
|
+
(send _ {:to :not_to :to_not} $(send nil? :be))
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
be_without_args(node) do |matcher|
|
29
|
+
add_offense(matcher, location: :selector)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -6,6 +6,14 @@ module RuboCop
|
|
6
6
|
module Capybara
|
7
7
|
# Checks for consistent method usage in feature specs.
|
8
8
|
#
|
9
|
+
# By default, the cop disables all Capybara-specific methods that have
|
10
|
+
# the same native RSpec method (e.g. are just aliases). Some teams
|
11
|
+
# however may prefer using some of the Capybara methods (like `feature`)
|
12
|
+
# to make it obvious that the test uses Capybara, while still disable
|
13
|
+
# the rest of the methods, like `given` (alias for `let`), `background`
|
14
|
+
# (alias for `before`), etc. You can configure which of the methods to
|
15
|
+
# be enabled by using the EnabledMethods configuration option.
|
16
|
+
#
|
9
17
|
# @example
|
10
18
|
# # bad
|
11
19
|
# feature 'User logs in' do
|
@@ -45,6 +53,12 @@ module RuboCop
|
|
45
53
|
feature: :describe
|
46
54
|
}.freeze
|
47
55
|
|
56
|
+
def_node_matcher :spec?, <<-PATTERN
|
57
|
+
(block
|
58
|
+
(send {(const nil? :RSpec) nil?} {:describe :feature} ...)
|
59
|
+
...)
|
60
|
+
PATTERN
|
61
|
+
|
48
62
|
def_node_matcher :feature_method, <<-PATTERN
|
49
63
|
(block
|
50
64
|
$(send {(const nil? :RSpec) nil?} ${#{MAP.keys.map(&:inspect).join(' ')}} ...)
|
@@ -52,7 +66,11 @@ module RuboCop
|
|
52
66
|
PATTERN
|
53
67
|
|
54
68
|
def on_block(node)
|
69
|
+
return unless spec?(root_node)
|
70
|
+
|
55
71
|
feature_method(node) do |send_node, match|
|
72
|
+
next if enabled?(match)
|
73
|
+
|
56
74
|
add_offense(
|
57
75
|
send_node,
|
58
76
|
location: :selector,
|
@@ -66,6 +84,22 @@ module RuboCop
|
|
66
84
|
corrector.replace(node.loc.selector, MAP[node.method_name].to_s)
|
67
85
|
end
|
68
86
|
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def root_node
|
91
|
+
processed_source.ast
|
92
|
+
end
|
93
|
+
|
94
|
+
def enabled?(method_name)
|
95
|
+
enabled_methods.include?(method_name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def enabled_methods
|
99
|
+
cop_config
|
100
|
+
.fetch('EnabledMethods', [])
|
101
|
+
.map(&:to_sym)
|
102
|
+
end
|
69
103
|
end
|
70
104
|
end
|
71
105
|
end
|
@@ -36,9 +36,9 @@ module RuboCop
|
|
36
36
|
# @example configuration
|
37
37
|
#
|
38
38
|
# # .rubocop.yml
|
39
|
-
# RSpec/EmptyExampleGroup:
|
40
|
-
#
|
41
|
-
#
|
39
|
+
# # RSpec/EmptyExampleGroup:
|
40
|
+
# # CustomIncludeMethods:
|
41
|
+
# # - include_tests
|
42
42
|
#
|
43
43
|
# # spec_helper.rb
|
44
44
|
# RSpec.configure do |config|
|
@@ -72,8 +72,7 @@ module RuboCop
|
|
72
72
|
private
|
73
73
|
|
74
74
|
def check_example_without_description(node)
|
75
|
-
|
76
|
-
return unless arg.nil?
|
75
|
+
return if node.arguments?
|
77
76
|
return unless disallow_empty_description?(node)
|
78
77
|
|
79
78
|
add_offense(node, message: MSG_ADD_DESCRIPTION)
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module FactoryBot
|
7
|
+
# Checks for create_list usage.
|
8
|
+
#
|
9
|
+
# This cop can be configured using the `EnforcedStyle` option
|
10
|
+
#
|
11
|
+
# @example `EnforcedStyle: create_list`
|
12
|
+
# # bad
|
13
|
+
# 3.times { create :user }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# create_list :user, 3
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# 3.times { |n| create :user, created_at: n.months.ago }
|
20
|
+
#
|
21
|
+
# @example `EnforcedStyle: n_times`
|
22
|
+
# # bad
|
23
|
+
# create_list :user, 3
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# 3.times { create :user }
|
27
|
+
class CreateList < Cop
|
28
|
+
include ConfigurableEnforcedStyle
|
29
|
+
|
30
|
+
MSG_CREATE_LIST = 'Prefer create_list.'.freeze
|
31
|
+
MSG_N_TIMES = 'Prefer %<number>s.times.'.freeze
|
32
|
+
|
33
|
+
def_node_matcher :n_times_block?, <<-PATTERN
|
34
|
+
(block
|
35
|
+
(send (int _) :times)
|
36
|
+
...
|
37
|
+
)
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def_node_matcher :factory_call, <<-PATTERN
|
41
|
+
(send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create (sym $_) $...)
|
42
|
+
PATTERN
|
43
|
+
|
44
|
+
def_node_matcher :factory_list_call, <<-PATTERN
|
45
|
+
(send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym $_) (int $_) $...)
|
46
|
+
PATTERN
|
47
|
+
|
48
|
+
def on_block(node)
|
49
|
+
return unless style == :create_list
|
50
|
+
return unless n_times_block?(node)
|
51
|
+
return unless contains_only_factory?(node.body)
|
52
|
+
|
53
|
+
add_offense(node.send_node,
|
54
|
+
location: :expression, message: MSG_CREATE_LIST)
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_send(node)
|
58
|
+
return unless style == :n_times
|
59
|
+
|
60
|
+
factory_list_call(node) do |_receiver, _factory, count, _|
|
61
|
+
add_offense(
|
62
|
+
node,
|
63
|
+
location: :selector,
|
64
|
+
message: format(MSG_N_TIMES, number: count)
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def autocorrect(node)
|
70
|
+
if style == :create_list
|
71
|
+
autocorrect_n_times_to_create_list(node)
|
72
|
+
else
|
73
|
+
autocorrect_create_list_to_n_times(node)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def contains_only_factory?(node)
|
80
|
+
if node.block_type?
|
81
|
+
factory_call(node.send_node)
|
82
|
+
else
|
83
|
+
factory_call(node)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def autocorrect_n_times_to_create_list(node)
|
88
|
+
block = node.parent
|
89
|
+
count = block.receiver.source
|
90
|
+
replacement = factory_call_replacement(block.body, count)
|
91
|
+
|
92
|
+
lambda do |corrector|
|
93
|
+
corrector.replace(block.loc.expression, replacement)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def autocorrect_create_list_to_n_times(node)
|
98
|
+
replacement = generate_n_times_block(node)
|
99
|
+
lambda do |corrector|
|
100
|
+
corrector.replace(node.loc.expression, replacement)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_n_times_block(node)
|
105
|
+
receiver, factory, count, options = *factory_list_call(node)
|
106
|
+
|
107
|
+
arguments = ":#{factory}"
|
108
|
+
options = build_options_string(options)
|
109
|
+
arguments += ", #{options}" unless options.empty?
|
110
|
+
|
111
|
+
replacement = format_receiver(receiver)
|
112
|
+
replacement += format_method_call(node, 'create', arguments)
|
113
|
+
"#{count}.times { #{replacement} }"
|
114
|
+
end
|
115
|
+
|
116
|
+
def factory_call_replacement(body, count)
|
117
|
+
receiver, factory, options = *factory_call(body)
|
118
|
+
|
119
|
+
arguments = ":#{factory}, #{count}"
|
120
|
+
options = build_options_string(options)
|
121
|
+
arguments += ", #{options}" unless options.empty?
|
122
|
+
|
123
|
+
replacement = format_receiver(receiver)
|
124
|
+
replacement += format_method_call(body, 'create_list', arguments)
|
125
|
+
replacement
|
126
|
+
end
|
127
|
+
|
128
|
+
def build_options_string(options)
|
129
|
+
options.map(&:source).join(', ')
|
130
|
+
end
|
131
|
+
|
132
|
+
def format_method_call(node, method, arguments)
|
133
|
+
if node.parenthesized?
|
134
|
+
"#{method}(#{arguments})"
|
135
|
+
else
|
136
|
+
"#{method} #{arguments}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def format_receiver(receiver)
|
141
|
+
return '' unless receiver
|
142
|
+
"#{receiver.source}."
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|