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,13 +1,19 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support/concern'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/syntax/mixin/have_matcher_owner'
3
6
  require 'transpec/syntax/operator_matcher'
4
7
 
5
8
  module Transpec
6
9
  class Syntax
7
10
  module Mixin
8
11
  module ShouldBase
9
- def self.included(syntax)
10
- syntax.add_dynamic_analysis_request do |rewriter|
12
+ extend ActiveSupport::Concern
13
+ include Send, HaveMatcherOwner
14
+
15
+ included do
16
+ add_dynamic_analysis_request do |rewriter|
11
17
  if OperatorMatcher.dynamic_analysis_target_node?(matcher_node)
12
18
  create_operator_matcher.register_request_for_dynamic_analysis(rewriter)
13
19
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/syntax/mixin/should_base'
5
- require 'transpec/syntax/mixin/send'
6
- require 'transpec/syntax/mixin/have_matcher_owner'
7
5
  require 'transpec/rspec_dsl'
8
6
  require 'transpec/util'
9
7
  require 'active_support/inflector/methods'
@@ -11,7 +9,7 @@ require 'active_support/inflector/methods'
11
9
  module Transpec
12
10
  class Syntax
13
11
  class OnelinerShould < Syntax
14
- include Mixin::ShouldBase, Mixin::Send, Mixin::HaveMatcherOwner, RSpecDSL, Util
12
+ include Mixin::ShouldBase, RSpecDSL, Util
15
13
 
16
14
  attr_reader :current_syntax_type
17
15
 
@@ -114,7 +112,7 @@ module Transpec
114
112
  return @example_block_node if instance_variable_defined?(:@example_block_node)
115
113
 
116
114
  @example_block_node = @node.each_ancestor_node.find do |node|
117
- next false unless node.type == :block
115
+ next false unless node.block_type?
118
116
  send_node = node.children.first
119
117
  receiver_node, method_name, = *send_node
120
118
  next false if receiver_node
@@ -93,7 +93,7 @@ module Transpec
93
93
  end
94
94
 
95
95
  def arg_is_enumerable?
96
- return true if arg_node.type == :array
96
+ return true if arg_node.array_type?
97
97
  node_data = runtime_node_data(arg_node)
98
98
  node_data && node_data[:arg_is_enumerable?].result
99
99
  end
@@ -101,7 +101,7 @@ module Transpec
101
101
  def parenthesize_single_line!(always)
102
102
  if in_explicit_parentheses?(arg_node)
103
103
  remove(range_in_between_selector_and_arg)
104
- elsif always || arg_node.type == :hash
104
+ elsif always || arg_node.hash_type?
105
105
  replace(range_in_between_selector_and_arg, '(')
106
106
  insert_after(expression_range, ')')
107
107
  elsif range_in_between_selector_and_arg.source.empty?
@@ -25,7 +25,7 @@ module Transpec
25
25
 
26
26
  def positive?
27
27
  @node.each_ancestor_node do |ancestor_node|
28
- next unless ancestor_node.type == :send
28
+ next unless ancestor_node.send_type?
29
29
  expectation_method_name = ancestor_node.children[1]
30
30
  return [:should, :to].include?(expectation_method_name)
31
31
  end
@@ -38,7 +38,7 @@ module Transpec
38
38
  def register_record
39
39
  original_syntax = 'expect { }.not_to raise_error('
40
40
 
41
- if arg_nodes.first.type == :const
41
+ if arg_nodes.first.const_type?
42
42
  original_syntax << 'SpecificErrorClass'
43
43
  original_syntax << ', message' if arg_nodes.count >= 2
44
44
  else
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax'
4
+ require 'transpec/syntax/mixin/send'
5
+ require 'transpec/syntax/mixin/any_instance_block'
6
+
7
+ module Transpec
8
+ class Syntax
9
+ class Receive < Syntax
10
+ include Mixin::Send, Mixin::AnyInstanceBlock
11
+
12
+ attr_reader :expectation
13
+
14
+ def self.standalone?
15
+ false
16
+ end
17
+
18
+ def self.target_method?(receiver_node, method_name)
19
+ receiver_node.nil? && method_name == :receive
20
+ end
21
+
22
+ def initialize(node, expectation, source_rewriter = nil, runtime_data = nil, report = nil)
23
+ @node = node
24
+ @expectation = expectation
25
+ @source_rewriter = source_rewriter
26
+ @runtime_data = runtime_data
27
+ @report = report || Report.new
28
+ end
29
+
30
+ def add_receiver_arg_to_any_instance_implementation_block!
31
+ added = super
32
+ return unless added
33
+ @report.records << Record.new(
34
+ "#{@expectation.method_name}(Klass).to receive(:message) { |arg| }",
35
+ "#{@expectation.method_name}(Klass).to receive(:message) { |instance, arg| }"
36
+ )
37
+ end
38
+
39
+ def any_instance?
40
+ @expectation.any_instance?
41
+ end
42
+
43
+ def any_instance_block_node
44
+ return unless any_instance?
45
+ super || @expectation.block_node
46
+ end
47
+ end
48
+ end
49
+ end
@@ -2,115 +2,27 @@
2
2
 
3
3
  require 'transpec/syntax'
4
4
  require 'transpec/util'
5
- require 'ast'
6
5
 
7
6
  module Transpec
8
7
  class Syntax
9
8
  class RSpecConfigure < Syntax
9
+ require 'transpec/syntax/rspec_configure/expectations'
10
+ require 'transpec/syntax/rspec_configure/mocks'
11
+
10
12
  def self.target_node?(node, runtime_data = nil)
11
- return false unless node && node.type == :block
13
+ return false unless node && node.block_type?
12
14
  send_node = node.children.first
13
15
  receiver_node, method_name, *_ = *send_node
14
16
  Util.const_name(receiver_node) == 'RSpec' && method_name == :configure
15
17
  end
16
18
 
17
- def self.add_framework_configuration(type, config_method_name)
18
- class_eval <<-END
19
- def #{type}_syntaxes
20
- #{type}_framework_configuration.syntaxes
21
- end
22
-
23
- def modify_#{type}_syntaxes!(syntaxes)
24
- #{type}_framework_configuration.modify_syntaxes!(syntaxes)
25
- end
26
-
27
- def #{type}_framework_configuration
28
- @#{type}_framework_configuration ||=
29
- FrameworkConfiguration.new(node, :#{config_method_name}, source_rewriter)
30
- end
31
- END
19
+ def expectations
20
+ @expectations ||= Expectations.new(node, source_rewriter)
32
21
  end
33
22
 
34
- add_framework_configuration :expectation, :expect_with
35
- add_framework_configuration :mock, :mock_with
36
-
37
- class FrameworkConfiguration
38
- include ::AST::Sexp
39
-
40
- def initialize(rspec_configure_node, framework_config_method_name, source_rewriter)
41
- @rspec_configure_node = rspec_configure_node
42
- @framework_config_method_name = framework_config_method_name
43
- @source_rewriter = source_rewriter
44
- end
45
-
46
- def syntaxes
47
- return [] unless syntaxes_node
48
-
49
- case syntaxes_node.type
50
- when :sym
51
- [syntaxes_node.children.first]
52
- when :array
53
- syntaxes_node.children.map do |child_node|
54
- child_node.children.first
55
- end
56
- else
57
- fail UnknownSyntaxError, "Unknown syntax specification: #{syntaxes_node}"
58
- end
59
- end
60
-
61
- def modify_syntaxes!(syntaxes)
62
- unless [Array, Symbol].include?(syntaxes.class)
63
- fail ArgumentError, 'Syntaxes must be either an array or a symbol.'
64
- end
65
-
66
- @source_rewriter.replace(syntaxes_node.loc.expression, syntaxes.inspect)
67
- end
68
-
69
- private
70
-
71
- def syntaxes_node
72
- return nil unless framework_block_node
73
-
74
- return @syntaxes_node if instance_variable_defined?(:@syntaxes_node)
75
-
76
- framework_config_variable_name = first_block_arg_name(framework_block_node)
77
-
78
- framework_block_node.each_descendent_node do |node|
79
- next unless node.type == :send
80
- receiver_node, method_name, arg_node, *_ = *node
81
- next unless receiver_node == s(:lvar, framework_config_variable_name)
82
- next unless method_name == :syntax=
83
- return @syntaxes_node = arg_node
84
- end
85
-
86
- @syntaxes_node = nil
87
- end
88
-
89
- def framework_block_node
90
- return @framework_block_node if instance_variable_defined?(:@framework_block_node)
91
-
92
- @framework_block_node = @rspec_configure_node.each_descendent_node.find do |node|
93
- next unless node.type == :block
94
- send_node = node.children.first
95
- receiver_node, method_name, *_ = *send_node
96
- next unless receiver_node == s(:lvar, rspec_configure_block_arg_name)
97
- method_name == @framework_config_method_name
98
- # TODO: Check expectation framework.
99
- end
100
- end
101
-
102
- def rspec_configure_block_arg_name
103
- first_block_arg_name(@rspec_configure_node)
104
- end
105
-
106
- def first_block_arg_name(block_node)
107
- args_node = block_node.children[1]
108
- first_arg_node = args_node.children.first
109
- first_arg_node.children.first
110
- end
23
+ def mocks
24
+ @mocks ||= Mocks.new(node, source_rewriter)
111
25
  end
112
-
113
- class UnknownSyntaxError < StandardError; end
114
26
  end
115
27
  end
116
28
  end
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/rspec_configure/framework'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ class RSpecConfigure
8
+ class Expectations < Framework
9
+ def framework_block_method_name
10
+ :expect_with
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,166 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/util'
4
+ require 'ast'
5
+
6
+ module Transpec
7
+ class Syntax
8
+ class RSpecConfigure
9
+ class Framework
10
+ module SyntaxConfiguration
11
+ def syntaxes
12
+ return [] unless syntaxes_node
13
+
14
+ case syntaxes_node.type
15
+ when :sym
16
+ [syntaxes_node.children.first]
17
+ when :array
18
+ syntaxes_node.children.map do |child_node|
19
+ child_node.children.first
20
+ end
21
+ else
22
+ fail UnknownSyntaxError, "Unknown syntax specification: #{syntaxes_node}"
23
+ end
24
+ end
25
+
26
+ def syntaxes=(syntaxes)
27
+ unless [Array, Symbol].include?(syntaxes.class)
28
+ fail ArgumentError, 'Syntaxes must be either an array or a symbol.'
29
+ end
30
+
31
+ set_configuration!(:syntax, syntaxes.inspect)
32
+ end
33
+
34
+ private
35
+
36
+ def syntaxes_node
37
+ return @syntaxes_node if instance_variable_defined?(:@syntaxes_node)
38
+
39
+ syntax_setter_node = find_configuration_node(:syntax=)
40
+
41
+ @syntaxes_node = if syntax_setter_node
42
+ syntax_setter_node.children[2]
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ class UnknownSyntaxError < StandardError; end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ module Transpec
56
+ class Syntax
57
+ class RSpecConfigure
58
+ class Framework
59
+ include SyntaxConfiguration, Util, ::AST::Sexp
60
+
61
+ def initialize(rspec_configure_node, source_rewriter)
62
+ @rspec_configure_node = rspec_configure_node
63
+ @source_rewriter = source_rewriter
64
+ end
65
+
66
+ private
67
+
68
+ def framework_block_method_name
69
+ fail NotImplementedError
70
+ end
71
+
72
+ def set_configuration!(config_name, value)
73
+ setter_node = find_configuration_node("#{config_name}=")
74
+
75
+ if setter_node
76
+ arg_node = setter_node.children[2]
77
+ @source_rewriter.replace(arg_node.loc.expression, value.to_s)
78
+ else
79
+ add_configuration!(config_name, value)
80
+ end
81
+ end
82
+
83
+ def add_configuration!(config_name, value)
84
+ block_arg_name = framework_block_arg_name || new_framework_block_arg_name
85
+
86
+ lines = [framework_indentation + "#{block_arg_name}.#{config_name} = #{value}"]
87
+
88
+ unless framework_block_node
89
+ indentation = indentation_of_line(@rspec_configure_node) + ' '
90
+ block_invocation = format(
91
+ '%s.%s :rspec do |%s|',
92
+ rspec_configure_block_arg_name, framework_block_method_name, block_arg_name
93
+ )
94
+ lines.unshift(indentation + block_invocation)
95
+ lines << indentation + 'end'
96
+ end
97
+
98
+ block_node = framework_block_node || @rspec_configure_node
99
+ insertion_position = beginning_of_line_range(block_node.loc.end)
100
+
101
+ lines.unshift('') unless (block_node.loc.end.line - block_node.loc.begin.line) <= 1
102
+ lines.map! { |line| line + "\n" }
103
+
104
+ @source_rewriter.insert_before(insertion_position, lines.join(''))
105
+ end
106
+
107
+ def find_configuration_node(configuration_method_name)
108
+ return nil unless framework_block_node
109
+
110
+ configuration_method_name = configuration_method_name.to_sym
111
+
112
+ framework_block_node.each_descendent_node.find do |node|
113
+ next unless node.send_type?
114
+ receiver_node, method_name, = *node
115
+ next unless receiver_node == s(:lvar, framework_block_arg_name)
116
+ method_name == configuration_method_name
117
+ end
118
+ end
119
+
120
+ def framework_block_arg_name
121
+ return nil unless framework_block_node
122
+ first_block_arg_name(framework_block_node)
123
+ end
124
+
125
+ def framework_block_node
126
+ return @framework_block_node if instance_variable_defined?(:@framework_block_node)
127
+
128
+ @framework_block_node = @rspec_configure_node.each_descendent_node.find do |node|
129
+ next unless node.block_type?
130
+ send_node = node.children.first
131
+ receiver_node, method_name, *_ = *send_node
132
+ next unless receiver_node == s(:lvar, rspec_configure_block_arg_name)
133
+ method_name == framework_block_method_name
134
+ # TODO: Check expectation framework.
135
+ end
136
+ end
137
+
138
+ def rspec_configure_block_arg_name
139
+ first_block_arg_name(@rspec_configure_node)
140
+ end
141
+
142
+ def framework_indentation
143
+ if framework_block_node
144
+ indentation_of_line(framework_block_node) + ' '
145
+ else
146
+ indentation_of_line(@rspec_configure_node) + ' '
147
+ end
148
+ end
149
+
150
+ def new_framework_block_arg_name
151
+ case rspec_configure_block_arg_name
152
+ when :rspec then self.class.name.split('::').last.downcase
153
+ when :c then 'config'
154
+ else 'c'
155
+ end
156
+ end
157
+
158
+ def first_block_arg_name(block_node)
159
+ args_node = block_node.children[1]
160
+ first_arg_node = args_node.children.first
161
+ first_arg_node.children.first
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/rspec_configure/framework'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ class RSpecConfigure
8
+ class Mocks < Framework
9
+ def framework_block_method_name
10
+ :mock_with
11
+ end
12
+
13
+ def yield_receiver_to_any_instance_implementation_blocks=(boolean)
14
+ set_configuration!(:yield_receiver_to_any_instance_implementation_blocks, boolean)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end