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
@@ -5,6 +5,46 @@ require 'parser'
5
5
  module Transpec
6
6
  module AST
7
7
  class Node < Parser::AST::Node
8
+ TYPES = %w(
9
+ true false nil
10
+ int float
11
+ str dstr
12
+ sym dsym
13
+ xstr
14
+ regexp regopt
15
+ array splat
16
+ hash pair kwsplat
17
+ irange erange
18
+ self
19
+ lvar ivar cvar gvar
20
+ nth_ref back_ref
21
+ const cbase
22
+ defined?
23
+ lvasgn ivasgn cvasgn gvasgn
24
+ casgn
25
+ masgn mlhs
26
+ op_asgn or_asgn and_asgn
27
+ module class sclass
28
+ def defs undef
29
+ alias
30
+ args
31
+ arg optarg restarg blockarg shadowarg kwarg kwoptarg kwrestarg
32
+ send
33
+ super zsuper
34
+ yield
35
+ block block_pass
36
+ and or not
37
+ if
38
+ case when
39
+ while until while_post until_post for
40
+ break next redo return
41
+ begin
42
+ rescue resbody ensure retry
43
+ preexe postexe
44
+ iflipflop eflipflop
45
+ match_current_line match_with_lvasgn
46
+ ).map(&:to_sym).freeze
47
+
8
48
  attr_reader :metadata
9
49
 
10
50
  def initialize(type, children = [], properties = {})
@@ -19,6 +59,13 @@ module Transpec
19
59
  end
20
60
  end
21
61
 
62
+ TYPES.each do |node_type|
63
+ method_name = "#{node_type.to_s.gsub(/\W/, '')}_type?"
64
+ define_method(method_name) do
65
+ type == node_type
66
+ end
67
+ end
68
+
22
69
  def parent_node
23
70
  @mutable_attributes[:parent_node]
24
71
  end
data/lib/transpec/cli.rb CHANGED
@@ -111,7 +111,7 @@ module Transpec
111
111
  Git.write_commit_message(commit_message.to_s)
112
112
 
113
113
  puts
114
- puts 'A commit message that describes the conversion summary was generated to'.color(:cyan)
114
+ puts 'A commit message which describes the conversion summary was generated to'.color(:cyan)
115
115
  puts '.git/COMMIT_EDITMSG. To use the message, type the following command for'.color(:cyan)
116
116
  puts 'the next commit:'.color(:cyan)
117
117
  puts ' git commit -eF .git/COMMIT_EDITMSG'
@@ -17,10 +17,20 @@ module Transpec
17
17
  |Convert specs to RSpec #{@rspec_version} syntax with Transpec
18
18
  |
19
19
  |This conversion is done by Transpec #{Transpec::Version} with the following command:
20
- | transpec #{@cli_args.join(' ')}
20
+ | transpec #{smart_cli_args}
21
21
  |
22
22
  |#{conversion_summary}
23
23
  END
24
24
  end
25
+
26
+ def smart_cli_args
27
+ @cli_args.map do |arg|
28
+ if arg.include?(' ')
29
+ arg.inspect
30
+ else
31
+ arg
32
+ end
33
+ end.join(' ')
34
+ end
25
35
  end
26
36
  end
@@ -7,16 +7,17 @@ module Transpec
7
7
  BOOLEAN_MATCHER_TYPES = [:conditional, :exact].freeze
8
8
 
9
9
  PREDICATES = [
10
- [:convert_should, true],
11
- [:convert_oneliner, true],
12
- [:convert_should_receive, true],
13
- [:convert_stub, true],
14
- [:convert_have_items, true],
15
- [:convert_its, true],
16
- [:convert_deprecated_method, true],
17
- [:parenthesize_matcher_arg, true],
18
- [:forced, false],
19
- [:skip_dynamic_analysis, false]
10
+ [:convert_should, true],
11
+ [:convert_oneliner, true],
12
+ [:convert_should_receive, true],
13
+ [:convert_stub, true],
14
+ [:convert_have_items, true],
15
+ [:convert_its, true],
16
+ [:convert_deprecated_method, true],
17
+ [:parenthesize_matcher_arg, true],
18
+ [:add_receiver_arg_to_any_instance_implementation_block, true],
19
+ [:forced, false],
20
+ [:skip_dynamic_analysis, false]
20
21
  ].freeze
21
22
 
22
23
  PREDICATES.each do |predicate, _|
@@ -54,10 +54,7 @@ module Transpec
54
54
  )
55
55
  end
56
56
 
57
- if should.have_matcher && @configuration.convert_have_items?
58
- parenthesize_matcher_arg = @configuration.parenthesize_matcher_arg
59
- should.have_matcher.convert_to_standard_expectation!(parenthesize_matcher_arg)
60
- end
57
+ process_have(should.have_matcher)
61
58
  end
62
59
 
63
60
  def process_oneliner_should(oneliner_should)
@@ -82,10 +79,12 @@ module Transpec
82
79
  end
83
80
 
84
81
  def process_expect(expect)
85
- if expect.have_matcher && @configuration.convert_have_items?
86
- parenthesize_matcher_arg = @configuration.parenthesize_matcher_arg
87
- expect.have_matcher.convert_to_standard_expectation!(parenthesize_matcher_arg)
88
- end
82
+ process_have(expect.have_matcher)
83
+ process_any_instance_block(expect.receive_matcher)
84
+ end
85
+
86
+ def process_allow(allow)
87
+ process_any_instance_block(allow.receive_matcher)
89
88
  end
90
89
 
91
90
  def process_should_receive(should_receive)
@@ -102,6 +101,8 @@ module Transpec
102
101
  elsif @configuration.convert_should_receive?
103
102
  should_receive.expectize!(@configuration.negative_form_of_to)
104
103
  end
104
+
105
+ process_any_instance_block(should_receive)
105
106
  end
106
107
 
107
108
  def process_double(double)
@@ -116,6 +117,8 @@ module Transpec
116
117
  end
117
118
 
118
119
  method_stub.remove_allowance_for_no_message! if @configuration.convert_deprecated_method?
120
+
121
+ process_any_instance_block(method_stub)
119
122
  end
120
123
 
121
124
  def process_be_boolean(be_boolean)
@@ -156,26 +159,45 @@ module Transpec
156
159
 
157
160
  def process_rspec_configure(rspec_configure)
158
161
  if need_to_modify_expectation_syntax_configuration?(rspec_configure)
159
- rspec_configure.modify_expectation_syntaxes!(:expect)
162
+ rspec_configure.expectations.syntaxes = :expect
160
163
  end
161
164
 
162
165
  if need_to_modify_mock_syntax_configuration?(rspec_configure)
163
- rspec_configure.modify_mock_syntaxes!(:expect)
166
+ rspec_configure.mocks.syntaxes = :expect
164
167
  end
168
+
169
+ if rspec_version.migration_term_of_any_instance_implementation_block? &&
170
+ configuration.convert_deprecated_method?
171
+ should_yield = configuration.add_receiver_arg_to_any_instance_implementation_block?
172
+ rspec_configure.mocks.yield_receiver_to_any_instance_implementation_blocks = should_yield
173
+ end
174
+ end
175
+
176
+ def process_have(have)
177
+ return if !have || !@configuration.convert_have_items?
178
+ have.convert_to_standard_expectation!(@configuration.parenthesize_matcher_arg)
179
+ end
180
+
181
+ def process_any_instance_block(messaging_host)
182
+ return unless messaging_host
183
+ return unless rspec_version.migration_term_of_any_instance_implementation_block?
184
+ return unless configuration.convert_deprecated_method?
185
+ return unless configuration.add_receiver_arg_to_any_instance_implementation_block?
186
+ messaging_host.add_receiver_arg_to_any_instance_implementation_block!
165
187
  end
166
188
 
167
189
  def need_to_modify_expectation_syntax_configuration?(rspec_configure)
168
190
  return false unless @configuration.convert_should?
169
- rspec_configure.expectation_syntaxes == [:should]
170
- rescue Syntax::RSpecConfigure::UnknownSyntaxError
191
+ rspec_configure.expectations.syntaxes == [:should]
192
+ rescue Syntax::RSpecConfigure::Framework::UnknownSyntaxError
171
193
  false
172
194
  end
173
195
 
174
196
  def need_to_modify_mock_syntax_configuration?(rspec_configure)
175
197
  return false if !@configuration.convert_should_receive? &&
176
198
  !@configuration.convert_stub?
177
- rspec_configure.mock_syntaxes == [:should]
178
- rescue Syntax::RSpecConfigure::UnknownSyntaxError
199
+ rspec_configure.mocks.syntaxes == [:should]
200
+ rescue Syntax::RSpecConfigure::Framework::UnknownSyntaxError
179
201
  false
180
202
  end
181
203
  end
@@ -61,8 +61,8 @@ module Transpec
61
61
  def inject_analysis_method(node, analysis_codes, source_rewriter)
62
62
  front, rear = build_wrapper_codes(node, analysis_codes)
63
63
 
64
- source_range = if taking_block?(node)
65
- node.parent_node.loc.expression
64
+ source_range = if (block_node = block_node_taken_by_method(node))
65
+ block_node.loc.expression
66
66
  else
67
67
  node.loc.expression
68
68
  end
@@ -6,6 +6,8 @@ require 'transpec/version'
6
6
  require 'optparse'
7
7
  require 'rainbow'
8
8
 
9
+ # rubocop:disable ClassLength
10
+
9
11
  module Transpec
10
12
  class OptionParser
11
13
  CONFIG_ATTRS_FOR_KEEP_TYPES = {
@@ -80,6 +82,10 @@ module Transpec
80
82
  @configuration.form_of_be_falsey = type.include?('falsy') ? 'be_falsy' : 'be_falsey'
81
83
  end
82
84
 
85
+ define_option('-a', '--no-yield-any-instance') do
86
+ @configuration.add_receiver_arg_to_any_instance_implementation_block = false
87
+ end
88
+
83
89
  define_option('-p', '--no-parentheses-matcher-arg') do
84
90
  @configuration.parenthesize_matcher_arg = false
85
91
  end
@@ -151,6 +157,11 @@ module Transpec
151
157
  " #{'true,false'.bright} (exact equality)",
152
158
  "Default: #{'truthy,falsey'.bright}"
153
159
  ],
160
+ '-a' => [
161
+ 'Suppress yielding receiver instances to',
162
+ "#{'any_instance'.underline} implementation blocks as the",
163
+ 'first block argument.'
164
+ ],
154
165
  '-p' => [
155
166
  'Suppress parenthesizing arguments of matchers',
156
167
  "when converting #{'should'.underline} with operator matcher",
@@ -49,12 +49,19 @@ module Transpec
49
49
 
50
50
  private
51
51
 
52
+ def rainbow
53
+ @rainbow ||= Rainbow.new
54
+ end
55
+
56
+ def colorize(string, *args)
57
+ rainbow.wrap(string).color(*args)
58
+ end
59
+
52
60
  def without_color
53
- # TODO: Consider using another coloring gem that does not depend global state.
54
- original_coloring_state = Rainbow.enabled
55
- Rainbow.enabled = false
61
+ original_coloring_state = rainbow.enabled
62
+ rainbow.enabled = false
56
63
  value = yield
57
- Rainbow.enabled = original_coloring_state
64
+ rainbow.enabled = original_coloring_state
58
65
  value
59
66
  end
60
67
 
@@ -66,9 +73,9 @@ module Transpec
66
73
  ''
67
74
  end
68
75
 
69
- text = entry_prefix + pluralize(count, 'conversion').color(:cyan) + "\n"
70
- text << indentation + ' ' + 'from: '.color(:cyan) + record.original_syntax + "\n"
71
- text << indentation + ' ' + 'to: '.color(:cyan) + record.converted_syntax + "\n"
76
+ text = entry_prefix + colorize(pluralize(count, 'conversion'), :cyan) + "\n"
77
+ text << indentation + ' ' + colorize('from: ', :cyan) + record.original_syntax + "\n"
78
+ text << indentation + ' ' + colorize('to: ', :cyan) + record.converted_syntax + "\n"
72
79
  end
73
80
 
74
81
  def convertion_and_incomplete_stats
@@ -76,7 +83,7 @@ module Transpec
76
83
 
77
84
  text = pluralize(records.count, 'conversion') + ', '
78
85
  text << pluralize(context_errors.count, 'incomplete') + ', '
79
- text.color(color)
86
+ colorize(text, color)
80
87
  end
81
88
 
82
89
  def error_stats
@@ -88,7 +95,7 @@ module Transpec
88
95
  :yellow
89
96
  end
90
97
 
91
- pluralize(syntax_errors.count, 'error').color(color)
98
+ colorize(pluralize(syntax_errors.count, 'error'), color)
92
99
  end
93
100
 
94
101
  def pluralize(number, thing, options = {})
@@ -43,9 +43,18 @@ module Transpec
43
43
 
44
44
  define_feature :be_truthy, '2.99.0.beta1'
45
45
  define_feature :yielded_example, '2.99.0.beta1'
46
+ define_feature :yielding_receiver_to_any_instance_implementation_block, '2.99.0.beta1'
46
47
  define_feature :oneliner_is_expected, '2.99.0.beta2', except: '3.0.0.beta1'
47
48
  define_feature :receive_messages, '3.0.0.beta1'
48
49
  define_feature :receive_message_chain, '3.0.0.beta2'
49
50
  define_feature :non_should_matcher_protocol, '3.0.0.beta2'
51
+
52
+ ANY_INSTANCE_IMPLEMENTATION_BLOCK_MIGRATION_BEGIN = new('2.99.0.beta1')
53
+ ANY_INSTANCE_IMPLEMENTATION_BLOCK_MIGRATION_EXCLUSIVE_END = new('3.0.0.beta1')
54
+
55
+ def migration_term_of_any_instance_implementation_block?
56
+ self >= ANY_INSTANCE_IMPLEMENTATION_BLOCK_MIGRATION_BEGIN &&
57
+ self < ANY_INSTANCE_IMPLEMENTATION_BLOCK_MIGRATION_EXCLUSIVE_END
58
+ end
50
59
  end
51
60
  end
@@ -85,7 +85,7 @@ module Transpec
85
85
  return false unless TWISTED_SCOPE_TYPES.include?(node.parent_node.type)
86
86
  scope_node = node.parent_node
87
87
  return true if node.equal?(scope_node.children[0])
88
- scope_node.type == :class && node.equal?(scope_node.children[1])
88
+ scope_node.class_type? && node.equal?(scope_node.children[1])
89
89
  end
90
90
 
91
91
  def scope_type(node)
@@ -95,7 +95,7 @@ module Transpec
95
95
  when :block
96
96
  special_block_type(node)
97
97
  when :defs
98
- if node.children.first.type == :self
98
+ if node.children.first.self_type?
99
99
  nil
100
100
  else
101
101
  node.type
@@ -132,8 +132,8 @@ module Transpec
132
132
  return :around if method_name == :around
133
133
 
134
134
  if arg_node && [:sym, :str].include?(arg_node.type)
135
- hook_arg = arg_node.children.first.to_sym
136
- return :all_before_after if hook_arg == :all
135
+ hook_arg = arg_node.children.first.to_sym
136
+ return :all_before_after if hook_arg == :all
137
137
  end
138
138
 
139
139
  :each_before_after
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax'
4
+ require 'transpec/syntax/mixin/expect_base'
5
+
6
+ module Transpec
7
+ class Syntax
8
+ class Allow < Syntax
9
+ include Mixin::ExpectBase
10
+
11
+ def self.target_method?(receiver_node, method_name)
12
+ receiver_node.nil? && [:allow, :allow_any_instance_of].include?(method_name)
13
+ end
14
+
15
+ def any_instance?
16
+ method_name == :allow_any_instance_of
17
+ end
18
+ end
19
+ end
20
+ end
@@ -38,7 +38,7 @@ module Transpec
38
38
  return @block_node if instance_variable_defined?(:@block_node)
39
39
 
40
40
  @block_node ||= @node.each_ancestor_node.find do |ancestor_node|
41
- next false unless ancestor_node.type == :block
41
+ next false unless ancestor_node.block_type?
42
42
  method_name = method_name_of_block_node(ancestor_node)
43
43
  METHODS_YIELD_EXAMPLE.include?(method_name)
44
44
  end
@@ -1,35 +1,20 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
- require 'transpec/syntax/mixin/send'
4
+ require 'transpec/syntax/mixin/expect_base'
5
5
  require 'transpec/syntax/mixin/have_matcher_owner'
6
6
 
7
7
  module Transpec
8
8
  class Syntax
9
9
  class Expect < Syntax
10
- include Mixin::Send, Mixin::HaveMatcherOwner
10
+ include Mixin::ExpectBase, Mixin::HaveMatcherOwner
11
11
 
12
12
  def self.target_method?(receiver_node, method_name)
13
- receiver_node.nil? && method_name == :expect
13
+ receiver_node.nil? && [:expect, :expect_any_instance_of].include?(method_name)
14
14
  end
15
15
 
16
- def current_syntax_type
17
- :expect
18
- end
19
-
20
- def positive?
21
- to_method_name = parent_node.children[1]
22
- to_method_name == :to
23
- end
24
-
25
- def matcher_node
26
- parent_node.children[2]
27
- end
28
-
29
- alias_method :subject_node, :arg_node
30
-
31
- def subject_range
32
- subject_node.loc.expression
16
+ def any_instance?
17
+ method_name == :expect_any_instance_of
33
18
  end
34
19
  end
35
20
  end
@@ -24,7 +24,7 @@ module Transpec
24
24
 
25
25
  front, rear = build_wrapper_codes
26
26
 
27
- insert_before(beginning_of_line_range, front)
27
+ insert_before(beginning_of_line_range(block_node), front)
28
28
  replace(expression_range, 'it')
29
29
  insert_after(block_node.loc.expression, rear)
30
30
 
@@ -92,12 +92,6 @@ module Transpec
92
92
  @base_indentation ||= indentation_of_line(@node)
93
93
  end
94
94
 
95
- def beginning_of_line_range
96
- block_range = block_node.loc.expression
97
- begin_pos = block_range.begin_pos - block_range.column
98
- Parser::Source::Range.new(block_range.source_buffer, begin_pos, begin_pos)
99
- end
100
-
101
95
  def register_record
102
96
  @report.records << Record.new(original_syntax, converted_syntax)
103
97
  end
@@ -124,7 +118,7 @@ module Transpec
124
118
  end
125
119
 
126
120
  def brackets?
127
- @node.type == :array
121
+ @node.array_type?
128
122
  end
129
123
 
130
124
  def literal?