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
@@ -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?