transpec 1.6.1 → 1.7.0

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