transpec 1.8.0 → 1.9.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.
@@ -49,7 +49,7 @@ module Transpec
49
49
  unless @configuration.skip_dynamic_analysis?
50
50
  puts 'Copying the project for dynamic analysis...'
51
51
  DynamicAnalyzer.new(rspec_command: @configuration.rspec_command) do |analyzer|
52
- puts "Running dynamic analysis with command \"#{analyzer.rspec_command}\"..."
52
+ puts "Running dynamic analysis with command #{analyzer.rspec_command.inspect}..."
53
53
  runtime_data = analyzer.analyze(paths)
54
54
  end
55
55
  puts
@@ -80,11 +80,11 @@ module Transpec
80
80
 
81
81
  def process_expect(expect)
82
82
  process_have(expect.have_matcher)
83
- process_any_instance_block(expect.receive_matcher)
83
+ process_messaging_host(expect.receive_matcher)
84
84
  end
85
85
 
86
86
  def process_allow(allow)
87
- process_any_instance_block(allow.receive_matcher)
87
+ process_messaging_host(allow.receive_matcher)
88
88
  end
89
89
 
90
90
  def process_should_receive(should_receive)
@@ -102,7 +102,7 @@ module Transpec
102
102
  should_receive.expectize!(@configuration.negative_form_of_to)
103
103
  end
104
104
 
105
- process_any_instance_block(should_receive)
105
+ process_messaging_host(should_receive)
106
106
  end
107
107
 
108
108
  def process_double(double)
@@ -122,9 +122,9 @@ module Transpec
122
122
  method_stub.convert_deprecated_method!
123
123
  end
124
124
 
125
- method_stub.remove_allowance_for_no_message! if @configuration.convert_deprecated_method?
125
+ method_stub.remove_no_message_allowance! if @configuration.convert_deprecated_method?
126
126
 
127
- process_any_instance_block(method_stub)
127
+ process_messaging_host(method_stub)
128
128
  end
129
129
 
130
130
  def process_be_boolean(be_boolean)
@@ -184,6 +184,17 @@ module Transpec
184
184
  have.convert_to_standard_expectation!(@configuration.parenthesize_matcher_arg)
185
185
  end
186
186
 
187
+ def process_messaging_host(messaging_host)
188
+ process_useless_and_return(messaging_host)
189
+ process_any_instance_block(messaging_host)
190
+ end
191
+
192
+ def process_useless_and_return(messaging_host)
193
+ return unless messaging_host
194
+ return unless configuration.convert_deprecated_method?
195
+ messaging_host.remove_useless_and_return!
196
+ end
197
+
187
198
  def process_any_instance_block(messaging_host)
188
199
  return unless messaging_host
189
200
  return unless rspec_version.migration_term_of_any_instance_implementation_block?
@@ -12,6 +12,10 @@ module Transpec
12
12
  receiver_node.nil? && [:allow, :allow_any_instance_of].include?(method_name)
13
13
  end
14
14
 
15
+ def method_name_for_instance
16
+ :allow
17
+ end
18
+
15
19
  def any_instance?
16
20
  method_name == :allow_any_instance_of
17
21
  end
@@ -13,6 +13,10 @@ module Transpec
13
13
  receiver_node.nil? && [:expect, :expect_any_instance_of].include?(method_name)
14
14
  end
15
15
 
16
+ def method_name_for_instance
17
+ :expect
18
+ end
19
+
16
20
  def any_instance?
17
21
  method_name == :expect_any_instance_of
18
22
  end
@@ -20,11 +20,9 @@ module Transpec
20
20
 
21
21
  attr_reader :expectation
22
22
 
23
- def self.target_method?(have_node, items_method_name)
24
- return false unless have_node
25
- have_receiver_node, have_method_name, *_ = *have_node
26
- return false if have_receiver_node
27
- [:have, :have_exactly, :have_at_least, :have_at_most].include?(have_method_name)
23
+ def self.target_method?(receiver_node, method_name)
24
+ receiver_node.nil? &&
25
+ [:have, :have_exactly, :have_at_least, :have_at_most].include?(method_name)
28
26
  end
29
27
 
30
28
  add_dynamic_analysis_request do |rewriter|
@@ -34,7 +32,7 @@ module Transpec
34
32
  def convert_to_standard_expectation!(parenthesize_matcher_arg = true)
35
33
  return if project_requires_collection_matcher?
36
34
  replace(@expectation.subject_range, replacement_subject_source) if explicit_subject?
37
- replace(expression_range, replacement_matcher_source(parenthesize_matcher_arg))
35
+ replace(matcher_range, replacement_matcher_source(parenthesize_matcher_arg))
38
36
  register_record if explicit_subject?
39
37
  end
40
38
 
@@ -42,16 +40,13 @@ module Transpec
42
40
  @expectation.respond_to?(:subject_node)
43
41
  end
44
42
 
45
- def have_node # rubocop:disable PredicateName
46
- node.children.first
47
- end
43
+ alias_method :have_node, :node
44
+ alias_method :items_node, :parent_node
48
45
 
49
46
  def size_node
50
47
  have_node.children[2]
51
48
  end
52
49
 
53
- alias_method :items_node, :node
54
-
55
50
  def items_method_has_arguments?
56
51
  items_node.children.size > 2
57
52
  end
@@ -107,10 +102,10 @@ module Transpec
107
102
  if subject_is_owner_of_collection?
108
103
  if collection_accessor_is_private?
109
104
  source << ".send(#{collection_accessor.inspect}"
110
- source << ", #{args_range.source}" if items_method_has_arguments?
105
+ source << ", #{collection_accessor_args_body_source}" if items_method_has_arguments?
111
106
  source << ')'
112
107
  else
113
- source << ".#{collection_accessor}#{parentheses_range.source}"
108
+ source << ".#{collection_accessor}#{collection_accessor_args_parentheses_source}"
114
109
  end
115
110
  end
116
111
  source << ".#{query_method}"
@@ -164,6 +159,22 @@ module Transpec
164
159
  end
165
160
  end
166
161
 
162
+ def matcher_range
163
+ expression_range.join(items_node.loc.expression)
164
+ end
165
+
166
+ def collection_accessor_args_parentheses_source
167
+ map = items_node.loc
168
+ range = map.selector.end.join(map.expression.end)
169
+ range.source
170
+ end
171
+
172
+ def collection_accessor_args_body_source
173
+ arg_nodes = items_node.children[2..-1]
174
+ range = arg_nodes.first.loc.expression.begin.join(arg_nodes.last.loc.expression.end)
175
+ range.source
176
+ end
177
+
167
178
  def register_record
168
179
  @report.records << HaveRecord.new(self)
169
180
  end
@@ -2,15 +2,14 @@
2
2
 
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/syntax/mixin/monkey_patch_any_instance'
5
- require 'transpec/syntax/mixin/any_instance_block'
6
- require 'transpec/syntax/mixin/allow_no_message'
5
+ require 'transpec/syntax/mixin/messaging_host'
7
6
  require 'transpec/util'
8
7
  require 'English'
9
8
 
10
9
  module Transpec
11
10
  class Syntax
12
11
  class MethodStub < Syntax
13
- include Mixin::MonkeyPatchAnyInstance, Mixin::AnyInstanceBlock, Mixin::AllowNoMessage, Util
12
+ include Mixin::MonkeyPatchAnyInstance, Mixin::MessagingHost, Util
14
13
 
15
14
  # rubocop:disable LineLength
16
15
  CLASSES_DEFINING_OWN_STUB_METHOD = [
@@ -84,6 +83,16 @@ module Transpec
84
83
  register_record(:deprecated)
85
84
  end
86
85
 
86
+ def remove_no_message_allowance!
87
+ return unless allow_no_message?
88
+ super
89
+ register_record(:no_message_allowance)
90
+ end
91
+
92
+ def remove_useless_and_return!
93
+ super && register_record(:useless_and_return)
94
+ end
95
+
87
96
  def add_receiver_arg_to_any_instance_implementation_block!
88
97
  super && register_record(:any_instance_block)
89
98
  end
@@ -163,9 +172,13 @@ module Transpec
163
172
  def register_record(conversion_type)
164
173
  record_class = case conversion_type
165
174
  when :deprecated
166
- DeprecatedRecord
175
+ DeprecatedMethodRecord
176
+ when :no_message_allowance
177
+ NoMessageAllowanceRecord
178
+ when :useless_and_return
179
+ MonkeyPatchUselessAndReturnRecord
167
180
  when :any_instance_block
168
- AnyInstanceBlockRecord
181
+ MonkeyPatchAnyInstanceBlockRecord
169
182
  else
170
183
  AllowRecord
171
184
  end
@@ -207,7 +220,7 @@ module Transpec
207
220
  end
208
221
  end
209
222
 
210
- class DeprecatedRecord < Record
223
+ class DeprecatedMethodRecord < Record
211
224
  def initialize(method_stub, *)
212
225
  @method_stub = method_stub
213
226
  end
@@ -223,6 +236,29 @@ module Transpec
223
236
  syntax << '(:message)'
224
237
  end
225
238
  end
239
+
240
+ class NoMessageAllowanceRecord < Record
241
+ def initialize(method_stub, *)
242
+ @method_stub = method_stub
243
+ end
244
+
245
+ def original_syntax
246
+ syntax = base_syntax
247
+ syntax << '.any_number_of_times' if @method_stub.any_number_of_times?
248
+ syntax << '.at_least(0)' if @method_stub.at_least_zero?
249
+ syntax
250
+ end
251
+
252
+ def converted_syntax
253
+ base_syntax
254
+ end
255
+
256
+ private
257
+
258
+ def base_syntax
259
+ "obj.#{@method_stub.method_name}(:message)"
260
+ end
261
+ end
226
262
  end
227
263
  end
228
264
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'active_support/concern'
4
4
  require 'transpec/syntax/mixin/send'
5
+ require 'transpec/util'
5
6
 
6
7
  module Transpec
7
8
  class Syntax
@@ -24,9 +25,7 @@ module Transpec
24
25
 
25
26
  def any_instance_block_node
26
27
  return unless any_instance?
27
- each_chained_method_node do |node, _|
28
- return node if node.block_type?
29
- end
28
+ Util.each_backward_chained_node(node).find(&:block_type?)
30
29
  end
31
30
 
32
31
  class AnyInstanceBlockRecord < Record
@@ -35,11 +34,21 @@ module Transpec
35
34
  end
36
35
 
37
36
  def original_syntax
38
- "Klass.any_instance.#{@host.method_name}(:message) { |arg| }"
37
+ "#{base_syntax} { |arg| }"
39
38
  end
40
39
 
41
40
  def converted_syntax
42
- "Klass.any_instance.#{@host.method_name}(:message) { |instance, arg| }"
41
+ "#{base_syntax} { |instance, arg| }"
42
+ end
43
+
44
+ def base_syntax
45
+ fail NotImplementedError
46
+ end
47
+ end
48
+
49
+ class MonkeyPatchAnyInstanceBlockRecord < AnyInstanceBlockRecord
50
+ def base_syntax
51
+ "Klass.any_instance.#{@host.method_name}(:message)"
43
52
  end
44
53
  end
45
54
  end
@@ -27,6 +27,10 @@ module Transpec
27
27
  :expect
28
28
  end
29
29
 
30
+ def method_name_for_instance
31
+ fail NotImplementedError
32
+ end
33
+
30
34
  def positive?
31
35
  to_method_name = to_node.children[1]
32
36
  to_method_name == :to
@@ -34,11 +38,8 @@ module Transpec
34
38
 
35
39
  def matcher_node
36
40
  to_arg_node = to_node.children[2]
37
- if to_arg_node.block_type?
38
- to_arg_node.children.first
39
- else
40
- to_arg_node
41
- end
41
+ Util.each_forward_chained_node(to_arg_node, :include_origin)
42
+ .select(&:send_type?).to_a.last
42
43
  end
43
44
 
44
45
  def block_node
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/any_instance_block'
5
+ require 'transpec/syntax/mixin/no_message_allowance'
6
+ require 'transpec/syntax/mixin/useless_and_return'
7
+
8
+ module Transpec
9
+ class Syntax
10
+ module Mixin
11
+ module MessagingHost
12
+ extend ActiveSupport::Concern
13
+ include Mixin::AnyInstanceBlock, Mixin::NoMessageAllowance, Mixin::UselessAndReturn
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,12 +2,13 @@
2
2
 
3
3
  require 'active_support/concern'
4
4
  require 'transpec/syntax/mixin/send'
5
+ require 'transpec/util'
5
6
  require 'ast'
6
7
 
7
8
  module Transpec
8
9
  class Syntax
9
10
  module Mixin
10
- module AllowNoMessage
11
+ module NoMessageAllowance
11
12
  extend ActiveSupport::Concern
12
13
  include Send, ::AST::Sexp
13
14
 
@@ -15,7 +16,7 @@ module Transpec
15
16
  any_number_of_times? || at_least_zero?
16
17
  end
17
18
 
18
- def remove_allowance_for_no_message!
19
+ def remove_no_message_allowance!
19
20
  remove_any_number_of_times!
20
21
  remove_at_least_zero!
21
22
  end
@@ -47,14 +48,14 @@ module Transpec
47
48
  end
48
49
 
49
50
  def any_number_of_times_node
50
- each_chained_method_node do |chained_node|
51
+ Util.each_backward_chained_node(node) do |chained_node|
51
52
  method_name = chained_node.children[1]
52
53
  return chained_node if method_name == :any_number_of_times
53
54
  end
54
55
  end
55
56
 
56
57
  def at_least_zero_node
57
- each_chained_method_node do |chained_node|
58
+ Util.each_backward_chained_node(node) do |chained_node|
58
59
  _, method_name, arg_node = *chained_node
59
60
  next unless method_name == :at_least
60
61
  return chained_node if arg_node == s(:int, 0)
@@ -107,19 +107,6 @@ module Transpec
107
107
  def range_after_arg
108
108
  arg_range.end.join(expression_range.end)
109
109
  end
110
-
111
- def each_chained_method_node
112
- return to_enum(__method__) unless block_given?
113
-
114
- @node.each_ancestor_node.reduce(@node) do |child_node, parent_node|
115
- return unless [:send, :block].include?(parent_node.type)
116
- return unless parent_node.children.first == child_node
117
- yield parent_node, child_node
118
- parent_node
119
- end
120
-
121
- nil
122
- end
123
110
  end
124
111
  end
125
112
  end
@@ -4,6 +4,7 @@ require 'active_support/concern'
4
4
  require 'transpec/syntax/mixin/send'
5
5
  require 'transpec/syntax/mixin/have_matcher_owner'
6
6
  require 'transpec/syntax/operator_matcher'
7
+ require 'transpec/util'
7
8
 
8
9
  module Transpec
9
10
  class Syntax
@@ -25,7 +26,12 @@ module Transpec
25
26
  end
26
27
 
27
28
  def matcher_node
28
- arg_node || parent_node
29
+ if arg_node
30
+ Util.each_forward_chained_node(arg_node, :include_origin)
31
+ .select(&:send_type?).to_a.last
32
+ else
33
+ parent_node
34
+ end
29
35
  end
30
36
 
31
37
  def should_range
@@ -0,0 +1,79 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/util'
6
+
7
+ module Transpec
8
+ class Syntax
9
+ module Mixin
10
+ module UselessAndReturn
11
+ extend ActiveSupport::Concern
12
+ include Send
13
+
14
+ def remove_useless_and_return!
15
+ return unless useless_and_return?
16
+ map = and_return_node.loc
17
+ and_return_range = map.dot.join(map.expression.end)
18
+ remove(and_return_range)
19
+ true
20
+ end
21
+
22
+ def useless_and_return?
23
+ return false unless and_return?
24
+ arg_node = and_return_node.children[2]
25
+ arg_node.nil?
26
+ end
27
+
28
+ def and_return_with_block?
29
+ block_node = Util.block_node_taken_by_method(and_return_node)
30
+ !block_node.nil?
31
+ end
32
+
33
+ def and_return?
34
+ !and_return_node.nil?
35
+ end
36
+
37
+ def and_return_node
38
+ return @and_return_node if instance_variable_defined?(:@and_return_node)
39
+
40
+ @and_return_node = Util.each_backward_chained_node(node) do |chained_node|
41
+ method_name = chained_node.children[1]
42
+ break chained_node if method_name == :and_return
43
+ end
44
+ end
45
+
46
+ class UselessAndReturnRecord < Record
47
+ def initialize(host, *)
48
+ @host = host
49
+ end
50
+
51
+ def original_syntax
52
+ syntax = base_syntax
53
+ syntax << '.and_return'
54
+ syntax << ' { value }' if @host.and_return_with_block?
55
+ syntax
56
+ end
57
+
58
+ def converted_syntax
59
+ syntax = base_syntax
60
+ syntax << ' { value }' if @host.and_return_with_block?
61
+ syntax
62
+ end
63
+
64
+ private
65
+
66
+ def base_syntax
67
+ fail NotImplementedError
68
+ end
69
+ end
70
+
71
+ class MonkeyPatchUselessAndReturnRecord < UselessAndReturnRecord
72
+ def base_syntax
73
+ "obj.#{@host.method_name}(:message)"
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end