transpec 1.2.2 → 1.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +36 -16
- data/README.md.erb +36 -16
- data/lib/transpec/option_parser.rb +1 -1
- data/lib/transpec/syntax/have.rb +126 -39
- data/lib/transpec/syntax/its.rb +15 -2
- data/lib/transpec/syntax/method_stub.rb +4 -4
- data/lib/transpec/syntax/mixin/any_instance.rb +43 -4
- data/lib/transpec/syntax/mixin/send.rb +4 -0
- data/lib/transpec/syntax/should_receive.rb +9 -9
- data/lib/transpec/version.rb +2 -2
- data/spec/transpec/cli_spec.rb +2 -2
- data/spec/transpec/converter_spec.rb +2 -2
- data/spec/transpec/static_context_inspector_spec.rb +5 -5
- data/spec/transpec/syntax/have_spec.rb +355 -0
- data/spec/transpec/syntax/its_spec.rb +49 -24
- data/spec/transpec/syntax/method_stub_spec.rb +467 -323
- data/spec/transpec/syntax/should_receive_spec.rb +212 -24
- data/transpec.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9cd93b43c3629f7c2f09782ee9616100b5147b8
|
4
|
+
data.tar.gz: 663a9de354fa930e147853a2024da3f904afae5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94f4f9b4a08a5d8ca703b9588e3bdda7a63eef38dc3b67b21de62a87c9f60ea09f560151ed08e68994281e0361ce7d2b344635843380c410c053c9f3c14f9f37
|
7
|
+
data.tar.gz: 65afbbd2ddd3f72b9794d95ed261c6d7f6c4f7f54ea02e415eee927c36c1fa95e6a2a71f8f60cce3e83bb26a65e52dea067a81db6d6352cf09117f4bc512e515
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
## Development
|
4
4
|
|
5
|
+
## v1.3.0
|
6
|
+
|
7
|
+
* Handle singular collection names like `have(n).item` ([#18](https://github.com/yujinakayama/transpec/issues/18))
|
8
|
+
* Handle collection accessors with arguments like `have(n).errors_on(...)` ([#18](https://github.com/yujinakayama/transpec/issues/18))
|
9
|
+
* Handle `described_class.any_instance` ([#18](https://github.com/yujinakayama/transpec/issues/18))
|
10
|
+
* Handle indirect `any_instance` subject with runtime information (e.g. `variable = SomeClass.any_instance; variable.stub(:message)`)
|
11
|
+
* Disable conversion of `have(n).items` automatically if `rspec-rails` or `rspec-collection_matchers` is loaded in the target project
|
12
|
+
* Disable conversion of `its` automatically if `rspec-its` is loaded in the target project
|
13
|
+
|
5
14
|
## v1.2.2
|
6
15
|
|
7
16
|
* Fix error `singleton can't be dumped (TypeError)` at the end of dynamic analysis ([#17](https://github.com/yujinakayama/transpec/issues/17))
|
data/README.md
CHANGED
@@ -117,11 +117,11 @@ Before converting your specs:
|
|
117
117
|
* Run `rspec` and check if all the specs pass.
|
118
118
|
* Ensure the Git repository is clean. (You don't want to mix up your changes and Transpec's changes, right?)
|
119
119
|
|
120
|
-
Then, run `transpec` (using
|
120
|
+
Then, run `transpec` (using `-m/--generate-commit-message` is recommended) in the project root directory:
|
121
121
|
|
122
122
|
```bash
|
123
123
|
$ cd some-project
|
124
|
-
$ transpec
|
124
|
+
$ transpec -m
|
125
125
|
Copying project for dynamic analysis...
|
126
126
|
Running dynamic analysis with command "bundle exec rspec"...
|
127
127
|
...............................................................................
|
@@ -214,12 +214,12 @@ $ transpec --keep should_receive,stub
|
|
214
214
|
#### Available syntax types
|
215
215
|
|
216
216
|
Type | Target Syntax | Converted Syntax
|
217
|
-
|
217
|
+
-----------------|----------------------------------|-----------------------------------
|
218
218
|
`should` | `obj.should matcher` | `expect(obj).to matcher`
|
219
219
|
`should_receive` | `obj.should_receive` | `expect(obj).to receive`
|
220
220
|
`stub` | `obj.stub` | `allow(obj).to receive`
|
221
221
|
`have_items` | `expect(obj).to have(x).items` | `expect(obj.size).to eq(x)`
|
222
|
-
`its` | `its(:attr) { }` | `describe { subject { } it { } }`
|
222
|
+
`its` | `its(:attr) { }` | `describe { subject { }; it { } }`
|
223
223
|
`deprecated` | `obj.stub!`, `mock('foo')`, etc. | `obj.stub`, `double('foo')`
|
224
224
|
|
225
225
|
See [Supported Conversions](#supported-conversions) for more details.
|
@@ -409,6 +409,8 @@ expect(obj).to be false
|
|
409
409
|
|
410
410
|
So, converting `be_true`/`be_false` to `be_truthy`/`be_falsey` never breaks your specs and this is the Transpec's default. If you are willing to test boolean values strictly, you can convert them to `be true`/`be false` with `--boolean-matcher true,false` option. Note that this may break your specs if your library codes don't return exact boolean values.
|
411
411
|
|
412
|
+
---
|
413
|
+
|
412
414
|
* Conversion can be disabled by: `--keep deprecated`
|
413
415
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
414
416
|
* See also: [Consider renaming `be_true` and `be_false` to `be_truthy` and `be_falsey` · rspec/rspec-expectations](https://github.com/rspec/rspec-expectations/issues/283)
|
@@ -429,6 +431,8 @@ expect(1.0 / 3.0).to be_within(0.001).of(0.333)
|
|
429
431
|
|
430
432
|
### `have(n).items` matcher
|
431
433
|
|
434
|
+
**This conversion will be disabled automatically if `rspec-collection_matchers` or `rspec-rails` is loaded in your spec.**
|
435
|
+
|
432
436
|
```ruby
|
433
437
|
# Targets
|
434
438
|
expect(collection).to have(3).items
|
@@ -455,8 +459,15 @@ expect(team.players.size).to eq(3)
|
|
455
459
|
expect(team.send(:players).size).to eq(3)
|
456
460
|
```
|
457
461
|
|
458
|
-
There's
|
459
|
-
If you choose so, disable this conversion
|
462
|
+
There's an option to continue using `have(n).items` matcher with [rspec-collection_matchers](https://github.com/rspec/rspec-collection_matchers) that is an external gem extracted from `rspec-expectations`.
|
463
|
+
If you choose so, disable this conversion by either:
|
464
|
+
|
465
|
+
* Specify `--keep have_items` option manually.
|
466
|
+
* Require `rspec-collection_matchers` or `rspec-rails` in your spec so that Transpec automatically disables this conversion.
|
467
|
+
|
468
|
+
Note: `rspec-rails` 3.0 [still uses `have(n).items` matcher with `rspec-collection_matchers`](https://github.com/rspec/rspec-rails/blob/v3.0.0.beta1/rspec-rails.gemspec#L41).
|
469
|
+
|
470
|
+
---
|
460
471
|
|
461
472
|
* Conversion can be disabled by: `--keep have_items`
|
462
473
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
@@ -501,11 +512,11 @@ lambda { do_something }.should_not raise_error # with `--keep should`
|
|
501
512
|
```ruby
|
502
513
|
# Targets
|
503
514
|
obj.should_receive(:foo)
|
504
|
-
|
515
|
+
Klass.any_instance.should_receive(:foo)
|
505
516
|
|
506
517
|
# Converted
|
507
518
|
expect(obj).to receive(:foo)
|
508
|
-
expect_any_instance_of(
|
519
|
+
expect_any_instance_of(Klass).to receive(:foo)
|
509
520
|
```
|
510
521
|
|
511
522
|
* Conversion can be disabled by: `--keep should_receive`
|
@@ -519,15 +530,15 @@ expect_any_instance_of(SomeClass).to receive(:foo)
|
|
519
530
|
obj.should_receive(:foo).any_number_of_times
|
520
531
|
obj.should_receive(:foo).at_least(0)
|
521
532
|
|
522
|
-
|
523
|
-
|
533
|
+
Klass.any_instance.should_receive(:foo).any_number_of_times
|
534
|
+
Klass.any_instance.should_receive(:foo).at_least(0)
|
524
535
|
|
525
536
|
# Converted
|
526
537
|
allow(obj).to receive(:foo)
|
527
538
|
obj.stub(:foo) # with `--keep stub`
|
528
539
|
|
529
|
-
allow_any_instance_of(
|
530
|
-
|
540
|
+
allow_any_instance_of(Klass).to receive(:foo)
|
541
|
+
Klass.any_instance.stub(:foo) # with `--keep stub`
|
531
542
|
```
|
532
543
|
|
533
544
|
* Conversion can be disabled by: `--keep deprecated`
|
@@ -544,7 +555,7 @@ obj.stub!(:foo)
|
|
544
555
|
|
545
556
|
obj.stub(:foo => 1, :bar => 2)
|
546
557
|
|
547
|
-
|
558
|
+
Klass.any_instance.stub(:foo)
|
548
559
|
|
549
560
|
# Converted
|
550
561
|
allow(obj).to receive(:foo)
|
@@ -558,7 +569,7 @@ allow(obj).to receive(:bar).and_return(2)
|
|
558
569
|
# If the target project's rspec gem dependency is 3.0 or later
|
559
570
|
allow(obj).to receive_messages(:foo => 1, :bar => 2)
|
560
571
|
|
561
|
-
allow_any_instance_of(
|
572
|
+
allow_any_instance_of(Klass).to receive(:foo)
|
562
573
|
```
|
563
574
|
|
564
575
|
Note: `allow(obj).to receive_messages(:foo => 1, :bar => 2)` that is designed to be the replacement for `obj.stub(:foo => 1, :bar => 2)` is available from RSpec 3.0 (though [it's now being considered to be backported to RSpec 2.99](https://github.com/rspec/rspec-mocks/issues/454)). So, in [the upgrade path to RSpec 3](http://myronmars.to/n/dev-blog/2013/07/the-plan-for-rspec-3#the_upgrade_path), if you want to convert them with keeping the syntax correspondence, you need to follow these steps:
|
@@ -570,6 +581,8 @@ Note: `allow(obj).to receive_messages(:foo => 1, :bar => 2)` that is designed to
|
|
570
581
|
|
571
582
|
Otherwise `obj.stub(:foo => 1, :bar => 2)` will be converted to two `allow(obj).to receive(...).and_return(...)` expressions on RSpec 2.99.
|
572
583
|
|
584
|
+
---
|
585
|
+
|
573
586
|
* Conversion can be disabled by: `--keep stub`
|
574
587
|
* Deprecation: Deprecated since RSpec 3.0
|
575
588
|
* See also:
|
@@ -625,6 +638,8 @@ double('something')
|
|
625
638
|
|
626
639
|
### Expectations on attribute of subject with `its`
|
627
640
|
|
641
|
+
**This conversion will be disabled automatically if `rspec-its` is loaded in your spec.**
|
642
|
+
|
628
643
|
```ruby
|
629
644
|
# Targets
|
630
645
|
describe 'example' do
|
@@ -658,8 +673,13 @@ describe 'example' do
|
|
658
673
|
end
|
659
674
|
```
|
660
675
|
|
661
|
-
There's
|
662
|
-
If you choose so, disable this conversion
|
676
|
+
There's an option to continue using `its` with [rspec-its](https://github.com/rspec/rspec-its) that is an external gem extracted from `rspec-core`.
|
677
|
+
If you choose so, disable this conversion by either:
|
678
|
+
|
679
|
+
* Specify `--keep its` option manually.
|
680
|
+
* Require `rspec-its` in your spec so that Transpec automatically disables this conversion.
|
681
|
+
|
682
|
+
---
|
663
683
|
|
664
684
|
* Conversion can be disabled by: `--keep its`
|
665
685
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
data/README.md.erb
CHANGED
@@ -90,11 +90,11 @@ Before converting your specs:
|
|
90
90
|
* Run `rspec` and check if all the specs pass.
|
91
91
|
* Ensure the Git repository is clean. (You don't want to mix up your changes and Transpec's changes, right?)
|
92
92
|
|
93
|
-
Then, run `transpec` (using
|
93
|
+
Then, run `transpec` (using `-m/--generate-commit-message` is recommended) in the project root directory:
|
94
94
|
|
95
95
|
```bash
|
96
96
|
$ cd some-project
|
97
|
-
$ transpec
|
97
|
+
$ transpec -m
|
98
98
|
Copying project for dynamic analysis...
|
99
99
|
Running dynamic analysis with command "bundle exec rspec"...
|
100
100
|
...............................................................................
|
@@ -187,14 +187,14 @@ $ transpec --keep should_receive,stub
|
|
187
187
|
#### Available syntax types
|
188
188
|
|
189
189
|
Type | Target Syntax | Converted Syntax
|
190
|
-
|
190
|
+
-----------------|----------------------------------|-----------------------------------
|
191
191
|
<%=
|
192
192
|
conversion_type_table = <<END
|
193
193
|
`should` | `obj.should matcher` | `expect(obj).to matcher`
|
194
194
|
`should_receive` | `obj.should_receive` | `expect(obj).to receive`
|
195
195
|
`stub` | `obj.stub` | `allow(obj).to receive`
|
196
196
|
`have_items` | `expect(obj).to have(x).items` | `expect(obj.size).to eq(x)`
|
197
|
-
`its` | `its(:attr) { }` | `describe { subject { } it { } }`
|
197
|
+
`its` | `its(:attr) { }` | `describe { subject { }; it { } }`
|
198
198
|
`deprecated` | `obj.stub!`, `mock('foo')`, etc. | `obj.stub`, `double('foo')`
|
199
199
|
END
|
200
200
|
|
@@ -405,6 +405,8 @@ expect(obj).to be false
|
|
405
405
|
|
406
406
|
So, converting `be_true`/`be_false` to `be_truthy`/`be_falsey` never breaks your specs and this is the Transpec's default. If you are willing to test boolean values strictly, you can convert them to `be true`/`be false` with `--boolean-matcher true,false` option. Note that this may break your specs if your library codes don't return exact boolean values.
|
407
407
|
|
408
|
+
---
|
409
|
+
|
408
410
|
* Conversion can be disabled by: `--keep deprecated`
|
409
411
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
410
412
|
* See also: [Consider renaming `be_true` and `be_false` to `be_truthy` and `be_falsey` · rspec/rspec-expectations](https://github.com/rspec/rspec-expectations/issues/283)
|
@@ -425,6 +427,8 @@ expect(1.0 / 3.0).to be_within(0.001).of(0.333)
|
|
425
427
|
|
426
428
|
### `have(n).items` matcher
|
427
429
|
|
430
|
+
**This conversion will be disabled automatically if `rspec-collection_matchers` or `rspec-rails` is loaded in your spec.**
|
431
|
+
|
428
432
|
```ruby
|
429
433
|
# Targets
|
430
434
|
expect(collection).to have(3).items
|
@@ -451,8 +455,15 @@ expect(team.players.size).to eq(3)
|
|
451
455
|
expect(team.send(:players).size).to eq(3)
|
452
456
|
```
|
453
457
|
|
454
|
-
There's
|
455
|
-
If you choose so, disable this conversion
|
458
|
+
There's an option to continue using `have(n).items` matcher with [rspec-collection_matchers](https://github.com/rspec/rspec-collection_matchers) that is an external gem extracted from `rspec-expectations`.
|
459
|
+
If you choose so, disable this conversion by either:
|
460
|
+
|
461
|
+
* Specify `--keep have_items` option manually.
|
462
|
+
* Require `rspec-collection_matchers` or `rspec-rails` in your spec so that Transpec automatically disables this conversion.
|
463
|
+
|
464
|
+
Note: `rspec-rails` 3.0 [still uses `have(n).items` matcher with `rspec-collection_matchers`](https://github.com/rspec/rspec-rails/blob/v3.0.0.beta1/rspec-rails.gemspec#L41).
|
465
|
+
|
466
|
+
---
|
456
467
|
|
457
468
|
* Conversion can be disabled by: `--keep have_items`
|
458
469
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
@@ -497,11 +508,11 @@ lambda { do_something }.should_not raise_error # with `--keep should`
|
|
497
508
|
```ruby
|
498
509
|
# Targets
|
499
510
|
obj.should_receive(:foo)
|
500
|
-
|
511
|
+
Klass.any_instance.should_receive(:foo)
|
501
512
|
|
502
513
|
# Converted
|
503
514
|
expect(obj).to receive(:foo)
|
504
|
-
expect_any_instance_of(
|
515
|
+
expect_any_instance_of(Klass).to receive(:foo)
|
505
516
|
```
|
506
517
|
|
507
518
|
* Conversion can be disabled by: `--keep should_receive`
|
@@ -515,15 +526,15 @@ expect_any_instance_of(SomeClass).to receive(:foo)
|
|
515
526
|
obj.should_receive(:foo).any_number_of_times
|
516
527
|
obj.should_receive(:foo).at_least(0)
|
517
528
|
|
518
|
-
|
519
|
-
|
529
|
+
Klass.any_instance.should_receive(:foo).any_number_of_times
|
530
|
+
Klass.any_instance.should_receive(:foo).at_least(0)
|
520
531
|
|
521
532
|
# Converted
|
522
533
|
allow(obj).to receive(:foo)
|
523
534
|
obj.stub(:foo) # with `--keep stub`
|
524
535
|
|
525
|
-
allow_any_instance_of(
|
526
|
-
|
536
|
+
allow_any_instance_of(Klass).to receive(:foo)
|
537
|
+
Klass.any_instance.stub(:foo) # with `--keep stub`
|
527
538
|
```
|
528
539
|
|
529
540
|
* Conversion can be disabled by: `--keep deprecated`
|
@@ -540,7 +551,7 @@ obj.stub!(:foo)
|
|
540
551
|
|
541
552
|
obj.stub(:foo => 1, :bar => 2)
|
542
553
|
|
543
|
-
|
554
|
+
Klass.any_instance.stub(:foo)
|
544
555
|
|
545
556
|
# Converted
|
546
557
|
allow(obj).to receive(:foo)
|
@@ -554,7 +565,7 @@ allow(obj).to receive(:bar).and_return(2)
|
|
554
565
|
# If the target project's rspec gem dependency is 3.0 or later
|
555
566
|
allow(obj).to receive_messages(:foo => 1, :bar => 2)
|
556
567
|
|
557
|
-
allow_any_instance_of(
|
568
|
+
allow_any_instance_of(Klass).to receive(:foo)
|
558
569
|
```
|
559
570
|
|
560
571
|
Note: `allow(obj).to receive_messages(:foo => 1, :bar => 2)` that is designed to be the replacement for `obj.stub(:foo => 1, :bar => 2)` is available from RSpec 3.0 (though [it's now being considered to be backported to RSpec 2.99](https://github.com/rspec/rspec-mocks/issues/454)). So, in [the upgrade path to RSpec 3](http://myronmars.to/n/dev-blog/2013/07/the-plan-for-rspec-3#the_upgrade_path), if you want to convert them with keeping the syntax correspondence, you need to follow these steps:
|
@@ -566,6 +577,8 @@ Note: `allow(obj).to receive_messages(:foo => 1, :bar => 2)` that is designed to
|
|
566
577
|
|
567
578
|
Otherwise `obj.stub(:foo => 1, :bar => 2)` will be converted to two `allow(obj).to receive(...).and_return(...)` expressions on RSpec 2.99.
|
568
579
|
|
580
|
+
---
|
581
|
+
|
569
582
|
* Conversion can be disabled by: `--keep stub`
|
570
583
|
* Deprecation: Deprecated since RSpec 3.0
|
571
584
|
* See also:
|
@@ -621,6 +634,8 @@ double('something')
|
|
621
634
|
|
622
635
|
### Expectations on attribute of subject with `its`
|
623
636
|
|
637
|
+
**This conversion will be disabled automatically if `rspec-its` is loaded in your spec.**
|
638
|
+
|
624
639
|
```ruby
|
625
640
|
# Targets
|
626
641
|
<%=
|
@@ -638,8 +653,13 @@ END
|
|
638
653
|
<%= Transpec::Converter.new.convert(its_target) -%>
|
639
654
|
```
|
640
655
|
|
641
|
-
There's
|
642
|
-
If you choose so, disable this conversion
|
656
|
+
There's an option to continue using `its` with [rspec-its](https://github.com/rspec/rspec-its) that is an external gem extracted from `rspec-core`.
|
657
|
+
If you choose so, disable this conversion by either:
|
658
|
+
|
659
|
+
* Specify `--keep its` option manually.
|
660
|
+
* Require `rspec-its` in your spec so that Transpec automatically disables this conversion.
|
661
|
+
|
662
|
+
---
|
643
663
|
|
644
664
|
* Conversion can be disabled by: `--keep its`
|
645
665
|
* Deprecation: Deprecated since RSpec 2.99, removed at RSpec 3.0
|
@@ -143,7 +143,7 @@ module Transpec
|
|
143
143
|
" #{'should_receive'.bright} (to #{'expect(obj).to receive'.underline})",
|
144
144
|
" #{'stub'.bright} (to #{'allow(obj).to receive'.underline})",
|
145
145
|
" #{'have_items'.bright} (to #{'expect(obj.size).to eq(x)'.underline})",
|
146
|
-
" #{'its'.bright} (to #{'describe { subject { } it { } }'.underline})",
|
146
|
+
" #{'its'.bright} (to #{'describe { subject { }; it { } }'.underline})",
|
147
147
|
" #{'deprecated'.bright} (e.g. from #{'mock'.underline} to #{'double'.underline})",
|
148
148
|
'These are all converted by default.'
|
149
149
|
],
|
data/lib/transpec/syntax/have.rb
CHANGED
@@ -39,30 +39,11 @@ module Transpec
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def register_request_for_dynamic_analysis(rewriter)
|
42
|
-
|
43
|
-
|
44
|
-
# `expect(owner).to have(n).things` invokes private owner#things with Object#__send__
|
45
|
-
# if the owner does not respond to any of #size, #count and #length.
|
46
|
-
#
|
47
|
-
# rubocop:disable LineLength
|
48
|
-
# https://github.com/rspec/rspec-expectations/blob/v2.14.3/lib/rspec/matchers/built_in/have.rb#L48-L58
|
49
|
-
# rubocop:enable LineLength
|
50
|
-
key = :subject_is_owner_of_collection?
|
51
|
-
code = "respond_to?(#{items_name.inspect}) || " +
|
52
|
-
"(methods & #{QUERY_METHOD_PRIORITIES.inspect}).empty?"
|
53
|
-
rewriter.register_request(node, key, code)
|
54
|
-
|
55
|
-
key = :available_query_methods
|
56
|
-
code = "target = #{code} ? #{items_name} : self; " +
|
57
|
-
"target.methods & #{QUERY_METHOD_PRIORITIES.inspect}"
|
58
|
-
rewriter.register_request(node, key, code)
|
59
|
-
|
60
|
-
key = :collection_accessor_is_private?
|
61
|
-
code = "private_methods.include?(#{items_name.inspect})"
|
62
|
-
rewriter.register_request(node, key, code)
|
42
|
+
DynamicInspector.register_request(self, rewriter)
|
63
43
|
end
|
64
44
|
|
65
45
|
def convert_to_standard_expectation!(parenthesize_matcher_arg = true)
|
46
|
+
return if project_requires_collection_matcher?
|
66
47
|
replace(@expectation.subject_range, replacement_subject_source)
|
67
48
|
replace(expression_range, replacement_matcher_source(size_source, parenthesize_matcher_arg))
|
68
49
|
register_record
|
@@ -78,6 +59,10 @@ module Transpec
|
|
78
59
|
|
79
60
|
alias_method :items_node, :node
|
80
61
|
|
62
|
+
def items_method_has_arguments?
|
63
|
+
items_node.children.size > 2
|
64
|
+
end
|
65
|
+
|
81
66
|
def have_method_name
|
82
67
|
have_node.children[1]
|
83
68
|
end
|
@@ -86,21 +71,31 @@ module Transpec
|
|
86
71
|
items_node.children[1]
|
87
72
|
end
|
88
73
|
|
74
|
+
def project_requires_collection_matcher?
|
75
|
+
runtime_subject_data && runtime_subject_data[:project_requires_collection_matcher?].result
|
76
|
+
end
|
77
|
+
|
78
|
+
def collection_accessor
|
79
|
+
if runtime_subject_data && runtime_subject_data[:collection_accessor].result
|
80
|
+
runtime_subject_data[:collection_accessor].result.to_sym
|
81
|
+
else
|
82
|
+
items_name
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
89
86
|
def subject_is_owner_of_collection?
|
90
|
-
|
91
|
-
|
87
|
+
return true if items_method_has_arguments?
|
88
|
+
runtime_subject_data && !runtime_subject_data[:collection_accessor].result.nil?
|
92
89
|
end
|
93
90
|
|
94
91
|
def collection_accessor_is_private?
|
95
|
-
|
96
|
-
node_data && node_data[:collection_accessor_is_private?].result
|
92
|
+
runtime_subject_data && runtime_subject_data[:collection_accessor_is_private?].result
|
97
93
|
end
|
98
94
|
|
99
95
|
def query_method
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
(QUERY_METHOD_PRIORITIES & available_query_methods).first
|
96
|
+
if runtime_subject_data && runtime_subject_data[:available_query_methods]
|
97
|
+
available_query_methods = runtime_subject_data[:available_query_methods].result
|
98
|
+
(QUERY_METHOD_PRIORITIES & available_query_methods.map(&:to_sym)).first
|
104
99
|
else
|
105
100
|
default_query_method
|
106
101
|
end
|
@@ -121,13 +116,20 @@ module Transpec
|
|
121
116
|
|
122
117
|
private
|
123
118
|
|
119
|
+
def runtime_subject_data
|
120
|
+
return @runtime_subject_data if instance_variable_defined?(:@runtime_subject_data)
|
121
|
+
@runtime_subject_data = runtime_node_data(@expectation.subject_node)
|
122
|
+
end
|
123
|
+
|
124
124
|
def replacement_subject_source
|
125
125
|
source = @expectation.subject_range.source
|
126
126
|
if subject_is_owner_of_collection?
|
127
127
|
if collection_accessor_is_private?
|
128
|
-
source << ".send(#{
|
128
|
+
source << ".send(#{collection_accessor.inspect}"
|
129
|
+
source << ", #{args_range.source}" if items_method_has_arguments?
|
130
|
+
source << ')'
|
129
131
|
else
|
130
|
-
source << ".#{
|
132
|
+
source << ".#{collection_accessor}#{parentheses_range.source}"
|
131
133
|
end
|
132
134
|
end
|
133
135
|
source << ".#{query_method}"
|
@@ -160,15 +162,91 @@ module Transpec
|
|
160
162
|
size_node.loc.expression.source
|
161
163
|
end
|
162
164
|
|
163
|
-
def dot_items_range
|
164
|
-
map = items_node.loc
|
165
|
-
map.dot.join(map.selector)
|
166
|
-
end
|
167
|
-
|
168
165
|
def register_record
|
169
166
|
@report.records << HaveRecord.new(self)
|
170
167
|
end
|
171
168
|
|
169
|
+
class DynamicInspector
|
170
|
+
def self.register_request(have, rewriter)
|
171
|
+
new(have, rewriter).register_request
|
172
|
+
end
|
173
|
+
|
174
|
+
def initialize(have, rewriter)
|
175
|
+
@have = have
|
176
|
+
@rewriter = rewriter
|
177
|
+
end
|
178
|
+
|
179
|
+
def target_node
|
180
|
+
@have.expectation.subject_node
|
181
|
+
end
|
182
|
+
|
183
|
+
def register_request
|
184
|
+
key = :collection_accessor
|
185
|
+
code = collection_accessor_inspection_code
|
186
|
+
@rewriter.register_request(target_node, key, code)
|
187
|
+
|
188
|
+
# Give up inspecting query methods of collection accessor with arguments
|
189
|
+
# (e.g. have(2).errors_on(variable)) since this is a context of #instance_eval.
|
190
|
+
unless @have.items_method_has_arguments?
|
191
|
+
key = :available_query_methods
|
192
|
+
code = "collection_accessor = #{code}; " +
|
193
|
+
'target = collection_accessor ? __send__(collection_accessor) : self; ' +
|
194
|
+
"target.methods & #{QUERY_METHOD_PRIORITIES.inspect}"
|
195
|
+
@rewriter.register_request(target_node, key, code)
|
196
|
+
end
|
197
|
+
|
198
|
+
key = :collection_accessor_is_private?
|
199
|
+
code = "private_methods.include?(#{@have.items_name.inspect})"
|
200
|
+
@rewriter.register_request(target_node, key, code)
|
201
|
+
|
202
|
+
key = :project_requires_collection_matcher?
|
203
|
+
code = 'defined?(RSpec::Rails) || defined?(RSpec::CollectionMatchers)'
|
204
|
+
@rewriter.register_request(target_node, key, code, :context)
|
205
|
+
end
|
206
|
+
|
207
|
+
# rubocop:disable MethodLength
|
208
|
+
def collection_accessor_inspection_code
|
209
|
+
# `expect(owner).to have(n).things` invokes private owner#things with Object#__send__
|
210
|
+
# if the owner does not respond to any of #size, #count and #length.
|
211
|
+
#
|
212
|
+
# rubocop:disable LineLength
|
213
|
+
# https://github.com/rspec/rspec-expectations/blob/v2.14.3/lib/rspec/matchers/built_in/have.rb#L48-L58
|
214
|
+
# rubocop:enable LineLength
|
215
|
+
<<-END.gsub(/^\s+\|/, '').chomp
|
216
|
+
|begin
|
217
|
+
| exact_name = #{@have.items_name.inspect}
|
218
|
+
|
|
219
|
+
| inflector = if defined?(ActiveSupport::Inflector) &&
|
220
|
+
| ActiveSupport::Inflector.respond_to?(:pluralize)
|
221
|
+
| ActiveSupport::Inflector
|
222
|
+
| elsif defined?(Inflector)
|
223
|
+
| Inflector
|
224
|
+
| else
|
225
|
+
| nil
|
226
|
+
| end
|
227
|
+
|
|
228
|
+
| if inflector
|
229
|
+
| pluralized_name = inflector.pluralize(exact_name).to_sym
|
230
|
+
| respond_to_pluralized_name = respond_to?(pluralized_name)
|
231
|
+
| end
|
232
|
+
|
|
233
|
+
| respond_to_query_methods = !(methods & #{QUERY_METHOD_PRIORITIES.inspect}).empty?
|
234
|
+
|
|
235
|
+
| if respond_to?(exact_name)
|
236
|
+
| exact_name
|
237
|
+
| elsif respond_to_pluralized_name
|
238
|
+
| pluralized_name
|
239
|
+
| elsif respond_to_query_methods
|
240
|
+
| nil
|
241
|
+
| else
|
242
|
+
| exact_name
|
243
|
+
| end
|
244
|
+
|end
|
245
|
+
END
|
246
|
+
end
|
247
|
+
# rubocop:enable MethodLength
|
248
|
+
end
|
249
|
+
|
172
250
|
class HaveRecord < Record
|
173
251
|
def initialize(have)
|
174
252
|
@have = have
|
@@ -210,7 +288,11 @@ module Transpec
|
|
210
288
|
|
211
289
|
def original_items
|
212
290
|
if @have.subject_is_owner_of_collection?
|
213
|
-
@have.
|
291
|
+
if @have.items_method_has_arguments?
|
292
|
+
"#{@have.collection_accessor}(...)"
|
293
|
+
else
|
294
|
+
@have.collection_accessor
|
295
|
+
end
|
214
296
|
else
|
215
297
|
'items'
|
216
298
|
end
|
@@ -218,11 +300,16 @@ module Transpec
|
|
218
300
|
|
219
301
|
def converted_subject
|
220
302
|
if @have.subject_is_owner_of_collection?
|
303
|
+
subject = 'obj.'
|
221
304
|
if @have.collection_accessor_is_private?
|
222
|
-
"
|
305
|
+
subject << "send(#{@have.collection_accessor.inspect}"
|
306
|
+
subject << ', ...' if @have.items_method_has_arguments?
|
307
|
+
subject << ')'
|
223
308
|
else
|
224
|
-
"
|
309
|
+
subject << "#{@have.collection_accessor}"
|
310
|
+
subject << '(...)' if @have.items_method_has_arguments?
|
225
311
|
end
|
312
|
+
subject << ".#{@have.query_method}"
|
226
313
|
else
|
227
314
|
"collection.#{@have.default_query_method}"
|
228
315
|
end
|
data/lib/transpec/syntax/its.rb
CHANGED
@@ -13,7 +13,15 @@ module Transpec
|
|
13
13
|
receiver_node.nil? && method_name == :its
|
14
14
|
end
|
15
15
|
|
16
|
+
def register_request_for_dynamic_analysis(rewriter)
|
17
|
+
key = :project_requires_its?
|
18
|
+
code = 'defined?(RSpec::Its)'
|
19
|
+
rewriter.register_request(@node, key, code, :context)
|
20
|
+
end
|
21
|
+
|
16
22
|
def convert_to_describe_subject_it!
|
23
|
+
return if project_requires_its?
|
24
|
+
|
17
25
|
front, rear = build_wrapper_codes
|
18
26
|
|
19
27
|
insert_before(beginning_of_line_range, front)
|
@@ -37,6 +45,11 @@ module Transpec
|
|
37
45
|
@node.parent_node
|
38
46
|
end
|
39
47
|
|
48
|
+
def project_requires_its?
|
49
|
+
node_data = runtime_node_data(@node)
|
50
|
+
node_data && node_data[:project_requires_its?].result
|
51
|
+
end
|
52
|
+
|
40
53
|
private
|
41
54
|
|
42
55
|
def build_wrapper_codes
|
@@ -99,9 +112,9 @@ module Transpec
|
|
99
112
|
|
100
113
|
def converted_syntax
|
101
114
|
if attribute_expression.brackets?
|
102
|
-
"describe '[:key]' do subject { super()[:key] } it { } end"
|
115
|
+
"describe '[:key]' do subject { super()[:key] }; it { } end"
|
103
116
|
else
|
104
|
-
"describe 'attr' do subject { super().attr } it { } end"
|
117
|
+
"describe 'attr' do subject { super().attr }; it { } end"
|
105
118
|
end
|
106
119
|
end
|
107
120
|
|
@@ -23,6 +23,7 @@ module Transpec
|
|
23
23
|
:allow_to_receive_available?,
|
24
24
|
[:allow, :receive]
|
25
25
|
)
|
26
|
+
register_request_of_any_instance_inspection(rewriter)
|
26
27
|
end
|
27
28
|
|
28
29
|
def allow_to_receive_available?
|
@@ -101,8 +102,7 @@ module Transpec
|
|
101
102
|
|
102
103
|
def allow_source
|
103
104
|
if any_instance?
|
104
|
-
|
105
|
-
"allow_any_instance_of(#{class_source})"
|
105
|
+
"allow_any_instance_of(#{any_instance_target_class_source})"
|
106
106
|
else
|
107
107
|
"allow(#{subject_range.source})"
|
108
108
|
end
|
@@ -127,7 +127,7 @@ module Transpec
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def original_syntax
|
130
|
-
syntax = any_instance? ? '
|
130
|
+
syntax = any_instance? ? 'Klass.any_instance' : 'obj'
|
131
131
|
syntax << ".#{method_name}"
|
132
132
|
syntax << (arg_node.type == :hash ? '(:message => value)' : '(:message)')
|
133
133
|
end
|
@@ -135,7 +135,7 @@ module Transpec
|
|
135
135
|
def converted_syntax(conversion_type)
|
136
136
|
case conversion_type
|
137
137
|
when :allow_to_receive, :allow_to_receive_messages
|
138
|
-
syntax = any_instance? ? 'allow_any_instance_of(
|
138
|
+
syntax = any_instance? ? 'allow_any_instance_of(Klass)' : 'allow(obj)'
|
139
139
|
syntax << '.to '
|
140
140
|
if conversion_type == :allow_to_receive
|
141
141
|
syntax << 'receive(:message)'
|