transpec 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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