transpec 0.2.6 → 1.0.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +10 -0
  5. data/README.md +111 -56
  6. data/README.md.erb +117 -62
  7. data/lib/transpec/ast/node.rb +41 -0
  8. data/lib/transpec/base_rewriter.rb +55 -0
  9. data/lib/transpec/cli.rb +43 -153
  10. data/lib/transpec/configuration.rb +13 -9
  11. data/lib/transpec/{rewriter.rb → converter.rb} +44 -71
  12. data/lib/transpec/dynamic_analyzer/rewriter.rb +94 -0
  13. data/lib/transpec/dynamic_analyzer/runtime_data.rb +27 -0
  14. data/lib/transpec/dynamic_analyzer.rb +166 -0
  15. data/lib/transpec/file_finder.rb +53 -0
  16. data/lib/transpec/option_parser.rb +166 -0
  17. data/lib/transpec/{context.rb → static_context_inspector.rb} +2 -2
  18. data/lib/transpec/syntax/be_close.rb +7 -9
  19. data/lib/transpec/syntax/double.rb +6 -10
  20. data/lib/transpec/syntax/expect.rb +35 -0
  21. data/lib/transpec/syntax/have.rb +195 -0
  22. data/lib/transpec/syntax/method_stub.rb +22 -27
  23. data/lib/transpec/syntax/mixin/allow_no_message.rb +73 -0
  24. data/lib/transpec/syntax/mixin/any_instance.rb +22 -0
  25. data/lib/transpec/syntax/mixin/expectizable.rb +26 -0
  26. data/lib/transpec/syntax/mixin/have_matcher.rb +23 -0
  27. data/lib/transpec/syntax/mixin/monkey_patch.rb +37 -0
  28. data/lib/transpec/syntax/mixin/send.rb +109 -0
  29. data/lib/transpec/syntax/{matcher.rb → operator_matcher.rb} +27 -14
  30. data/lib/transpec/syntax/raise_error.rb +6 -10
  31. data/lib/transpec/syntax/rspec_configure.rb +29 -28
  32. data/lib/transpec/syntax/should.rb +45 -15
  33. data/lib/transpec/syntax/should_receive.rb +44 -16
  34. data/lib/transpec/syntax.rb +29 -21
  35. data/lib/transpec/util.rb +12 -2
  36. data/lib/transpec/version.rb +3 -3
  37. data/spec/spec_helper.rb +8 -6
  38. data/spec/support/cache_helper.rb +50 -0
  39. data/spec/support/shared_context.rb +49 -1
  40. data/spec/transpec/ast/node_spec.rb +65 -0
  41. data/spec/transpec/cli_spec.rb +33 -242
  42. data/spec/transpec/commit_message_spec.rb +2 -2
  43. data/spec/transpec/configuration_spec.rb +12 -8
  44. data/spec/transpec/{rewriter_spec.rb → converter_spec.rb} +198 -148
  45. data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +183 -0
  46. data/spec/transpec/dynamic_analyzer_spec.rb +164 -0
  47. data/spec/transpec/file_finder_spec.rb +118 -0
  48. data/spec/transpec/option_parser_spec.rb +185 -0
  49. data/spec/transpec/{context_spec.rb → static_context_inspector_spec.rb} +27 -12
  50. data/spec/transpec/syntax/be_close_spec.rb +8 -4
  51. data/spec/transpec/syntax/double_spec.rb +105 -12
  52. data/spec/transpec/syntax/expect_spec.rb +83 -0
  53. data/spec/transpec/syntax/have_spec.rb +599 -0
  54. data/spec/transpec/syntax/method_stub_spec.rb +276 -115
  55. data/spec/transpec/syntax/{matcher_spec.rb → operator_matcher_spec.rb} +277 -98
  56. data/spec/transpec/syntax/raise_error_spec.rb +92 -46
  57. data/spec/transpec/syntax/should_receive_spec.rb +298 -92
  58. data/spec/transpec/syntax/should_spec.rb +230 -44
  59. data/spec/transpec/util_spec.rb +2 -9
  60. data/tasks/lib/transpec_demo.rb +1 -1
  61. data/tasks/lib/transpec_test.rb +5 -7
  62. data/tasks/test.rake +5 -1
  63. data/transpec.gemspec +1 -1
  64. metadata +46 -22
  65. data/lib/transpec/syntax/able_to_allow_no_message.rb +0 -73
  66. data/lib/transpec/syntax/able_to_target_any_instance.rb +0 -24
  67. data/lib/transpec/syntax/expectizable.rb +0 -27
  68. data/lib/transpec/syntax/send_node_syntax.rb +0 -57
@@ -1,28 +1,39 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/able_to_allow_no_message'
5
- require 'transpec/syntax/able_to_target_any_instance'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/syntax/mixin/monkey_patch'
6
+ require 'transpec/syntax/mixin/allow_no_message'
7
+ require 'transpec/syntax/mixin/any_instance'
6
8
  require 'transpec/util'
7
9
  require 'English'
8
10
 
9
11
  module Transpec
10
12
  class Syntax
11
13
  class MethodStub < Syntax
12
- include AbleToAllowNoMessage, AbleToTargetAnyInstance, Util
14
+ include Mixin::Send, Mixin::MonkeyPatch, Mixin::AllowNoMessage, Mixin::AnyInstance, Util
13
15
 
14
- CLASSES_DEFINING_OWN_STUB_METHOD = [
15
- 'Typhoeus', # https://github.com/typhoeus/typhoeus/blob/6a59c62/lib/typhoeus.rb#L66-L85
16
- 'Excon' # https://github.com/geemus/excon/blob/6af4f9c/lib/excon.rb#L143-L178
17
- ]
16
+ def self.target_method?(receiver_node, method_name)
17
+ !receiver_node.nil? && [:stub, :unstub, :stub!, :unstub!].include?(method_name)
18
+ end
19
+
20
+ def register_request_for_dynamic_analysis(rewriter)
21
+ register_request_of_syntax_availability_inspection(
22
+ rewriter,
23
+ :allow_to_receive_available?,
24
+ [:allow, :receive]
25
+ )
26
+ end
27
+
28
+ def allow_to_receive_available?
29
+ check_syntax_availability(__method__)
30
+ end
18
31
 
19
32
  def allowize!
20
33
  # There's no way of unstubbing in #allow syntax.
21
34
  return unless [:stub, :stub!].include?(method_name)
22
35
 
23
- fail 'Already replaced deprecated method, cannot allowize.' if @replaced_deprecated_method
24
-
25
- unless context.allow_to_receive_available?
36
+ unless allow_to_receive_available?
26
37
  fail InvalidContextError.new(selector_range, "##{method_name}", '#allow')
27
38
  end
28
39
 
@@ -35,34 +46,18 @@ module Transpec
35
46
  end
36
47
 
37
48
  register_record(:allow)
38
-
39
- @allowized = true
40
49
  end
41
50
 
42
- def replace_deprecated_method!
51
+ def convert_deprecated_method!
43
52
  return unless replacement_method_for_deprecated_method
44
53
 
45
- fail 'Already allowized, cannot replace deprecated method.' if @allowized
46
-
47
54
  replace(selector_range, replacement_method_for_deprecated_method)
48
55
 
49
56
  register_record(:deprecated)
50
-
51
- @replaced_deprecated_method = true
52
57
  end
53
58
 
54
59
  private
55
60
 
56
- def self.target_receiver_node?(node)
57
- return false if node.nil?
58
- const_name = Util.const_name(node)
59
- !CLASSES_DEFINING_OWN_STUB_METHOD.include?(const_name)
60
- end
61
-
62
- def self.target_method_names
63
- [:stub, :unstub, :stub!, :unstub!]
64
- end
65
-
66
61
  def build_allow_expressions_from_hash_node(hash_node)
67
62
  expressions = []
68
63
 
@@ -0,0 +1,73 @@
1
+ # coding: utf-8
2
+
3
+ module Transpec
4
+ class Syntax
5
+ module Mixin
6
+ module AllowNoMessage
7
+ include ::AST::Sexp
8
+
9
+ def allow_no_message?
10
+ any_number_of_times? || at_least_zero?
11
+ end
12
+
13
+ def remove_allowance_for_no_message!
14
+ remove_any_number_of_times!
15
+ remove_at_least_zero!
16
+ end
17
+
18
+ private
19
+
20
+ def any_number_of_times?
21
+ !any_number_of_times_node.nil?
22
+ end
23
+
24
+ def at_least_zero?
25
+ !at_least_zero_node.nil?
26
+ end
27
+
28
+ def remove_any_number_of_times!
29
+ return unless any_number_of_times?
30
+ remove_dot_and_method!(any_number_of_times_node)
31
+ end
32
+
33
+ def remove_at_least_zero!
34
+ return unless at_least_zero?
35
+ remove_dot_and_method!(at_least_zero_node)
36
+ end
37
+
38
+ def remove_dot_and_method!(send_node)
39
+ map = send_node.loc
40
+ dot_and_method_range = map.dot.join(map.expression.end)
41
+ remove(dot_and_method_range)
42
+ end
43
+
44
+ def any_number_of_times_node
45
+ each_following_chained_method_node do |chained_node|
46
+ method_name = chained_node.children[1]
47
+ return chained_node if method_name == :any_number_of_times
48
+ end
49
+ end
50
+
51
+ def at_least_zero_node
52
+ each_following_chained_method_node do |chained_node|
53
+ _, method_name, arg_node = *chained_node
54
+ next unless method_name == :at_least
55
+ return chained_node if arg_node == s(:int, 0)
56
+ end
57
+ end
58
+
59
+ def each_following_chained_method_node
60
+ return to_enum(__method__) unless block_given?
61
+
62
+ @ancestor_nodes.reverse.reduce(@node) do |child_node, parent_node|
63
+ return unless [:send, :block].include?(parent_node.type)
64
+ return unless parent_node.children.first == child_node
65
+ yield parent_node, child_node
66
+ parent_node
67
+ end
68
+ nil
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+
3
+ module Transpec
4
+ class Syntax
5
+ module Mixin
6
+ module AnyInstance
7
+ def any_instance?
8
+ !class_node_of_any_instance.nil?
9
+ end
10
+
11
+ def class_node_of_any_instance
12
+ return nil unless subject_node.type == :send
13
+ return nil unless subject_node.children.count == 2
14
+ receiver_node, method_name = *subject_node
15
+ return nil unless method_name == :any_instance
16
+ return nil unless receiver_node.type == :const
17
+ receiver_node
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/util'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ module Mixin
8
+ module Expectizable
9
+ def wrap_subject_in_expect!
10
+ wrap_subject_with_method!('expect')
11
+ end
12
+
13
+ private
14
+
15
+ def wrap_subject_with_method!(method)
16
+ if Util.in_parentheses?(subject_node)
17
+ insert_before(subject_range, method)
18
+ else
19
+ insert_before(subject_range, "#{method}(")
20
+ insert_after(subject_range, ')')
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/have'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ module Mixin
8
+ module HaveMatcher
9
+ def have_matcher
10
+ return @have_matcher if instance_variable_defined?(:@have_matcher)
11
+
12
+ @have_matcher ||= begin
13
+ if Have.target_node?(matcher_node, @runtime_data)
14
+ Have.new(matcher_node, self, @source_rewriter, @runtime_data, @report)
15
+ else
16
+ nil
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+
3
+ module Transpec
4
+ class Syntax
5
+ module Mixin
6
+ module MonkeyPatch
7
+ def register_request_of_syntax_availability_inspection(rewriter, key, methods)
8
+ code = "self.class.name.start_with?('RSpec::')"
9
+
10
+ methods.each do |method|
11
+ code << " && respond_to?(#{method.inspect})"
12
+ end
13
+
14
+ rewriter.register_request(@node, key, code, :context)
15
+ end
16
+
17
+ def check_syntax_availability(key)
18
+ node_data = runtime_node_data(@node)
19
+
20
+ if node_data
21
+ node_data[key].result
22
+ else
23
+ static_context_inspector.send(key)
24
+ end
25
+ end
26
+
27
+ def subject_node
28
+ receiver_node
29
+ end
30
+
31
+ def subject_range
32
+ receiver_range
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,109 @@
1
+ # coding: utf-8
2
+
3
+ module Transpec
4
+ class Syntax
5
+ module Mixin
6
+ module Send
7
+ def self.included(klass)
8
+ klass.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def register_request_for_dynamic_analysis(node, rewriter)
13
+ return unless target_node?(node)
14
+
15
+ receiver_node, method_name, *_ = *node
16
+
17
+ if receiver_node
18
+ target_node = receiver_node
19
+ target_object_type = :object
20
+ else
21
+ target_node = node
22
+ target_object_type = :context
23
+ end
24
+
25
+ key = source_location_key(method_name)
26
+ code = "method(#{method_name.inspect}).source_location"
27
+ rewriter.register_request(target_node, key, code, target_object_type)
28
+ end
29
+
30
+ def target_node?(node, runtime_data = nil)
31
+ check_target_node_statically(node) && check_target_node_dynamically(node, runtime_data)
32
+ end
33
+
34
+ def target_method?(receiver_node, method_name)
35
+ false
36
+ end
37
+
38
+ def check_target_node_statically(node)
39
+ return false unless node && node.type == :send
40
+ receiver_node, method_name, *_ = *node
41
+ target_method?(receiver_node, method_name)
42
+ end
43
+
44
+ def check_target_node_dynamically(node, runtime_data)
45
+ return true unless runtime_data
46
+
47
+ receiver_node, method_name, *_ = *node
48
+ target_node = receiver_node ? receiver_node : node
49
+
50
+ return true unless (node_data = runtime_data[target_node])
51
+ return true unless (eval_data = node_data[source_location_key(method_name)])
52
+ return true unless (source_location = eval_data.result)
53
+
54
+ file_path = source_location.first
55
+ !file_path.match(%r{/gems/rspec\-[^/]+/lib/rspec/}).nil?
56
+ end
57
+
58
+ def source_location_key(method_name)
59
+ "#{method_name}_source_location".to_sym
60
+ end
61
+ end
62
+
63
+ def receiver_node
64
+ @node.children[0]
65
+ end
66
+
67
+ def method_name
68
+ @node.children[1]
69
+ end
70
+
71
+ def arg_node
72
+ @node.children[2]
73
+ end
74
+
75
+ def arg_nodes
76
+ @node.children[2..-1]
77
+ end
78
+
79
+ def selector_range
80
+ @node.loc.selector
81
+ end
82
+
83
+ def receiver_range
84
+ receiver_node.loc.expression
85
+ end
86
+
87
+ def arg_range
88
+ arg_node.loc.expression
89
+ end
90
+
91
+ def parentheses_range
92
+ selector_range.end.join(expression_range.end)
93
+ end
94
+
95
+ def range_in_between_receiver_and_selector
96
+ receiver_range.end.join(selector_range.begin)
97
+ end
98
+
99
+ def range_in_between_selector_and_arg
100
+ selector_range.end.join(arg_range.begin)
101
+ end
102
+
103
+ def range_after_arg
104
+ arg_range.end.join(expression_range.end)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,22 +1,34 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/send_node_syntax'
4
+ require 'transpec/syntax/mixin/send'
5
5
  require 'transpec/util'
6
6
 
7
7
  module Transpec
8
8
  class Syntax
9
- class Matcher < Syntax
10
- include SendNodeSyntax, Util, ::AST::Sexp
9
+ class OperatorMatcher < Syntax
10
+ include Mixin::Send, Util, ::AST::Sexp
11
11
 
12
- def self.target_node?(node)
12
+ OPERATORS = [:==, :===, :<, :<=, :>, :>=, :=~].freeze
13
+
14
+ def self.standalone?
13
15
  false
14
16
  end
15
17
 
16
- def initialize(node, source_rewriter, report = Report.new)
18
+ def self.target_method?(receiver_node, method_name)
19
+ !receiver_node.nil? && OPERATORS.include?(method_name)
20
+ end
21
+
22
+ def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
17
23
  @node = node
18
24
  @source_rewriter = source_rewriter
19
- @report = report
25
+ @runtime_data = runtime_data
26
+ @report = report || Report.new
27
+ end
28
+
29
+ def register_request_for_dynamic_analysis(rewriter)
30
+ return unless method_name == :=~
31
+ rewriter.register_request(arg_node, :arg_is_enumerable?, 'is_a?(Enumerable)')
20
32
  end
21
33
 
22
34
  def correct_operator!(parenthesize_arg = true)
@@ -31,7 +43,7 @@ module Transpec
31
43
  end
32
44
 
33
45
  def parenthesize!(always = true)
34
- return if argument_is_here_document?
46
+ return if contain_here_document?(arg_node)
35
47
 
36
48
  left_of_arg_source = range_in_between_selector_and_arg.source
37
49
 
@@ -60,7 +72,7 @@ module Transpec
60
72
  def convert_to_match!(parenthesize_arg)
61
73
  handle_anterior_of_operator!
62
74
 
63
- if arg_node.type == :array
75
+ if arg_is_enumerable?
64
76
  replace(selector_range, 'match_array')
65
77
  else
66
78
  replace(selector_range, 'match')
@@ -70,7 +82,7 @@ module Transpec
70
82
 
71
83
  # Need to register record after all source rewrites are done
72
84
  # to avoid false record when failed with overlapped rewrite.
73
- if arg_node.type == :array
85
+ if arg_is_enumerable?
74
86
  register_record('=~ [1, 2]', 'match_array([1, 2])')
75
87
  else
76
88
  register_record('=~ /pattern/', 'match(/pattern/)')
@@ -85,6 +97,12 @@ module Transpec
85
97
  end
86
98
  end
87
99
 
100
+ def arg_is_enumerable?
101
+ return true if arg_node.type == :array
102
+ node_data = runtime_node_data(arg_node)
103
+ node_data && node_data[:arg_is_enumerable?].result
104
+ end
105
+
88
106
  def parenthesize_single_line!(always)
89
107
  if in_parentheses?(arg_node)
90
108
  remove(range_in_between_selector_and_arg)
@@ -120,11 +138,6 @@ module Transpec
120
138
  end
121
139
  end
122
140
 
123
- def argument_is_here_document?
124
- here_document?(arg_node) ||
125
- arg_node.each_descendent_node.any? { |n| here_document?(n) }
126
- end
127
-
128
141
  def register_record(original_syntax, converted_syntax)
129
142
  original_syntax ||= "#{method_name} expected"
130
143
  @report.records << Record.new(original_syntax, converted_syntax)
@@ -1,12 +1,16 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/send_node_syntax'
4
+ require 'transpec/syntax/mixin/send'
5
5
 
6
6
  module Transpec
7
7
  class Syntax
8
8
  class RaiseError < Syntax
9
- include SendNodeSyntax
9
+ include Mixin::Send
10
+
11
+ def self.target_method?(receiver_node, method_name)
12
+ receiver_node.nil? && method_name == :raise_error
13
+ end
10
14
 
11
15
  def remove_error_specification_with_negative_expectation!
12
16
  return if positive?
@@ -31,14 +35,6 @@ module Transpec
31
35
 
32
36
  private
33
37
 
34
- def self.target_receiver_node?(node)
35
- node.nil?
36
- end
37
-
38
- def self.target_method_names
39
- [:raise_error]
40
- end
41
-
42
38
  def register_record
43
39
  original_syntax = 'expect { }.not_to raise_error('
44
40
 
@@ -2,11 +2,39 @@
2
2
 
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/util'
5
- require 'transpec/ast/scanner'
6
5
 
7
6
  module Transpec
8
7
  class Syntax
9
8
  class RSpecConfigure < Syntax
9
+ extend Util
10
+
11
+ def self.target_node?(node, runtime_data = nil)
12
+ return false unless node && node.type == :block
13
+ send_node = node.children.first
14
+ receiver_node, method_name, *_ = *send_node
15
+ const_name(receiver_node) == 'RSpec' && method_name == :configure
16
+ end
17
+
18
+ def self.add_framework_configuration(type, config_method_name)
19
+ class_eval <<-END
20
+ def #{type}_syntaxes
21
+ #{type}_framework_configuration.syntaxes
22
+ end
23
+
24
+ def modify_#{type}_syntaxes!(syntaxes)
25
+ #{type}_framework_configuration.modify_syntaxes!(syntaxes)
26
+ end
27
+
28
+ def #{type}_framework_configuration
29
+ @#{type}_framework_configuration ||=
30
+ FrameworkConfiguration.new(node, :#{config_method_name}, source_rewriter)
31
+ end
32
+ END
33
+ end
34
+
35
+ add_framework_configuration :expectation, :expect_with
36
+ add_framework_configuration :mock, :mock_with
37
+
10
38
  class FrameworkConfiguration
11
39
  include ::AST::Sexp
12
40
 
@@ -83,33 +111,6 @@ module Transpec
83
111
  end
84
112
  end
85
113
 
86
- def self.target_node?(node)
87
- return false unless node.type == :block
88
- send_node = node.children.first
89
- receiver_node, method_name, *_ = *send_node
90
- Util.const_name(receiver_node) == 'RSpec' && method_name == :configure
91
- end
92
-
93
- def self.add_framework_configuration(type, config_method_name)
94
- class_eval <<-END
95
- def #{type}_syntaxes
96
- #{type}_framework_configuration.syntaxes
97
- end
98
-
99
- def modify_#{type}_syntaxes!(syntaxes)
100
- #{type}_framework_configuration.modify_syntaxes!(syntaxes)
101
- end
102
-
103
- def #{type}_framework_configuration
104
- @#{type}_framework_configuration ||=
105
- FrameworkConfiguration.new(node, :#{config_method_name}, source_rewriter)
106
- end
107
- END
108
- end
109
-
110
- add_framework_configuration :expectation, :expect_with
111
- add_framework_configuration :mock, :mock_with
112
-
113
114
  class UnknownSyntaxError < StandardError; end
114
115
  end
115
116
  end
@@ -1,21 +1,50 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/expectizable'
5
- require 'transpec/syntax/matcher'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/syntax/mixin/monkey_patch'
6
+ require 'transpec/syntax/mixin/expectizable'
7
+ require 'transpec/syntax/mixin/have_matcher'
6
8
  require 'transpec/util'
9
+ require 'transpec/syntax/operator_matcher'
7
10
 
8
11
  module Transpec
9
12
  class Syntax
10
13
  class Should < Syntax
11
- include Expectizable, Util
14
+ include Mixin::Send, Mixin::MonkeyPatch, Mixin::Expectizable, Mixin::HaveMatcher, Util
15
+
16
+ attr_reader :current_syntax_type
17
+
18
+ def self.target_method?(receiver_node, method_name)
19
+ !receiver_node.nil? && [:should, :should_not].include?(method_name)
20
+ end
21
+
22
+ def initialize(node, ancestor_nodes, source_rewriter = nil, runtime_data = nil, report = nil)
23
+ super
24
+ @current_syntax_type = :should
25
+ end
26
+
27
+ def register_request_for_dynamic_analysis(rewriter)
28
+ register_request_of_syntax_availability_inspection(
29
+ rewriter,
30
+ :expect_available?,
31
+ [:expect]
32
+ )
33
+
34
+ operator_matcher.register_request_for_dynamic_analysis(rewriter) if operator_matcher
35
+ have_matcher.register_request_for_dynamic_analysis(rewriter) if have_matcher
36
+ end
37
+
38
+ def expect_available?
39
+ check_syntax_availability(__method__)
40
+ end
12
41
 
13
42
  def positive?
14
43
  method_name == :should
15
44
  end
16
45
 
17
46
  def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
18
- unless context.expect_to_matcher_available?
47
+ unless expect_available?
19
48
  fail InvalidContextError.new(selector_range, "##{method_name}", '#expect')
20
49
  end
21
50
 
@@ -27,13 +56,22 @@ module Transpec
27
56
 
28
57
  replace(should_range, positive? ? 'to' : negative_form)
29
58
 
59
+ @current_syntax_type = :expect
30
60
  register_record(negative_form)
31
61
 
32
- matcher.correct_operator!(parenthesize_matcher_arg)
62
+ operator_matcher.correct_operator!(parenthesize_matcher_arg) if operator_matcher
33
63
  end
34
64
 
35
- def matcher
36
- @matcher ||= Matcher.new(matcher_node, @source_rewriter, @report)
65
+ def operator_matcher
66
+ return @operator_matcher if instance_variable_defined?(:@operator_matcher)
67
+
68
+ @operator_matcher ||= begin
69
+ if OperatorMatcher.target_node?(matcher_node, @runtime_data)
70
+ OperatorMatcher.new(matcher_node, @source_rewriter, @runtime_data, @report)
71
+ else
72
+ nil
73
+ end
74
+ end
37
75
  end
38
76
 
39
77
  def matcher_node
@@ -42,14 +80,6 @@ module Transpec
42
80
 
43
81
  private
44
82
 
45
- def self.target_receiver_node?(node)
46
- !node.nil?
47
- end
48
-
49
- def self.target_method_names
50
- [:should, :should_not]
51
- end
52
-
53
83
  def replace_proc_selector_with_expect!
54
84
  send_node = subject_node.children.first
55
85
  range_of_subject_method_taking_block = send_node.loc.expression