transpec 1.10.4 → 1.11.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -3
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +96 -18
  5. data/README.md.erb +117 -51
  6. data/lib/transpec/base_rewriter.rb +25 -28
  7. data/lib/transpec/cli.rb +27 -14
  8. data/lib/transpec/configuration.rb +2 -1
  9. data/lib/transpec/converter.rb +54 -32
  10. data/lib/transpec/dynamic_analyzer/helper.rb.erb +44 -0
  11. data/lib/transpec/dynamic_analyzer/node_util.rb +17 -0
  12. data/lib/transpec/dynamic_analyzer/rewriter.rb +12 -4
  13. data/lib/transpec/dynamic_analyzer/runtime_data.rb +3 -4
  14. data/lib/transpec/dynamic_analyzer.rb +14 -52
  15. data/lib/transpec/option_parser.rb +89 -81
  16. data/lib/transpec/processed_source.rb +48 -0
  17. data/lib/transpec/record.rb +2 -2
  18. data/lib/transpec/report.rb +5 -1
  19. data/lib/transpec/rspec_dsl.rb +12 -2
  20. data/lib/transpec/rspec_version.rb +8 -7
  21. data/lib/transpec/spec_suite.rb +114 -0
  22. data/lib/transpec/syntax/example.rb +4 -20
  23. data/lib/transpec/syntax/example_group.rb +38 -0
  24. data/lib/transpec/syntax/have.rb +6 -9
  25. data/lib/transpec/syntax/its.rb +5 -7
  26. data/lib/transpec/syntax/method_stub.rb +12 -13
  27. data/lib/transpec/syntax/mixin/any_instance_block.rb +14 -6
  28. data/lib/transpec/syntax/mixin/context_sensitive.rb +41 -0
  29. data/lib/transpec/syntax/mixin/matcher_owner.rb +16 -26
  30. data/lib/transpec/syntax/mixin/monkey_patch_any_instance.rb +1 -1
  31. data/lib/transpec/syntax/mixin/no_message_allowance.rb +2 -2
  32. data/lib/transpec/syntax/mixin/useless_and_return.rb +2 -2
  33. data/lib/transpec/syntax/oneliner_should.rb +9 -13
  34. data/lib/transpec/syntax/operator.rb +3 -7
  35. data/lib/transpec/syntax/pending.rb +4 -20
  36. data/lib/transpec/syntax/rspec_configure/configuration_modification.rb +86 -0
  37. data/lib/transpec/syntax/rspec_configure/framework.rb +45 -86
  38. data/lib/transpec/syntax/rspec_configure.rb +18 -6
  39. data/lib/transpec/syntax/should.rb +3 -5
  40. data/lib/transpec/syntax/should_receive.rb +1 -1
  41. data/lib/transpec/syntax.rb +8 -0
  42. data/lib/transpec/util.rb +0 -8
  43. data/lib/transpec/version.rb +2 -2
  44. data/spec/acceptance/configuration_modification_spec.rb +132 -0
  45. data/spec/acceptance/conversion_spec.rb +114 -0
  46. data/spec/support/shared_context.rb +6 -12
  47. data/spec/transpec/cli_spec.rb +21 -23
  48. data/spec/transpec/configuration_spec.rb +2 -1
  49. data/spec/transpec/converter_spec.rb +292 -213
  50. data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +3 -3
  51. data/spec/transpec/dynamic_analyzer_spec.rb +8 -2
  52. data/spec/transpec/option_parser_spec.rb +42 -4
  53. data/spec/transpec/processed_source_spec.rb +67 -0
  54. data/spec/transpec/rspec_version_spec.rb +8 -2
  55. data/spec/transpec/spec_suite_spec.rb +107 -0
  56. data/spec/transpec/syntax/allow_spec.rb +9 -27
  57. data/spec/transpec/syntax/example_group_spec.rb +172 -0
  58. data/spec/transpec/syntax/expect_spec.rb +18 -54
  59. data/spec/transpec/syntax/have_spec.rb +35 -14
  60. data/spec/transpec/syntax/its_spec.rb +27 -7
  61. data/spec/transpec/syntax/method_stub_spec.rb +31 -8
  62. data/spec/transpec/syntax/oneliner_should_spec.rb +22 -131
  63. data/spec/transpec/syntax/rspec_configure_spec.rb +118 -15
  64. data/spec/transpec/syntax/should_spec.rb +51 -82
  65. data/tasks/fixtures/guard/COMMIT_EDITMSG +80 -0
  66. data/tasks/fixtures/mail/COMMIT_EDITMSG +84 -0
  67. data/tasks/fixtures/twitter/COMMIT_EDITMSG +36 -0
  68. data/tasks/lib/transpec_test.rb +23 -2
  69. data/tasks/readme.rake +35 -0
  70. metadata +22 -4
  71. data/lib/transpec/parser.rb +0 -9
@@ -1,21 +1,31 @@
1
1
  # coding: utf-8
2
2
 
3
3
  require 'transpec/syntax'
4
+ require 'transpec/syntax/mixin/send'
4
5
  require 'transpec/util'
5
6
 
6
7
  module Transpec
7
8
  class Syntax
8
9
  class RSpecConfigure < Syntax
10
+ require 'transpec/syntax/rspec_configure/configuration_modification'
9
11
  require 'transpec/syntax/rspec_configure/expectations'
10
12
  require 'transpec/syntax/rspec_configure/mocks'
11
13
 
12
- include Util
14
+ include Mixin::Send, ConfigurationModification
15
+
16
+ define_dynamic_analysis do |rewriter|
17
+ code = "TranspecAnalysis.global_data[:rspec_configure_run_order] ||= 0\n" \
18
+ "TranspecAnalysis.global_data[:rspec_configure_run_order] += 1"
19
+ rewriter.register_request(node, :run_order, code)
20
+ end
13
21
 
14
22
  def dynamic_analysis_target?
15
- return false unless node && node.block_type?
16
- send_node = node.children.first
17
- receiver_node, method_name, *_ = *send_node
18
- const_name(receiver_node) == 'RSpec' && method_name == :configure
23
+ return false unless super
24
+ const_name(receiver_node) == 'RSpec' && method_name == :configure && parent_node.block_type?
25
+ end
26
+
27
+ def expose_dsl_globally=(boolean)
28
+ set_configuration!(:expose_dsl_globally, boolean)
19
29
  end
20
30
 
21
31
  def expectations
@@ -26,8 +36,10 @@ module Transpec
26
36
  @mocks ||= Mocks.new(self, source_rewriter)
27
37
  end
28
38
 
39
+ alias_method :block_node, :parent_node
40
+
29
41
  def block_arg_name
30
- first_block_arg_name(node)
42
+ first_block_arg_name(block_node)
31
43
  end
32
44
  end
33
45
  end
@@ -21,20 +21,20 @@ module Transpec
21
21
  )
22
22
  end
23
23
 
24
- def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
24
+ def initialize(*)
25
25
  super
26
26
  @current_syntax_type = :should
27
27
  end
28
28
 
29
29
  def dynamic_analysis_target?
30
- super && !receiver_node.nil? && [:should, :should_not].include?(method_name)
30
+ super && receiver_node && [:should, :should_not].include?(method_name)
31
31
  end
32
32
 
33
33
  def expect_available?
34
34
  syntax_available?(__method__)
35
35
  end
36
36
 
37
- def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
37
+ def expectize!(negative_form = 'not_to')
38
38
  fail ContextError.new("##{method_name}", '#expect', selector_range) unless expect_available?
39
39
 
40
40
  if proc_literal?(subject_node)
@@ -47,8 +47,6 @@ module Transpec
47
47
 
48
48
  @current_syntax_type = :expect
49
49
  register_record(negative_form)
50
-
51
- operator_matcher.convert_operator!(parenthesize_matcher_arg) if operator_matcher
52
50
  end
53
51
 
54
52
  private
@@ -29,7 +29,7 @@ module Transpec
29
29
 
30
30
  def dynamic_analysis_target?
31
31
  super &&
32
- !receiver_node.nil? &&
32
+ receiver_node &&
33
33
  [:should_receive, :should_not_receive].include?(method_name)
34
34
  end
35
35
 
@@ -113,6 +113,10 @@ module Transpec
113
113
  dynamic_analysis_target?
114
114
  end
115
115
 
116
+ def dependent_syntaxes
117
+ @dependent_syntaxes ||= []
118
+ end
119
+
116
120
  def static_context_inspector
117
121
  @static_context_inspector ||= StaticContextInspector.new(node)
118
122
  end
@@ -124,5 +128,9 @@ module Transpec
124
128
  def expression_range
125
129
  node.loc.expression
126
130
  end
131
+
132
+ def inspect
133
+ "#<#{self.class}: #{node.type}>"
134
+ end
127
135
  end
128
136
  end
data/lib/transpec/util.rb CHANGED
@@ -12,14 +12,6 @@ module Transpec
12
12
 
13
13
  module_function
14
14
 
15
- def node_id(node)
16
- source_range = node.loc.expression
17
- source_buffer = source_range.source_buffer
18
- absolute_path = File.expand_path(source_buffer.name)
19
- relative_path = Pathname.new(absolute_path).relative_path_from(Pathname.pwd).to_s
20
- [relative_path, source_range.begin_pos, source_range.end_pos].join('_')
21
- end
22
-
23
15
  def proc_literal?(node)
24
16
  return false unless node.block_type?
25
17
 
@@ -4,8 +4,8 @@ module Transpec
4
4
  # http://semver.org/
5
5
  module Version
6
6
  MAJOR = 1
7
- MINOR = 10
8
- PATCH = 4
7
+ MINOR = 11
8
+ PATCH = 0
9
9
 
10
10
  def self.to_s
11
11
  [MAJOR, MINOR, PATCH].join('.')
@@ -0,0 +1,132 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/cli'
5
+
6
+ module Transpec
7
+ describe 'RSpec.configure modification' do
8
+ include FileHelper
9
+ include_context 'isolated environment'
10
+
11
+ let(:cli) do
12
+ DynamicAnalyzer.any_instance.stub(:silent?).and_return(true)
13
+ cli = CLI.new
14
+ cli.stub(:puts)
15
+ cli
16
+ end
17
+
18
+ context 'when there are multiple RSpec.configure in the spec suite' do
19
+ before do
20
+ create_file('spec/spec_helper.rb', <<-END)
21
+ RSpec.configure do |config|
22
+ end
23
+ END
24
+
25
+ create_file('spec/unit/spec_helper.rb', <<-END)
26
+ require 'spec_helper'
27
+
28
+ RSpec.configure do |config|
29
+ end
30
+ END
31
+
32
+ create_file('spec/unit/unit_spec.rb', <<-END)
33
+ require 'unit/spec_helper'
34
+
35
+ describe 'example' do
36
+ it 'responds to #message' do
37
+ Object.any_instance.stub(:message) do |arg|
38
+ end
39
+ end
40
+ end
41
+ END
42
+ end
43
+
44
+ it 'modifies only the one that was run first' do
45
+ cli.project.stub(:rspec_version).and_return(RSpecVersion.new('2.99.0'))
46
+ cli.run([])
47
+
48
+ File.read('spec/spec_helper.rb').should == <<-END
49
+ RSpec.configure do |config|
50
+ config.mock_with :rspec do |mocks|
51
+ mocks.yield_receiver_to_any_instance_implementation_blocks = true
52
+ end
53
+ end
54
+ END
55
+
56
+ File.read('spec/unit/spec_helper.rb').should == <<-END
57
+ require 'spec_helper'
58
+
59
+ RSpec.configure do |config|
60
+ end
61
+ END
62
+ end
63
+ end
64
+
65
+ describe 'yield_receiver_to_any_instance_implementation_blocks' do
66
+ let(:spec_helper_path) { 'spec/spec_helper.rb' }
67
+
68
+ before do
69
+ create_file(spec_helper_path, <<-END)
70
+ RSpec.configure do |config|
71
+ end
72
+ END
73
+ end
74
+
75
+ [
76
+ 'Object.any_instance.stub(:message)',
77
+ 'Object.any_instance.should_receive(:message)',
78
+ 'allow_any_instance_of(Object).to receive(:message)',
79
+ 'expect_any_instance_of(Object).to receive(:message)'
80
+ ].each do |syntax|
81
+ context "when there's a #{syntax} block to convert" do
82
+ before do
83
+ create_file('spec/example_spec.rb', <<-END)
84
+ describe 'example' do
85
+ it 'responds to #message' do
86
+ #{syntax} do |arg|
87
+ end
88
+ end
89
+ end
90
+ END
91
+ end
92
+
93
+ it 'adds yield_receiver_to_any_instance_implementation_blocks to the RSpec.configure' do
94
+ cli.project.stub(:rspec_version).and_return(RSpecVersion.new('2.99.0'))
95
+ cli.run([])
96
+
97
+ File.read(spec_helper_path).should == <<-END
98
+ RSpec.configure do |config|
99
+ config.mock_with :rspec do |mocks|
100
+ mocks.yield_receiver_to_any_instance_implementation_blocks = true
101
+ end
102
+ end
103
+ END
104
+ end
105
+ end
106
+ end
107
+
108
+ context "when there's no any_instance blocks to convert" do
109
+ before do
110
+ create_file('spec/example_spec.rb', <<-END)
111
+ describe 'example' do
112
+ it 'responds to #foo' do
113
+ Object.any_instance.stub(:foo) do
114
+ end
115
+ end
116
+ end
117
+ END
118
+ end
119
+
120
+ it 'does not modify RSpec.configure' do
121
+ cli.project.stub(:rspec_version).and_return(RSpecVersion.new('2.99.0'))
122
+ cli.run([])
123
+
124
+ File.read(spec_helper_path).should == <<-END
125
+ RSpec.configure do |config|
126
+ end
127
+ END
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,114 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'transpec/cli'
5
+
6
+ module Transpec
7
+ describe 'conversion' do
8
+ include FileHelper
9
+ include_context 'isolated environment'
10
+
11
+ let(:cli) do
12
+ DynamicAnalyzer.any_instance.stub(:silent?).and_return(true)
13
+ cli = CLI.new
14
+ cli.stub(:puts)
15
+ cli
16
+ end
17
+
18
+ let(:spec_path) { 'spec/example_spec.rb' }
19
+
20
+ let(:converted_source) do
21
+ create_file(spec_path, source)
22
+ cli.run([])
23
+ File.read(spec_path)
24
+ end
25
+
26
+ describe 'one-liner expectation with have(n).items matcher' do
27
+ let(:source) do
28
+ <<-END
29
+ class Team
30
+ def players
31
+ [:foo, :bar, :baz]
32
+ end
33
+ end
34
+
35
+ describe 'example' do
36
+ describe 'collection' do
37
+ subject { [:foo, :bar, :baz] }
38
+
39
+ it { should have(3).items }
40
+ end
41
+
42
+ describe 'owner of collection' do
43
+ subject { Team.new }
44
+
45
+ it { should have_at_least(3).players }
46
+ end
47
+ end
48
+ END
49
+ end
50
+
51
+ let(:expected_source) do
52
+ <<-END
53
+ class Team
54
+ def players
55
+ [:foo, :bar, :baz]
56
+ end
57
+ end
58
+
59
+ describe 'example' do
60
+ describe 'collection' do
61
+ subject { [:foo, :bar, :baz] }
62
+
63
+ it 'has 3 items' do
64
+ expect(subject.size).to eq(3)
65
+ end
66
+ end
67
+
68
+ describe 'owner of collection' do
69
+ subject { Team.new }
70
+
71
+ it 'has at least 3 players' do
72
+ expect(subject.players.size).to be >= 3
73
+ end
74
+ end
75
+ end
76
+ END
77
+ end
78
+
79
+ it 'is converted properly' do
80
+ converted_source.should == expected_source
81
+ end
82
+ end
83
+
84
+ describe 'one-liner expectation with operator matcher' do
85
+ context 'in RSpec 2.99.0.beta2 or later' do
86
+ before do
87
+ cli.project.stub(:rspec_version).and_return(RSpecVersion.new('2.99.0.beta2'))
88
+ end
89
+
90
+ let(:source) do
91
+ <<-END
92
+ describe 'example' do
93
+ subject { 1 }
94
+ it { should == 1 }
95
+ end
96
+ END
97
+ end
98
+
99
+ let(:expected_source) do
100
+ <<-END
101
+ describe 'example' do
102
+ subject { 1 }
103
+ it { is_expected.to eq(1) }
104
+ end
105
+ END
106
+ end
107
+
108
+ it 'is converted properly' do
109
+ converted_source.should == expected_source
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -2,26 +2,20 @@
2
2
 
3
3
  # This context requires `source` to be defined with #let.
4
4
  shared_context 'parsed objects' do
5
- let(:source_path) { '(string)' }
5
+ let(:source_path) { nil }
6
6
 
7
- let(:source_buffer) do
8
- require 'parser'
9
- buffer = Parser::Source::Buffer.new(source_path)
10
- buffer.source = source
11
- buffer
7
+ let(:processed_source) do
8
+ require 'transpec/processed_source'
9
+ Transpec::ProcessedSource.parse(source, source_path)
12
10
  end
13
11
 
14
12
  let(:ast) do
15
- require 'transpec/ast/builder'
16
- require 'transpec/parser'
17
- builder = Transpec::AST::Builder.new
18
- parser = Parser::CurrentRuby.new(builder)
19
- parser.parse(source_buffer)
13
+ processed_source.ast
20
14
  end
21
15
 
22
16
  let(:source_rewriter) do
23
17
  require 'parser'
24
- Parser::Source::Rewriter.new(source_buffer)
18
+ Parser::Source::Rewriter.new(processed_source.buffer)
25
19
  end
26
20
 
27
21
  let(:rewritten_source) { source_rewriter.process }
@@ -47,7 +47,7 @@ module Transpec
47
47
 
48
48
  shared_examples 'rewrites files' do
49
49
  it 'rewrites files' do
50
- cli.should_receive(:convert_file)
50
+ cli.should_receive(:convert_spec)
51
51
  cli.run(args)
52
52
  end
53
53
 
@@ -58,7 +58,7 @@ module Transpec
58
58
 
59
59
  shared_examples 'aborts processing' do
60
60
  it 'aborts processing' do
61
- cli.should_not_receive(:convert_file)
61
+ cli.should_not_receive(:convert_spec)
62
62
  cli.run(args).should be_false
63
63
  end
64
64
  end
@@ -154,26 +154,21 @@ module Transpec
154
154
  DynamicAnalyzer.any_instance.stub(:analyze).and_raise(DynamicAnalyzer::AnalysisError)
155
155
  end
156
156
 
157
- it 'suggests using -c/--rspec-command option' do
158
- cli.stub(:exit)
157
+ include_examples 'aborts processing'
159
158
 
159
+ it 'suggests using -c/--rspec-command option' do
160
160
  cli.should_receive(:warn) do |message|
161
- message.should include('-c/--rspec-command')
161
+ message.should include('use -c/--rspec-command')
162
162
  end
163
163
 
164
164
  cli.run(args)
165
165
  end
166
-
167
- it 'exits with status 1' do
168
- cli.should_receive(:exit).with(1)
169
- cli.run(args)
170
- end
171
166
  end
172
167
 
173
168
  context 'when a syntax error is raised while processing files' do
174
169
  let(:args) { [invalid_syntax_file_path, valid_syntax_file_path] }
175
- let(:invalid_syntax_file_path) { 'invalid_example.rb' }
176
- let(:valid_syntax_file_path) { 'valid_example.rb' }
170
+ let(:invalid_syntax_file_path) { 'spec/invalid_example.rb' }
171
+ let(:valid_syntax_file_path) { 'spec/valid_example.rb' }
177
172
 
178
173
  before do
179
174
  create_file(invalid_syntax_file_path, 'This is invalid syntax <')
@@ -181,10 +176,8 @@ module Transpec
181
176
  end
182
177
 
183
178
  it 'warns to the user' do
184
- cli.should_receive(:warn) do |message|
185
- message.should include('Syntax error')
186
- end
187
-
179
+ cli.should_receive(:warn)
180
+ .with('Syntax error at spec/invalid_example.rb:2:1. Skipping the file.')
188
181
  cli.run(args)
189
182
  end
190
183
 
@@ -208,7 +201,7 @@ module Transpec
208
201
 
209
202
  it 'skips dynamic analysis' do
210
203
  DynamicAnalyzer.any_instance.should_not_receive(:analyze)
211
- cli.should_receive(:convert_file)
204
+ cli.should_receive(:convert_spec)
212
205
  cli.run(args)
213
206
  end
214
207
  end
@@ -228,13 +221,18 @@ module Transpec
228
221
  end
229
222
  end
230
223
 
231
- describe '#convert_file' do
224
+ describe '#convert_spec' do
232
225
  include_context 'isolated environment'
233
226
 
234
- let(:file_path) { 'example.rb' }
227
+ let(:processed_source) do
228
+ path = 'example.rb'
229
+ create_file(path, source)
230
+ ProcessedSource.parse_file(path)
231
+ end
232
+
233
+ let(:spec_suite) { SpecSuite.new }
235
234
 
236
235
  before do
237
- create_file(file_path, source)
238
236
  cli.stub(:puts)
239
237
  end
240
238
 
@@ -261,7 +259,7 @@ module Transpec
261
259
  message.should =~ /context/i
262
260
  end
263
261
 
264
- cli.convert_file(file_path)
262
+ cli.convert_spec(processed_source, spec_suite)
265
263
  end
266
264
  end
267
265
 
@@ -281,7 +279,7 @@ module Transpec
281
279
  message.should =~ /converted.+but.+incorrect/i
282
280
  end
283
281
 
284
- cli.convert_file(file_path)
282
+ cli.convert_spec(processed_source, spec_suite)
285
283
  end
286
284
  end
287
285
 
@@ -323,7 +321,7 @@ module Transpec
323
321
  times += 1
324
322
  end
325
323
 
326
- cli.convert_file(file_path)
324
+ cli.convert_spec(processed_source, spec_suite)
327
325
  end
328
326
  end
329
327
  end
@@ -19,7 +19,8 @@ module Transpec
19
19
  [:convert_deprecated_method?, true],
20
20
  [:parenthesize_matcher_arg?, true],
21
21
  [:add_receiver_arg_to_any_instance_implementation_block?, true],
22
- [:convert_stub_with_hash_to_stub_and_return?, false],
22
+ [:convert_stub_with_hash_to_allow_to_receive_and_return?, false],
23
+ [:convert_example_group?, false],
23
24
  [:forced?, false],
24
25
  [:skip_dynamic_analysis?, false],
25
26
  [:negative_form_of_to, 'not_to'],