transpec 1.9.3 → 1.10.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +5 -0
  5. data/CONTRIBUTING.md +19 -0
  6. data/README.md +78 -9
  7. data/README.md.erb +68 -10
  8. data/lib/transpec/annotatable.rb +16 -0
  9. data/lib/transpec/cli.rb +35 -27
  10. data/lib/transpec/configuration.rb +1 -0
  11. data/lib/transpec/conversion_error.rb +23 -0
  12. data/lib/transpec/converter.rb +59 -50
  13. data/lib/transpec/dynamic_analyzer.rb +13 -29
  14. data/lib/transpec/dynamic_analyzer/rewriter.rb +3 -10
  15. data/lib/transpec/dynamic_analyzer/runtime_data.rb +16 -8
  16. data/lib/transpec/file_finder.rb +1 -1
  17. data/lib/transpec/git.rb +1 -1
  18. data/lib/transpec/option_parser.rb +12 -10
  19. data/lib/transpec/project.rb +3 -3
  20. data/lib/transpec/record.rb +19 -2
  21. data/lib/transpec/report.rb +29 -13
  22. data/lib/transpec/rspec_version.rb +7 -7
  23. data/lib/transpec/static_context_inspector.rb +1 -5
  24. data/lib/transpec/syntax.rb +11 -16
  25. data/lib/transpec/syntax/be_boolean.rb +1 -1
  26. data/lib/transpec/syntax/be_close.rb +1 -1
  27. data/lib/transpec/syntax/current_example.rb +88 -0
  28. data/lib/transpec/syntax/double.rb +1 -1
  29. data/lib/transpec/syntax/example.rb +60 -54
  30. data/lib/transpec/syntax/have.rb +27 -15
  31. data/lib/transpec/syntax/have/have_record.rb +12 -0
  32. data/lib/transpec/syntax/have/source_builder.rb +18 -16
  33. data/lib/transpec/syntax/its.rb +12 -11
  34. data/lib/transpec/syntax/matcher_definition.rb +1 -1
  35. data/lib/transpec/syntax/method_stub.rb +3 -7
  36. data/lib/transpec/syntax/mixin/matcher_owner.rb +2 -2
  37. data/lib/transpec/syntax/mixin/monkey_patch.rb +3 -5
  38. data/lib/transpec/syntax/mixin/monkey_patch_any_instance.rb +2 -4
  39. data/lib/transpec/syntax/mixin/owned_matcher.rb +1 -4
  40. data/lib/transpec/syntax/mixin/send.rb +7 -9
  41. data/lib/transpec/syntax/oneliner_should.rb +4 -4
  42. data/lib/transpec/syntax/operator.rb +27 -11
  43. data/lib/transpec/syntax/pending.rb +110 -0
  44. data/lib/transpec/syntax/raise_error.rb +1 -1
  45. data/lib/transpec/syntax/receive.rb +4 -4
  46. data/lib/transpec/syntax/rspec_configure/framework.rb +3 -3
  47. data/lib/transpec/syntax/should.rb +2 -2
  48. data/lib/transpec/syntax/should_receive.rb +3 -3
  49. data/lib/transpec/util.rb +38 -6
  50. data/lib/transpec/version.rb +2 -2
  51. data/spec/support/file_helper.rb +1 -1
  52. data/spec/support/shared_context.rb +3 -8
  53. data/spec/transpec/cli_spec.rb +63 -1
  54. data/spec/transpec/configuration_spec.rb +1 -0
  55. data/spec/transpec/converter_spec.rb +106 -15
  56. data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +12 -52
  57. data/spec/transpec/dynamic_analyzer_spec.rb +2 -2
  58. data/spec/transpec/option_parser_spec.rb +3 -2
  59. data/spec/transpec/report_spec.rb +33 -4
  60. data/spec/transpec/rspec_version_spec.rb +5 -2
  61. data/spec/transpec/syntax/current_example_spec.rb +267 -0
  62. data/spec/transpec/syntax/example_spec.rb +156 -122
  63. data/spec/transpec/syntax/have_spec.rb +43 -32
  64. data/spec/transpec/syntax/method_stub_spec.rb +8 -0
  65. data/spec/transpec/syntax/operator_spec.rb +67 -2
  66. data/spec/transpec/syntax/pending_spec.rb +375 -0
  67. metadata +12 -4
  68. data/lib/transpec/context_error.rb +0 -23
@@ -4,8 +4,8 @@ module Transpec
4
4
  # http://semver.org/
5
5
  module Version
6
6
  MAJOR = 1
7
- MINOR = 9
8
- PATCH = 3
7
+ MINOR = 10
8
+ PATCH = 0
9
9
 
10
10
  def self.to_s
11
11
  [MAJOR, MINOR, PATCH].join('.')
@@ -9,7 +9,7 @@ module FileHelper
9
9
  file_path = File.expand_path(file_path)
10
10
 
11
11
  dir_path = File.dirname(file_path)
12
- FileUtils.makedirs(dir_path) unless File.exists?(dir_path)
12
+ FileUtils.makedirs(dir_path) unless File.exist?(dir_path)
13
13
 
14
14
  File.open(file_path, 'w') do |file|
15
15
  case content
@@ -2,9 +2,11 @@
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)' }
6
+
5
7
  let(:source_buffer) do
6
8
  require 'parser'
7
- buffer = Parser::Source::Buffer.new('(string)')
9
+ buffer = Parser::Source::Buffer.new(source_path)
8
10
  buffer.source = source
9
11
  buffer
10
12
  end
@@ -34,13 +36,6 @@ shared_context 'dynamic analysis objects' do
34
36
 
35
37
  let(:source_path) { 'spec/example_spec.rb' }
36
38
 
37
- let(:source_buffer) do
38
- require 'parser'
39
- buffer = Parser::Source::Buffer.new(source_path)
40
- buffer.source = source
41
- buffer
42
- end
43
-
44
39
  runtime_data_cache = {}
45
40
 
46
41
  let(:runtime_data) do
@@ -185,7 +185,7 @@ module Transpec
185
185
  let(:args) { ['--skip-dynamic-analysis', file_path] }
186
186
 
187
187
  it 'skips dynamic analysis' do
188
- DynamicAnalyzer.any_instance.should_not_receive(:analysis)
188
+ DynamicAnalyzer.any_instance.should_not_receive(:analyze)
189
189
  cli.should_receive(:convert_file)
190
190
  cli.run(args)
191
191
  end
@@ -242,6 +242,68 @@ module Transpec
242
242
  cli.convert_file(file_path)
243
243
  end
244
244
  end
245
+
246
+ context 'when it did a less accurate conversion due to a lack of runtime information' do
247
+ let(:source) do
248
+ <<-END
249
+ describe 'example group' do
250
+ it 'is an example' do
251
+ expect(obj).to have(2).items
252
+ end
253
+ end
254
+ END
255
+ end
256
+
257
+ it 'warns to user' do
258
+ cli.should_receive(:warn) do |message|
259
+ message.should =~ /converted.+but.+incorrect/i
260
+ end
261
+
262
+ cli.convert_file(file_path)
263
+ end
264
+ end
265
+
266
+ context 'when both conversion errors and less accurate records are reported' do
267
+ let(:source) do
268
+ <<-END
269
+ describe 'example group' do
270
+ it 'is first' do
271
+ expect(obj).to have(1).item
272
+ end
273
+
274
+ class Klass
275
+ def second
276
+ 2.should == 2
277
+ end
278
+ end
279
+
280
+ it 'is an example' do
281
+ Klass.new.some_method
282
+ end
283
+
284
+ it 'is third' do
285
+ expect(obj).to have(3).items
286
+ end
287
+ end
288
+ END
289
+ end
290
+
291
+ it 'displays them in order of line number' do
292
+ times = 1
293
+
294
+ cli.should_receive(:warn).exactly(3).times do |message|
295
+ line_number = case times
296
+ when 1 then 3
297
+ when 2 then 8
298
+ when 3 then 17
299
+ end
300
+ message.should include(":#{line_number}:")
301
+ times += 1
302
+ end
303
+
304
+ cli.convert_file(file_path)
305
+ end
306
+ end
245
307
  end
246
308
  end
247
309
  end
@@ -15,6 +15,7 @@ module Transpec
15
15
  [:convert_stub?, true],
16
16
  [:convert_have_items?, true],
17
17
  [:convert_its?, true],
18
+ [:convert_pending?, true],
18
19
  [:convert_deprecated_method?, true],
19
20
  [:parenthesize_matcher_arg?, true],
20
21
  [:add_receiver_arg_to_any_instance_implementation_block?, true],
@@ -117,6 +117,11 @@ module Transpec
117
117
  it 'does not convert the expectation to non-monkey-patch syntax' do
118
118
  should == source
119
119
  end
120
+
121
+ it 'adds the conversion error to the report' do
122
+ converter.convert(source)
123
+ converter.report.should have(1).conversion_error
124
+ end
120
125
  end
121
126
  end
122
127
 
@@ -913,15 +918,101 @@ module Transpec
913
918
  describe '#process_example' do
914
919
  let(:example_object) { double('example_object').as_null_object }
915
920
 
921
+ shared_examples 'does nothing' do
922
+ it 'does nothing' do
923
+ example_object.should_not_receive(:convert_pending_to_skip!)
924
+ converter.process_example(example_object)
925
+ end
926
+ end
927
+
928
+ context 'when RSpecVersion#rspec_2_99? returns true' do
929
+ before { rspec_version.stub(:rspec_2_99?).and_return(true) }
930
+
931
+ context 'and Configuration#convert_pending? returns true' do
932
+ before { configuration.convert_pending = true }
933
+
934
+ it 'invokes Example#convert_pending_to_skip!' do
935
+ example_object.should_receive(:convert_pending_to_skip!)
936
+ converter.process_example(example_object)
937
+ end
938
+ end
939
+
940
+ context 'and Configuration#convert_pending? returns false' do
941
+ before { configuration.convert_pending = false }
942
+ include_examples 'does nothing'
943
+ end
944
+ end
945
+
946
+ context 'when RSpecVersion#rspec_2_99? returns false' do
947
+ before { rspec_version.stub(:rspec_2_99?).and_return(false) }
948
+
949
+ context 'and Configuration#convert_pending? returns true' do
950
+ before { configuration.convert_pending = true }
951
+ include_examples 'does nothing'
952
+ end
953
+
954
+ context 'and Configuration#convert_pending? returns false' do
955
+ before { configuration.convert_pending = false }
956
+ include_examples 'does nothing'
957
+ end
958
+ end
959
+ end
960
+
961
+ describe '#process_pending' do
962
+ let(:pending_object) { double('pending_object').as_null_object }
963
+
964
+ shared_examples 'does nothing' do
965
+ it 'does nothing' do
966
+ pending_object.should_not_receive(:convert_deprecated_syntax!)
967
+ converter.process_pending(pending_object)
968
+ end
969
+ end
970
+
971
+ context 'when RSpecVersion#rspec_2_99? returns true' do
972
+ before { rspec_version.stub(:rspec_2_99?).and_return(true) }
973
+
974
+ context 'and Configuration#convert_pending? returns true' do
975
+ before { configuration.convert_pending = true }
976
+
977
+ it 'invokes Example#convert_deprecated_syntax!' do
978
+ pending_object.should_receive(:convert_deprecated_syntax!)
979
+ converter.process_pending(pending_object)
980
+ end
981
+ end
982
+
983
+ context 'and Configuration#convert_pending? returns false' do
984
+ before { configuration.convert_pending = false }
985
+ include_examples 'does nothing'
986
+ end
987
+ end
988
+
989
+ context 'when RSpecVersion#rspec_2_99? returns false' do
990
+ before { rspec_version.stub(:rspec_2_99?).and_return(false) }
991
+
992
+ context 'and Configuration#convert_pending? returns true' do
993
+ before { configuration.convert_pending = true }
994
+ include_examples 'does nothing'
995
+ end
996
+
997
+ context 'and Configuration#convert_pending? returns false' do
998
+ before { configuration.convert_pending = false }
999
+ include_examples 'does nothing'
1000
+ end
1001
+ end
1002
+ end
1003
+
1004
+ describe '#process_current_example' do
1005
+ let(:current_example_object) { double('current_example_object').as_null_object }
1006
+
916
1007
  context 'when RSpecVersion#yielded_example_available? returns true' do
917
1008
  before { rspec_version.stub(:yielded_example_available?).and_return(true) }
918
1009
 
919
1010
  context 'and Configuration#convert_deprecated_method? is true' do
920
1011
  before { configuration.convert_deprecated_method = true }
921
1012
 
922
- it 'invokes Example#convert!' do
923
- example_object.should_receive(:convert!)
924
- converter.process_example(example_object)
1013
+ it 'invokes CurrentExample#convert!' do
1014
+ current_example_object.should_receive(:convert!)
1015
+ converter.process_current_example(current_example_object)
925
1016
  end
926
1017
  end
927
1018
 
@@ -929,8 +1020,8 @@ module Transpec
929
1020
  before { configuration.convert_deprecated_method = false }
930
1021
 
931
1022
  it 'does nothing' do
932
- example_object.should_not_receive(:convert!)
933
- converter.process_example(example_object)
1023
+ current_example_object.should_not_receive(:convert!)
1024
+ converter.process_current_example(current_example_object)
934
1025
  end
935
1026
  end
936
1027
  end
@@ -942,8 +1033,8 @@ module Transpec
942
1033
  before { configuration.convert_deprecated_method = true }
943
1034
 
944
1035
  it 'does nothing' do
945
- example_object.should_not_receive(:convert!)
946
- converter.process_example(example_object)
1036
+ current_example_object.should_not_receive(:convert!)
1037
+ converter.process_current_example(current_example_object)
947
1038
  end
948
1039
  end
949
1040
  end
@@ -1041,9 +1132,9 @@ module Transpec
1041
1132
  end
1042
1133
  end
1043
1134
 
1044
- context 'when RSpecVersion#migration_term_of_any_instance_implementation_block? returns true' do
1135
+ context 'when RSpecVersion#rspec_2_99? returns true' do
1045
1136
  before do
1046
- rspec_version.stub(:migration_term_of_any_instance_implementation_block?).and_return(true)
1137
+ rspec_version.stub(:rspec_2_99?).and_return(true)
1047
1138
  end
1048
1139
 
1049
1140
  context 'and Configuration#convert_deprecated_method? returns true' do
@@ -1078,9 +1169,9 @@ module Transpec
1078
1169
  end
1079
1170
  end
1080
1171
 
1081
- context 'when RSpecVersion#migration_term_of_any_instance_implementation_block? returns false' do
1172
+ context 'when RSpecVersion#rspec_2_99? returns false' do
1082
1173
  before do
1083
- rspec_version.stub(:migration_term_of_any_instance_implementation_block?).and_return(false)
1174
+ rspec_version.stub(:rspec_2_99?).and_return(false)
1084
1175
  end
1085
1176
 
1086
1177
  it 'does not invoke RSpecConfigure.mocks.yield_receiver_to_any_instance_implementation_blocks=' do
@@ -1115,9 +1206,9 @@ module Transpec
1115
1206
  describe '#process_any_instance_block' do
1116
1207
  let(:messaging_host) { double('messaging host').as_null_object }
1117
1208
 
1118
- context 'when RSpecVersion#migration_term_of_any_instance_implementation_block? returns true' do
1209
+ context 'when RSpecVersion#rspec_2_99? returns true' do
1119
1210
  before do
1120
- rspec_version.stub(:migration_term_of_any_instance_implementation_block?).and_return(true)
1211
+ rspec_version.stub(:rspec_2_99?).and_return(true)
1121
1212
  end
1122
1213
 
1123
1214
  context 'and Configuration#convert_deprecated_method? returns true' do
@@ -1156,9 +1247,9 @@ module Transpec
1156
1247
  end
1157
1248
  end
1158
1249
 
1159
- context 'when RSpecVersion#migration_term_of_any_instance_implementation_block? returns false' do
1250
+ context 'when RSpecVersion#rspec_2_99? returns false' do
1160
1251
  before do
1161
- rspec_version.stub(:migration_term_of_any_instance_implementation_block?).and_return(false)
1252
+ rspec_version.stub(:rspec_2_99?).and_return(false)
1162
1253
  end
1163
1254
 
1164
1255
  it 'does nothing' do
@@ -15,18 +15,14 @@ module Transpec
15
15
 
16
16
  let(:source) do
17
17
  <<-END
18
- it 'is foo' do
19
- subject.should be(foo)
20
- end
18
+ subject.should be(foo)
21
19
  END
22
20
  end
23
21
 
24
22
  # rubocop:disable LineLength
25
23
  let(:expected_source) do
26
24
  <<-END
27
- it 'is foo' do
28
- transpec_analysis((transpec_analysis((subject), self, { :should_source_location => [:object, "method(:should).source_location"] }, __FILE__, 41, 48).should be(foo)), self, { :expect_available? => [:context, "self.class.ancestors.any? { |a| a.name.start_with?('RSpec::') } && respond_to?(:expect)"] }, __FILE__, 41, 63)
29
- end
25
+ transpec_analyze((transpec_analyze((subject), self, "(string)_12_19", { :should_source_location => [:object, "method(:should).source_location"] }).should be(foo)), self, "(string)_12_34", { :expect_available? => [:context, "self.class.ancestors.any? { |a| a.name.start_with?('RSpec::') } && respond_to?(:expect)"] })
30
26
  END
31
27
  end
32
28
  # rubocop:enable LineLength
@@ -38,22 +34,18 @@ module Transpec
38
34
  context 'when the target includes here document' do
39
35
  let(:source) do
40
36
  <<-END
41
- it 'matches to foo' do
42
- subject.should =~ <<-HEREDOC.gsub('foo', 'bar')
43
- foo
44
- HEREDOC
45
- end
37
+ subject.should =~ <<-HEREDOC.gsub('foo', 'bar')
38
+ foo
39
+ HEREDOC
46
40
  END
47
41
  end
48
42
 
49
43
  # rubocop:disable LineLength
50
44
  let(:expected_source) do
51
45
  <<-END
52
- it 'matches to foo' do
53
- transpec_analysis((transpec_analysis((subject), self, { :should_source_location => [:object, "method(:should).source_location"] }, __FILE__, 53, 60).should), self, { :"=~_source_location" => [:object, "method(:=~).source_location"], :expect_available? => [:context, "self.class.ancestors.any? { |a| a.name.start_with?('RSpec::') } && respond_to?(:expect)"] }, __FILE__, 53, 67) =~ transpec_analysis((<<-HEREDOC.gsub('foo', 'bar')), self, { :arg_is_enumerable? => [:object, "is_a?(Enumerable)"] }, __FILE__, 71, 100)
54
- foo
55
- HEREDOC
56
- end
46
+ transpec_analyze((transpec_analyze((subject), self, "(string)_14_21", { :should_source_location => [:object, "method(:should).source_location"] }).should), self, "(string)_14_28", { :"=~_source_location" => [:object, "method(:=~).source_location"], :expect_available? => [:context, "self.class.ancestors.any? { |a| a.name.start_with?('RSpec::') } && respond_to?(:expect)"] }) =~ transpec_analyze((<<-HEREDOC.gsub('foo', 'bar')), self, "(string)_32_61", { :arg_is_enumerable? => [:object, "is_a?(Enumerable)"] })
47
+ foo
48
+ HEREDOC
57
49
  END
58
50
  end
59
51
  # rubocop:enable LineLength
@@ -66,18 +58,14 @@ module Transpec
66
58
  context 'when the target takes block' do
67
59
  let(:source) do
68
60
  <<-END
69
- it 'raises error' do
70
- expect { do_something }.to throw_symbol
71
- end
61
+ expect { do_something }.to throw_symbol
72
62
  END
73
63
  end
74
64
 
75
65
  # rubocop:disable LineLength
76
66
  let(:expected_source) do
77
67
  <<-END
78
- it 'raises error' do
79
- transpec_analysis((expect { do_something }), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 51, 57).to throw_symbol
80
- end
68
+ transpec_analyze((expect { do_something }), self, "(string)_14_20", { :expect_source_location => [:context, "method(:expect).source_location"] }).to throw_symbol
81
69
  END
82
70
  end
83
71
  # rubocop:enable LineLength
@@ -87,45 +75,17 @@ module Transpec
87
75
  end
88
76
  end
89
77
 
90
- context 'when the target is only the expression in a block' do
91
- let(:source) do
92
- <<-END
93
- it 'raises error' do
94
- expect
95
- end
96
- END
97
- end
98
-
99
- # rubocop:disable LineLength
100
- let(:expected_source) do
101
- <<-END
102
- it 'raises error' do
103
- transpec_analysis((expect), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 51, 57)
104
- end
105
- END
106
- end
107
- # rubocop:enable LineLength
108
-
109
- it 'wraps the target properly' do
110
- should == expected_source
111
- end
112
- end
113
-
114
78
  context 'when the target is method invocation without parentheses' do
115
79
  let(:source) do
116
80
  <<-END
117
- it 'raises error' do
118
- expect subject
119
- end
81
+ double 'something'
120
82
  END
121
83
  end
122
84
 
123
85
  # rubocop:disable LineLength
124
86
  let(:expected_source) do
125
87
  <<-END
126
- it 'raises error' do
127
- transpec_analysis((expect subject), self, { :expect_source_location => [:context, "method(:expect).source_location"] }, __FILE__, 51, 65)
128
- end
88
+ transpec_analyze((double 'something'), self, "(string)_14_32", { :double_source_location => [:context, "method(:double).source_location"] })
129
89
  END
130
90
  end
131
91
  # rubocop:enable LineLength
@@ -164,7 +164,7 @@ module Transpec
164
164
  runtime_data.should be_an(DynamicAnalyzer::RuntimeData)
165
165
  end
166
166
 
167
- describe 'its element' do
167
+ describe 'an element of the runtime data' do
168
168
  let(:ast) do
169
169
  source_buffer = Parser::Source::Buffer.new(file_path)
170
170
  source_buffer.source = source
@@ -188,7 +188,7 @@ module Transpec
188
188
  end
189
189
 
190
190
  it 'has result of requested analysis' do
191
- element[:available_query_methods].result.should =~ %w(size count length)
191
+ element[:available_query_methods].should =~ %w(size count length)
192
192
  end
193
193
  end
194
194
  end