transpec 1.10.4 → 1.11.0

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