transpec 1.6.1 → 1.7.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -4
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +4 -0
  5. data/Guardfile +1 -1
  6. data/README.md +168 -18
  7. data/README.md.erb +154 -18
  8. data/lib/transpec/ast/node.rb +47 -0
  9. data/lib/transpec/cli.rb +1 -1
  10. data/lib/transpec/commit_message.rb +11 -1
  11. data/lib/transpec/configuration.rb +11 -10
  12. data/lib/transpec/converter.rb +36 -14
  13. data/lib/transpec/dynamic_analyzer/rewriter.rb +2 -2
  14. data/lib/transpec/option_parser.rb +11 -0
  15. data/lib/transpec/report.rb +16 -9
  16. data/lib/transpec/rspec_version.rb +9 -0
  17. data/lib/transpec/static_context_inspector.rb +4 -4
  18. data/lib/transpec/syntax/allow.rb +20 -0
  19. data/lib/transpec/syntax/example.rb +1 -1
  20. data/lib/transpec/syntax/expect.rb +5 -20
  21. data/lib/transpec/syntax/its.rb +2 -8
  22. data/lib/transpec/syntax/method_stub.rb +72 -37
  23. data/lib/transpec/syntax/mixin/allow_no_message.rb +8 -17
  24. data/lib/transpec/syntax/mixin/any_instance_block.rb +34 -0
  25. data/lib/transpec/syntax/mixin/expect_base.rb +70 -0
  26. data/lib/transpec/syntax/mixin/expectizable.rb +3 -0
  27. data/lib/transpec/syntax/mixin/have_matcher_owner.rb +5 -2
  28. data/lib/transpec/syntax/mixin/monkey_patch.rb +6 -0
  29. data/lib/transpec/syntax/mixin/{any_instance.rb → monkey_patch_any_instance.rb} +12 -8
  30. data/lib/transpec/syntax/mixin/send.rb +16 -3
  31. data/lib/transpec/syntax/mixin/should_base.rb +8 -2
  32. data/lib/transpec/syntax/oneliner_should.rb +2 -4
  33. data/lib/transpec/syntax/operator_matcher.rb +2 -2
  34. data/lib/transpec/syntax/raise_error.rb +2 -2
  35. data/lib/transpec/syntax/receive.rb +49 -0
  36. data/lib/transpec/syntax/rspec_configure.rb +8 -96
  37. data/lib/transpec/syntax/rspec_configure/expectations.rb +15 -0
  38. data/lib/transpec/syntax/rspec_configure/framework.rb +166 -0
  39. data/lib/transpec/syntax/rspec_configure/mocks.rb +19 -0
  40. data/lib/transpec/syntax/should.rb +1 -4
  41. data/lib/transpec/syntax/should_receive.rb +89 -43
  42. data/lib/transpec/util.rb +21 -7
  43. data/lib/transpec/version.rb +2 -2
  44. data/spec/transpec/ast/node_spec.rb +52 -0
  45. data/spec/transpec/commit_message_spec.rb +2 -2
  46. data/spec/transpec/configuration_spec.rb +14 -13
  47. data/spec/transpec/converter_spec.rb +151 -20
  48. data/spec/transpec/option_parser_spec.rb +10 -0
  49. data/spec/transpec/rspec_version_spec.rb +20 -6
  50. data/spec/transpec/static_context_inspector_spec.rb +2 -2
  51. data/spec/transpec/syntax/allow_spec.rb +140 -0
  52. data/spec/transpec/syntax/double_spec.rb +1 -1
  53. data/spec/transpec/syntax/expect_spec.rb +103 -10
  54. data/spec/transpec/syntax/have_spec.rb +4 -4
  55. data/spec/transpec/syntax/method_stub_spec.rb +41 -1
  56. data/spec/transpec/syntax/operator_matcher_spec.rb +6 -6
  57. data/spec/transpec/syntax/receive_spec.rb +270 -0
  58. data/spec/transpec/syntax/rspec_configure_spec.rb +241 -30
  59. data/spec/transpec/syntax/should_receive_spec.rb +93 -2
  60. data/spec/transpec/syntax/should_spec.rb +2 -2
  61. data/spec/transpec/util_spec.rb +2 -6
  62. data/transpec.gemspec +5 -3
  63. metadata +37 -14
@@ -1,17 +1,16 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/mixin/send'
5
- require 'transpec/syntax/mixin/monkey_patch'
4
+ require 'transpec/syntax/mixin/monkey_patch_any_instance'
5
+ require 'transpec/syntax/mixin/any_instance_block'
6
6
  require 'transpec/syntax/mixin/allow_no_message'
7
- require 'transpec/syntax/mixin/any_instance'
8
7
  require 'transpec/util'
9
8
  require 'English'
10
9
 
11
10
  module Transpec
12
11
  class Syntax
13
12
  class MethodStub < Syntax
14
- include Mixin::Send, Mixin::MonkeyPatch, Mixin::AllowNoMessage, Mixin::AnyInstance, Util
13
+ include Mixin::MonkeyPatchAnyInstance, Mixin::AnyInstanceBlock, Mixin::AllowNoMessage, Util
15
14
 
16
15
  # rubocop:disable LineLength
17
16
  CLASSES_DEFINING_OWN_STUB_METHOD = [
@@ -81,13 +80,17 @@ module Transpec
81
80
  register_record(:deprecated)
82
81
  end
83
82
 
83
+ def add_receiver_arg_to_any_instance_implementation_block!
84
+ super && register_record(:any_instance_block)
85
+ end
86
+
84
87
  private
85
88
 
86
89
  def replacement_source_and_conversion_type(rspec_version)
87
90
  if method_name == :stub_chain
88
91
  [build_allow_to(:receive_message_chain), :allow_to_receive_message_chain]
89
92
  else
90
- if arg_node.type == :hash
93
+ if arg_node.hash_type?
91
94
  if rspec_version.receive_messages_available?
92
95
  [build_allow_to(:receive_messages), :allow_to_receive_messages]
93
96
  else
@@ -141,7 +144,7 @@ module Transpec
141
144
 
142
145
  def message_source(node)
143
146
  message_source = node.loc.expression.source
144
- message_source.prepend(':') if node.type == :sym && !message_source.start_with?(':')
147
+ message_source.prepend(':') if node.sym_type? && !message_source.start_with?(':')
145
148
  message_source
146
149
  end
147
150
 
@@ -154,49 +157,81 @@ module Transpec
154
157
  end
155
158
 
156
159
  def register_record(conversion_type)
157
- @report.records << Record.new(original_syntax, converted_syntax(conversion_type))
158
- end
160
+ record_class = case conversion_type
161
+ when :deprecated
162
+ DeprecatedRecord
163
+ when :any_instance_block
164
+ AnyInstanceBlockRecord
165
+ else
166
+ AllowRecord
167
+ end
168
+ @report.records << record_class.new(self, conversion_type)
169
+ end
170
+
171
+ class AllowRecord < Record
172
+ def initialize(method_stub, conversion_type)
173
+ @method_stub = method_stub
174
+ @conversion_type = conversion_type
175
+ end
159
176
 
160
- def original_syntax
161
- syntax = any_instance? ? 'Klass.any_instance' : 'obj'
162
- syntax << ".#{method_name}"
177
+ def original_syntax
178
+ syntax = @method_stub.any_instance? ? 'Klass.any_instance' : 'obj'
179
+ syntax << ".#{@method_stub.method_name}"
163
180
 
164
- if method_name == :stub_chain
165
- syntax << '(:message1, :message2)'
166
- else
167
- syntax << (arg_node.type == :hash ? '(:message => value)' : '(:message)')
181
+ if @method_stub.method_name == :stub_chain
182
+ syntax << '(:message1, :message2)'
183
+ else
184
+ syntax << (@method_stub.arg_node.hash_type? ? '(:message => value)' : '(:message)')
185
+ end
168
186
  end
169
- end
170
187
 
171
- def converted_syntax(conversion_type)
172
- if conversion_type == :deprecated
173
- converted_syntax_from_deprecated
174
- else
175
- allowized_syntax(conversion_type)
188
+ def converted_syntax
189
+ syntax = @method_stub.any_instance? ? 'allow_any_instance_of(Klass)' : 'allow(obj)'
190
+ syntax << '.to '
191
+
192
+ case @conversion_type
193
+ when :allow_to_receive
194
+ syntax << 'receive(:message)'
195
+ syntax << '.and_return(value)' if @method_stub.arg_node.hash_type?
196
+ when :allow_to_receive_messages
197
+ syntax << 'receive_messages(:message => value)'
198
+ when :allow_to_receive_message_chain
199
+ syntax << 'receive_message_chain(:message1, :message2)'
200
+ end
201
+
202
+ syntax
176
203
  end
177
204
  end
178
205
 
179
- def allowized_syntax(conversion_type)
180
- syntax = any_instance? ? 'allow_any_instance_of(Klass)' : 'allow(obj)'
181
- syntax << '.to '
206
+ class DeprecatedRecord < Record
207
+ def initialize(method_stub, *)
208
+ @method_stub = method_stub
209
+ end
182
210
 
183
- case conversion_type
184
- when :allow_to_receive
185
- syntax << 'receive(:message)'
186
- syntax << '.and_return(value)' if arg_node.type == :hash
187
- when :allow_to_receive_messages
188
- syntax << 'receive_messages(:message => value)'
189
- when :allow_to_receive_message_chain
190
- syntax << 'receive_message_chain(:message1, :message2)'
211
+ def original_syntax
212
+ syntax = @method_stub.any_instance? ? 'Klass.any_instance' : 'obj'
213
+ syntax << ".#{@method_stub.method_name}(:message)"
191
214
  end
192
215
 
193
- syntax
216
+ def converted_syntax
217
+ syntax = 'obj.'
218
+ syntax << @method_stub.send(:replacement_method_for_deprecated_method)
219
+ syntax << '(:message)'
220
+ end
194
221
  end
195
222
 
196
- def converted_syntax_from_deprecated
197
- syntax = 'obj.'
198
- syntax << replacement_method_for_deprecated_method
199
- syntax << '(:message)'
223
+ class AnyInstanceBlockRecord < Record
224
+ def initialize(method_stub, *)
225
+ @method_stub = method_stub
226
+ end
227
+
228
+ def original_syntax
229
+ "Klass.any_instance.#{@method_stub.method_name}(:message) { |arg| }"
230
+ end
231
+
232
+ def converted_syntax
233
+ "Klass.any_instance.#{@method_stub.method_name}(:message) { |instance, arg| }"
234
+ end
200
235
  end
201
236
  end
202
237
  end
@@ -1,12 +1,15 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
3
5
  require 'ast'
4
6
 
5
7
  module Transpec
6
8
  class Syntax
7
9
  module Mixin
8
10
  module AllowNoMessage
9
- include ::AST::Sexp
11
+ extend ActiveSupport::Concern
12
+ include Send, ::AST::Sexp
10
13
 
11
14
  def allow_no_message?
12
15
  any_number_of_times? || at_least_zero?
@@ -17,8 +20,6 @@ module Transpec
17
20
  remove_at_least_zero!
18
21
  end
19
22
 
20
- private
21
-
22
23
  def any_number_of_times?
23
24
  !any_number_of_times_node.nil?
24
25
  end
@@ -27,6 +28,8 @@ module Transpec
27
28
  !at_least_zero_node.nil?
28
29
  end
29
30
 
31
+ private
32
+
30
33
  def remove_any_number_of_times!
31
34
  return unless any_number_of_times?
32
35
  remove_dot_and_method!(any_number_of_times_node)
@@ -44,31 +47,19 @@ module Transpec
44
47
  end
45
48
 
46
49
  def any_number_of_times_node
47
- each_following_chained_method_node do |chained_node|
50
+ each_chained_method_node do |chained_node|
48
51
  method_name = chained_node.children[1]
49
52
  return chained_node if method_name == :any_number_of_times
50
53
  end
51
54
  end
52
55
 
53
56
  def at_least_zero_node
54
- each_following_chained_method_node do |chained_node|
57
+ each_chained_method_node do |chained_node|
55
58
  _, method_name, arg_node = *chained_node
56
59
  next unless method_name == :at_least
57
60
  return chained_node if arg_node == s(:int, 0)
58
61
  end
59
62
  end
60
-
61
- def each_following_chained_method_node
62
- return to_enum(__method__) unless block_given?
63
-
64
- @node.each_ancestor_node.reduce(@node) do |child_node, parent_node|
65
- return unless [:send, :block].include?(parent_node.type)
66
- return unless parent_node.children.first == child_node
67
- yield parent_node, child_node
68
- parent_node
69
- end
70
- nil
71
- end
72
63
  end
73
64
  end
74
65
  end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+
6
+ module Transpec
7
+ class Syntax
8
+ module Mixin
9
+ module AnyInstanceBlock
10
+ extend ActiveSupport::Concern
11
+ include Send
12
+
13
+ def add_receiver_arg_to_any_instance_implementation_block!
14
+ return unless any_instance_block_node
15
+ first_arg_node = any_instance_block_node.children[1].children[0]
16
+ return unless first_arg_node
17
+ first_arg_name = first_arg_node.children.first
18
+ return if first_arg_name == :instance
19
+ insert_before(first_arg_node.loc.expression, 'instance, ')
20
+ true
21
+ end
22
+
23
+ private
24
+
25
+ def any_instance_block_node
26
+ return unless any_instance?
27
+ each_chained_method_node do |node, _|
28
+ return node if node.block_type?
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/syntax/receive'
6
+ require 'transpec/util'
7
+
8
+ module Transpec
9
+ class Syntax
10
+ module Mixin
11
+ module ExpectBase
12
+ extend ActiveSupport::Concern
13
+ include Send
14
+
15
+ included do
16
+ add_dynamic_analysis_request do |rewriter|
17
+ if Receive.dynamic_analysis_target_node?(matcher_node)
18
+ create_receive_matcher.register_request_for_dynamic_analysis(rewriter)
19
+ end
20
+ end
21
+
22
+ alias_method :subject_node, :arg_node
23
+ alias_method :to_node, :parent_node
24
+ end
25
+
26
+ def current_syntax_type
27
+ :expect
28
+ end
29
+
30
+ def positive?
31
+ to_method_name = to_node.children[1]
32
+ to_method_name == :to
33
+ end
34
+
35
+ def matcher_node
36
+ 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
42
+ end
43
+
44
+ def block_node
45
+ Util.block_node_taken_by_method(to_node)
46
+ end
47
+
48
+ def subject_range
49
+ subject_node.loc.expression
50
+ end
51
+
52
+ def receive_matcher
53
+ return @receive_matcher if instance_variable_defined?(:@receive_matcher)
54
+
55
+ @receive_matcher ||= if Receive.conversion_target_node?(matcher_node, @runtime_data)
56
+ create_receive_matcher
57
+ else
58
+ nil
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def create_receive_matcher
65
+ Receive.new(matcher_node, self, @source_rewriter, @runtime_data, @report)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,11 +1,14 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
3
4
  require 'transpec/util'
4
5
 
5
6
  module Transpec
6
7
  class Syntax
7
8
  module Mixin
8
9
  module Expectizable
10
+ extend ActiveSupport::Concern
11
+
9
12
  def wrap_subject_in_expect!
10
13
  wrap_subject_with_method!('expect')
11
14
  end
@@ -1,13 +1,16 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
3
4
  require 'transpec/syntax/have'
4
5
 
5
6
  module Transpec
6
7
  class Syntax
7
8
  module Mixin
8
9
  module HaveMatcherOwner
9
- def self.included(syntax)
10
- syntax.add_dynamic_analysis_request do |rewriter|
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ add_dynamic_analysis_request do |rewriter|
11
14
  if Have.dynamic_analysis_target_node?(matcher_node)
12
15
  create_have_matcher.register_request_for_dynamic_analysis(rewriter)
13
16
  end
@@ -1,9 +1,15 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+
3
6
  module Transpec
4
7
  class Syntax
5
8
  module Mixin
6
9
  module MonkeyPatch
10
+ extend ActiveSupport::Concern
11
+ include Send
12
+
7
13
  def register_request_of_syntax_availability_inspection(rewriter, key, methods)
8
14
  code = "self.class.ancestors.any? { |a| a.name.start_with?('RSpec::') }"
9
15
 
@@ -1,16 +1,18 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/monkey_patch'
3
5
  require 'ast'
4
6
 
5
7
  module Transpec
6
8
  class Syntax
7
9
  module Mixin
8
- module AnyInstance
9
- include ::AST::Sexp
10
+ module MonkeyPatchAnyInstance
11
+ extend ActiveSupport::Concern
12
+ include MonkeyPatch, ::AST::Sexp
10
13
 
11
- def self.included(syntax)
12
- syntax.add_dynamic_analysis_request do |rewriter|
13
- key = :any_instance_target_class_name
14
+ included do
15
+ add_dynamic_analysis_request do |rewriter|
14
16
  code = <<-END.gsub(/^\s+\|/, '').chomp
15
17
  |if self.class.name == 'RSpec::Mocks::AnyInstance::Recorder'
16
18
  | if respond_to?(:klass)
@@ -24,7 +26,7 @@ module Transpec
24
26
  | nil
25
27
  |end
26
28
  END
27
- rewriter.register_request(subject_node, key, code)
29
+ rewriter.register_request(subject_node, :any_instance_target_class_name, code)
28
30
  end
29
31
  end
30
32
 
@@ -35,6 +37,8 @@ module Transpec
35
37
  !node_data[:any_instance_target_class_name].result.nil?
36
38
  end
37
39
 
40
+ private
41
+
38
42
  def any_instance_target_class_source
39
43
  return nil unless any_instance?
40
44
 
@@ -46,13 +50,13 @@ module Transpec
46
50
  end
47
51
 
48
52
  def any_instance_target_node
49
- return nil unless subject_node.type == :send
53
+ return nil unless subject_node.send_type?
50
54
  return nil unless subject_node.children.count == 2
51
55
  receiver_node, method_name = *subject_node
52
56
  return nil unless receiver_node
53
57
  return nil unless method_name == :any_instance
54
58
 
55
- if receiver_node.type == :const || receiver_node == s(:send, nil, :described_class)
59
+ if receiver_node.const_type? || receiver_node == s(:send, nil, :described_class)
56
60
  receiver_node
57
61
  else
58
62
  nil
@@ -14,7 +14,7 @@ module Transpec
14
14
  end
15
15
 
16
16
  def check_target_node_statically(node)
17
- return false unless node && node.type == :send
17
+ return false unless node && node.send_type?
18
18
  receiver_node, method_name, *_ = *node
19
19
  target_method?(receiver_node, method_name)
20
20
  end
@@ -44,8 +44,8 @@ module Transpec
44
44
  end
45
45
  end
46
46
 
47
- def self.included(syntax)
48
- syntax.add_dynamic_analysis_request do |rewriter|
47
+ included do
48
+ add_dynamic_analysis_request do |rewriter|
49
49
  if receiver_node
50
50
  target_node = receiver_node
51
51
  target_object_type = :object
@@ -107,6 +107,19 @@ 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
110
123
  end
111
124
  end
112
125
  end