transpec 1.9.0 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa52c57bc733f1dfe6a1c635a6338bd54cc39c0d
4
- data.tar.gz: 54c31463aff3d7f8a0f52588da49914a4cb597d9
3
+ metadata.gz: 2c34e8b6406b750b87a6af37fd7ed8e1df46a235
4
+ data.tar.gz: 6d778d31bc2c9518fda218793f8a740268ab3dc7
5
5
  SHA512:
6
- metadata.gz: af49f12b94003b1b14f426044d349c03d76c53a8ca78470e75765e1e15f1a1b3c431d2a5c64a0fae7329a74053d80759a0ada4c9282b251eac112a85bd71cdf9
7
- data.tar.gz: 9c160cd00df22d3a0f0f52c1318ca10ebafd3b1fe6b8ddf4d4215a71121fd6448edba07ba649945d0e0aad187b7addb35760d7f4a714320f5cb706cf1ff38429
6
+ metadata.gz: a9e4b610441d631390420e67e391e759b1180e3260abe01ff78deb4fe3cefc57838f9d33da1a1cd5560d5e411a9ddd65f06c8c2fd287dce6a4203cacd737d5eb
7
+ data.tar.gz: 1ba96f0b28b40c05dd29257caead516bedfb4e4fac7fc4d51a56445f1e6734514385d1a27bd0610975d8ba4e513920b5d4e0c40807f6dc4c69c6d158bfa26bab
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Development
4
4
 
5
+ ## v1.9.1
6
+
7
+ * Fix crash on `expect(obj).to non_matcher_object` in dynamic analysis ([#39](https://github.com/yujinakayama/transpec/issues/39))
8
+
5
9
  ## v1.9.0
6
10
 
7
11
  * Support conversion of `and_return { value }` and `and_return` without arguments
data/README.md CHANGED
@@ -41,7 +41,7 @@ describe Account do
41
41
  end
42
42
 
43
43
  describe '#renew' do
44
- context 'when the account is renewable and not closed' do
44
+ context 'when the account is not closed' do
45
45
  before do
46
46
  account.stub(:closed?).and_return(false)
47
47
  end
@@ -77,7 +77,7 @@ describe Account do
77
77
  end
78
78
 
79
79
  describe '#renew' do
80
- context 'when the account is renewable and not closed' do
80
+ context 'when the account is not closed' do
81
81
  before do
82
82
  allow(account).to receive(:closed?).and_return(false)
83
83
  end
@@ -106,13 +106,13 @@ Simply install `transpec` with `gem` command:
106
106
  $ gem install transpec
107
107
  ```
108
108
 
109
- Usually you don't need to add `transpec` to your `*.gemspec` or `Gemfile` since this isn't a tool to be used daily.
109
+ Normally you don't need to add `transpec` to your `Gemfile` or `*.gemspec` since this isn't a tool to be used daily.
110
110
 
111
111
  ## Basic Usage
112
112
 
113
113
  Before converting your specs:
114
114
 
115
- * Make sure your project has `rspec` gem dependency **2.14** or later. If not, change your `*.gemspec` or `Gemfile` to do so.
115
+ * Make sure your project has `rspec` gem dependency **2.14** or later. If not, change your `Gemfile` or `*.gemspec` to do so.
116
116
  * Run `rspec` and check if all the specs pass.
117
117
  * Ensure the Git repository is clean. (You don't want to mix up your changes and Transpec's changes, do you?)
118
118
 
data/README.md.erb CHANGED
@@ -43,7 +43,7 @@ describe Account do
43
43
  end
44
44
 
45
45
  describe '#renew' do
46
- context 'when the account is renewable and not closed' do
46
+ context 'when the account is not closed' do
47
47
  before do
48
48
  account.stub(:closed?).and_return(false)
49
49
  end
@@ -80,13 +80,13 @@ Simply install `transpec` with `gem` command:
80
80
  $ gem install transpec
81
81
  ```
82
82
 
83
- Usually you don't need to add `transpec` to your `*.gemspec` or `Gemfile` since this isn't a tool to be used daily.
83
+ Normally you don't need to add `transpec` to your `Gemfile` or `*.gemspec` since this isn't a tool to be used daily.
84
84
 
85
85
  ## Basic Usage
86
86
 
87
87
  Before converting your specs:
88
88
 
89
- * Make sure your project has `rspec` gem dependency **<%= Transpec.required_rspec_version %>** or later. If not, change your `*.gemspec` or `Gemfile` to do so.
89
+ * Make sure your project has `rspec` gem dependency **<%= Transpec.required_rspec_version %>** or later. If not, change your `Gemfile` or `*.gemspec` to do so.
90
90
  * Run `rspec` and check if all the specs pass.
91
91
  * Ensure the Git repository is clean. (You don't want to mix up your changes and Transpec's changes, do you?)
92
92
 
@@ -61,7 +61,7 @@ module Transpec
61
61
  extend ActiveSupport::Concern
62
62
 
63
63
  module ClassMethods
64
- def add_dynamic_analysis_request(&block)
64
+ def define_dynamic_analysis_request(&block)
65
65
  dynamic_analysis_requests << block
66
66
  end
67
67
 
@@ -7,6 +7,10 @@ require 'transpec/syntax/mixin/owned_matcher'
7
7
  module Transpec
8
8
  class Syntax
9
9
  class Have < Syntax
10
+ require 'transpec/syntax/have/dynamic_inspector'
11
+ require 'transpec/syntax/have/source_builder'
12
+ require 'transpec/syntax/have/have_record'
13
+
10
14
  include Mixin::Send, Mixin::OwnedMatcher
11
15
 
12
16
  # String#count is not query method, and there's no way to determine
@@ -25,19 +29,21 @@ module Transpec
25
29
  [:have, :have_exactly, :have_at_least, :have_at_most].include?(method_name)
26
30
  end
27
31
 
28
- add_dynamic_analysis_request do |rewriter|
32
+ define_dynamic_analysis_request do |rewriter|
29
33
  DynamicInspector.register_request(self, rewriter)
30
34
  end
31
35
 
32
36
  def convert_to_standard_expectation!(parenthesize_matcher_arg = true)
33
37
  return if project_requires_collection_matcher?
34
- replace(@expectation.subject_range, replacement_subject_source) if explicit_subject?
35
- replace(matcher_range, replacement_matcher_source(parenthesize_matcher_arg))
38
+
39
+ replace(expectation.subject_range, replacement_subject_source) if explicit_subject?
40
+ replace(matcher_range, source_builder.replacement_matcher_source(parenthesize_matcher_arg))
41
+
36
42
  register_record if explicit_subject?
37
43
  end
38
44
 
39
45
  def explicit_subject?
40
- @expectation.respond_to?(:subject_node)
46
+ expectation.respond_to?(:subject_node)
41
47
  end
42
48
 
43
49
  alias_method :have_node, :node
@@ -51,10 +57,6 @@ module Transpec
51
57
  items_node.children.size > 2
52
58
  end
53
59
 
54
- def have_method_name # rubocop:disable PredicateName
55
- have_node.children[1]
56
- end
57
-
58
60
  def items_name
59
61
  items_node.children[1]
60
62
  end
@@ -93,35 +95,9 @@ module Transpec
93
95
  QUERY_METHOD_PRIORITIES.first
94
96
  end
95
97
 
96
- def replacement_subject_source
97
- build_replacement_subject_source(@expectation.subject_range.source)
98
- end
99
-
100
- def build_replacement_subject_source(original_subject_source)
101
- source = original_subject_source.dup
102
- if subject_is_owner_of_collection?
103
- if collection_accessor_is_private?
104
- source << ".send(#{collection_accessor.inspect}"
105
- source << ", #{collection_accessor_args_body_source}" if items_method_has_arguments?
106
- source << ')'
107
- else
108
- source << ".#{collection_accessor}#{collection_accessor_args_parentheses_source}"
109
- end
110
- end
111
- source << ".#{query_method}"
112
- end
113
-
114
- def replacement_matcher_source(parenthesize_arg)
115
- build_replacement_matcher_source(size_source, parenthesize_arg)
116
- end
117
-
118
- def build_replacement_matcher_source(size_source, parenthesize_arg = true)
119
- case @expectation.current_syntax_type
120
- when :should
121
- build_replacement_matcher_source_for_should(size_source)
122
- when :expect
123
- build_replacement_matcher_source_for_expect(size_source, parenthesize_arg)
124
- end
98
+ def replacement_subject_source(original_subject_source = nil)
99
+ original_subject_source ||= expectation.subject_range.source
100
+ source_builder.replacement_subject_source(original_subject_source)
125
101
  end
126
102
 
127
103
  def size_source
@@ -130,247 +106,23 @@ module Transpec
130
106
 
131
107
  private
132
108
 
109
+ def source_builder
110
+ @source_builder ||= SourceBuilder.new(self, size_source)
111
+ end
112
+
133
113
  def runtime_subject_data
134
114
  return @runtime_subject_data if instance_variable_defined?(:@runtime_subject_data)
135
- node = explicit_subject? ? @expectation.subject_node : @expectation.node
115
+ node = explicit_subject? ? expectation.subject_node : expectation.node
136
116
  @runtime_subject_data = runtime_node_data(node)
137
117
  end
138
118
 
139
- def build_replacement_matcher_source_for_should(size_source)
140
- case have_method_name
141
- when :have, :have_exactly then "== #{size_source}"
142
- when :have_at_least then ">= #{size_source}"
143
- when :have_at_most then "<= #{size_source}"
144
- end
145
- end
146
-
147
- def build_replacement_matcher_source_for_expect(size_source, parenthesize_arg)
148
- case have_method_name
149
- when :have, :have_exactly
150
- if parenthesize_arg
151
- "eq(#{size_source})"
152
- else
153
- "eq #{size_source}"
154
- end
155
- when :have_at_least
156
- "be >= #{size_source}"
157
- when :have_at_most
158
- "be <= #{size_source}"
159
- end
160
- end
161
-
162
119
  def matcher_range
163
120
  expression_range.join(items_node.loc.expression)
164
121
  end
165
122
 
166
- def collection_accessor_args_parentheses_source
167
- map = items_node.loc
168
- range = map.selector.end.join(map.expression.end)
169
- range.source
170
- end
171
-
172
- def collection_accessor_args_body_source
173
- arg_nodes = items_node.children[2..-1]
174
- range = arg_nodes.first.loc.expression.begin.join(arg_nodes.last.loc.expression.end)
175
- range.source
176
- end
177
-
178
123
  def register_record
179
124
  @report.records << HaveRecord.new(self)
180
125
  end
181
-
182
- class DynamicInspector
183
- def self.register_request(have, rewriter)
184
- new(have, rewriter).register_request
185
- end
186
-
187
- def initialize(have, rewriter)
188
- @have = have
189
- @rewriter = rewriter
190
- end
191
-
192
- def target_node
193
- if @have.explicit_subject?
194
- @have.expectation.subject_node
195
- else
196
- @have.expectation.node
197
- end
198
- end
199
-
200
- def target_type
201
- if @have.explicit_subject?
202
- :object
203
- else
204
- :context
205
- end
206
- end
207
-
208
- def register_request
209
- key = :collection_accessor
210
- code = collection_accessor_inspection_code
211
- @rewriter.register_request(target_node, key, code, target_type)
212
-
213
- # Give up inspecting query methods of collection accessor with arguments
214
- # (e.g. have(2).errors_on(variable)) since this is a context of #instance_eval.
215
- unless @have.items_method_has_arguments?
216
- key = :available_query_methods
217
- code = available_query_methods_inspection_code
218
- @rewriter.register_request(target_node, key, code, target_type)
219
- end
220
-
221
- key = :collection_accessor_is_private?
222
- code = "#{subject_code}.private_methods.include?(#{@have.items_name.inspect})"
223
- @rewriter.register_request(target_node, key, code, target_type)
224
-
225
- key = :project_requires_collection_matcher?
226
- code = 'defined?(RSpec::Rails) || defined?(RSpec::CollectionMatchers)'
227
- @rewriter.register_request(target_node, key, code, :context)
228
- end
229
-
230
- def subject_code
231
- @have.explicit_subject? ? 'self' : 'subject'
232
- end
233
-
234
- # rubocop:disable MethodLength
235
- def collection_accessor_inspection_code
236
- # `expect(owner).to have(n).things` invokes private owner#things with Object#__send__
237
- # if the owner does not respond to any of #size, #count and #length.
238
- #
239
- # rubocop:disable LineLength
240
- # https://github.com/rspec/rspec-expectations/blob/v2.14.3/lib/rspec/matchers/built_in/have.rb#L48-L58
241
- # rubocop:enable LineLength
242
- @collection_accessor_inspection_code ||= <<-END.gsub(/^\s+\|/, '').chomp
243
- |begin
244
- | exact_name = #{@have.items_name.inspect}
245
- |
246
- | inflector = if defined?(ActiveSupport::Inflector) &&
247
- | ActiveSupport::Inflector.respond_to?(:pluralize)
248
- | ActiveSupport::Inflector
249
- | elsif defined?(Inflector)
250
- | Inflector
251
- | else
252
- | nil
253
- | end
254
- |
255
- | if inflector
256
- | pluralized_name = inflector.pluralize(exact_name).to_sym
257
- | respond_to_pluralized_name = #{subject_code}.respond_to?(pluralized_name)
258
- | end
259
- |
260
- | respond_to_query_methods =
261
- | !(#{subject_code}.methods & #{QUERY_METHOD_PRIORITIES.inspect}).empty?
262
- |
263
- | if #{subject_code}.respond_to?(exact_name)
264
- | exact_name
265
- | elsif respond_to_pluralized_name
266
- | pluralized_name
267
- | elsif respond_to_query_methods
268
- | nil
269
- | else
270
- | exact_name
271
- | end
272
- |end
273
- END
274
- end
275
- # rubocop:enable MethodLength
276
-
277
- def available_query_methods_inspection_code
278
- <<-END.gsub(/^\s+\|/, '').chomp
279
- |collection_accessor = #{collection_accessor_inspection_code}
280
- |target = if collection_accessor
281
- | #{subject_code}.__send__(collection_accessor)
282
- | else
283
- | #{subject_code}
284
- | end
285
- |target.methods & #{QUERY_METHOD_PRIORITIES.inspect}
286
- END
287
- end
288
- end
289
-
290
- class HaveRecord < Record
291
- def initialize(have)
292
- @have = have
293
- end
294
-
295
- def original_syntax
296
- @original_syntax ||= begin
297
- type = @have.expectation.class.snake_case_name.to_sym
298
- syntax = build_expectation(original_subject, type)
299
- syntax << " #{@have.have_method_name}(n).#{original_items}"
300
- end
301
- end
302
-
303
- def converted_syntax
304
- @converted_syntax ||= begin
305
- type = @have.expectation.current_syntax_type
306
- syntax = build_expectation(converted_subject, type)
307
- syntax << " #{@have.build_replacement_matcher_source('n')}"
308
- end
309
- end
310
-
311
- def build_expectation(subject, type)
312
- case type
313
- when :should
314
- syntax = "#{subject}.should"
315
- syntax << '_not' unless positive?
316
- when :expect
317
- syntax = "expect(#{subject})."
318
- syntax << (positive? ? 'to' : 'not_to')
319
- end
320
-
321
- syntax
322
- end
323
-
324
- def positive?
325
- @have.expectation.positive?
326
- end
327
-
328
- def original_subject
329
- if @have.subject_is_owner_of_collection?
330
- 'obj'
331
- else
332
- 'collection'
333
- end
334
- end
335
-
336
- def original_items
337
- if @have.subject_is_owner_of_collection?
338
- if @have.items_method_has_arguments?
339
- "#{@have.collection_accessor}(...)"
340
- else
341
- @have.collection_accessor
342
- end
343
- else
344
- 'items'
345
- end
346
- end
347
-
348
- def converted_subject
349
- if @have.subject_is_owner_of_collection?
350
- build_converted_subject('obj')
351
- else
352
- build_converted_subject('collection')
353
- end
354
- end
355
-
356
- def build_converted_subject(subject)
357
- subject << '.'
358
-
359
- if @have.subject_is_owner_of_collection?
360
- if @have.collection_accessor_is_private?
361
- subject << "send(#{@have.collection_accessor.inspect}"
362
- subject << ', ...' if @have.items_method_has_arguments?
363
- subject << ')'
364
- else
365
- subject << "#{@have.collection_accessor}"
366
- subject << '(...)' if @have.items_method_has_arguments?
367
- end
368
- subject << ".#{@have.query_method}"
369
- else
370
- subject << "#{@have.default_query_method}"
371
- end
372
- end
373
- end
374
126
  end
375
127
  end
376
128
  end
@@ -0,0 +1,119 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/have'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ class Have
8
+ class DynamicInspector
9
+ def self.register_request(have, rewriter)
10
+ new(have, rewriter).register_request
11
+ end
12
+
13
+ attr_reader :have, :rewriter
14
+
15
+ def initialize(have, rewriter)
16
+ @have = have
17
+ @rewriter = rewriter
18
+ end
19
+
20
+ def target_node
21
+ if have.explicit_subject?
22
+ have.expectation.subject_node
23
+ else
24
+ have.expectation.node
25
+ end
26
+ end
27
+
28
+ def target_type
29
+ if have.explicit_subject?
30
+ :object
31
+ else
32
+ :context
33
+ end
34
+ end
35
+
36
+ def register_request
37
+ key = :collection_accessor
38
+ code = collection_accessor_inspection_code
39
+ rewriter.register_request(target_node, key, code, target_type)
40
+
41
+ # Give up inspecting query methods of collection accessor with arguments
42
+ # (e.g. have(2).errors_on(variable)) since this is a context of #instance_eval.
43
+ unless have.items_method_has_arguments?
44
+ key = :available_query_methods
45
+ code = available_query_methods_inspection_code
46
+ rewriter.register_request(target_node, key, code, target_type)
47
+ end
48
+
49
+ key = :collection_accessor_is_private?
50
+ code = "#{subject_code}.private_methods.include?(#{have.items_name.inspect})"
51
+ rewriter.register_request(target_node, key, code, target_type)
52
+
53
+ key = :project_requires_collection_matcher?
54
+ code = 'defined?(RSpec::Rails) || defined?(RSpec::CollectionMatchers)'
55
+ rewriter.register_request(target_node, key, code, :context)
56
+ end
57
+
58
+ def subject_code
59
+ have.explicit_subject? ? 'self' : 'subject'
60
+ end
61
+
62
+ # rubocop:disable MethodLength
63
+ def collection_accessor_inspection_code
64
+ # `expect(owner).to have(n).things` invokes private owner#things with Object#__send__
65
+ # if the owner does not respond to any of #size, #count and #length.
66
+ #
67
+ # rubocop:disable LineLength
68
+ # https://github.com/rspec/rspec-expectations/blob/v2.14.3/lib/rspec/matchers/built_in/have.rb#L48-L58
69
+ # rubocop:enable LineLength
70
+ @collection_accessor_inspection_code ||= <<-END.gsub(/^\s+\|/, '').chomp
71
+ |begin
72
+ | exact_name = #{have.items_name.inspect}
73
+ |
74
+ | inflector = if defined?(ActiveSupport::Inflector) &&
75
+ | ActiveSupport::Inflector.respond_to?(:pluralize)
76
+ | ActiveSupport::Inflector
77
+ | elsif defined?(Inflector)
78
+ | Inflector
79
+ | else
80
+ | nil
81
+ | end
82
+ |
83
+ | if inflector
84
+ | pluralized_name = inflector.pluralize(exact_name).to_sym
85
+ | respond_to_pluralized_name = #{subject_code}.respond_to?(pluralized_name)
86
+ | end
87
+ |
88
+ | respond_to_query_methods =
89
+ | !(#{subject_code}.methods & #{QUERY_METHOD_PRIORITIES.inspect}).empty?
90
+ |
91
+ | if #{subject_code}.respond_to?(exact_name)
92
+ | exact_name
93
+ | elsif respond_to_pluralized_name
94
+ | pluralized_name
95
+ | elsif respond_to_query_methods
96
+ | nil
97
+ | else
98
+ | exact_name
99
+ | end
100
+ |end
101
+ END
102
+ end
103
+ # rubocop:enable MethodLength
104
+
105
+ def available_query_methods_inspection_code
106
+ <<-END.gsub(/^\s+\|/, '').chomp
107
+ |collection_accessor = #{collection_accessor_inspection_code}
108
+ |target = if collection_accessor
109
+ | #{subject_code}.__send__(collection_accessor)
110
+ | else
111
+ | #{subject_code}
112
+ | end
113
+ |target.methods & #{QUERY_METHOD_PRIORITIES.inspect}
114
+ END
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,105 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/have'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ class Have
8
+ class HaveRecord < Record
9
+ attr_reader :have
10
+
11
+ def initialize(have)
12
+ @have = have
13
+ end
14
+
15
+ def original_syntax
16
+ @original_syntax ||= begin
17
+ type = have.expectation.class.snake_case_name.to_sym
18
+ syntax = build_expectation(original_subject, type)
19
+ syntax << " #{have.method_name}(n).#{original_items}"
20
+ end
21
+ end
22
+
23
+ def converted_syntax
24
+ @converted_syntax ||= begin
25
+ type = have.expectation.current_syntax_type
26
+ syntax = build_expectation(converted_subject, type)
27
+ syntax << " #{source_builder.replacement_matcher_source}"
28
+ end
29
+ end
30
+
31
+ def build_expectation(subject, type)
32
+ case type
33
+ when :should
34
+ syntax = "#{subject}.should"
35
+ syntax << '_not' unless positive?
36
+ when :expect
37
+ syntax = "expect(#{subject})."
38
+ syntax << (positive? ? 'to' : 'not_to')
39
+ end
40
+
41
+ syntax
42
+ end
43
+
44
+ def positive?
45
+ have.expectation.positive?
46
+ end
47
+
48
+ def original_subject
49
+ if have.subject_is_owner_of_collection?
50
+ 'obj'
51
+ else
52
+ 'collection'
53
+ end
54
+ end
55
+
56
+ def original_items
57
+ if have.subject_is_owner_of_collection?
58
+ if have.items_method_has_arguments?
59
+ "#{have.collection_accessor}(...)"
60
+ else
61
+ have.collection_accessor
62
+ end
63
+ else
64
+ 'items'
65
+ end
66
+ end
67
+
68
+ def converted_subject
69
+ if @have.subject_is_owner_of_collection?
70
+ build_converted_subject('obj')
71
+ else
72
+ build_converted_subject('collection')
73
+ end
74
+ end
75
+
76
+ def build_converted_subject(subject)
77
+ if have.subject_is_owner_of_collection?
78
+ converted_owner_of_collection(subject)
79
+ else
80
+ subject << ".#{have.default_query_method}"
81
+ end
82
+ end
83
+
84
+ def converted_owner_of_collection(subject)
85
+ subject << '.'
86
+
87
+ if have.collection_accessor_is_private?
88
+ subject << "send(#{have.collection_accessor.inspect}"
89
+ subject << ', ...' if have.items_method_has_arguments?
90
+ subject << ')'
91
+ else
92
+ subject << "#{have.collection_accessor}"
93
+ subject << '(...)' if have.items_method_has_arguments?
94
+ end
95
+
96
+ subject << ".#{have.query_method}"
97
+ end
98
+
99
+ def source_builder
100
+ @source_builder ||= SourceBuilder.new(have, 'n')
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,78 @@
1
+ # coding: utf-8
2
+
3
+ require 'transpec/syntax/have'
4
+
5
+ module Transpec
6
+ class Syntax
7
+ class Have
8
+ class SourceBuilder
9
+ attr_reader :have, :size_source
10
+
11
+ def initialize(have, size_source)
12
+ @have = have
13
+ @size_source = size_source
14
+ end
15
+
16
+ def replacement_subject_source(original_subject_source)
17
+ source = original_subject_source
18
+ if have.subject_is_owner_of_collection?
19
+ if have.collection_accessor_is_private?
20
+ source << ".send(#{have.collection_accessor.inspect}"
21
+ if have.items_method_has_arguments?
22
+ source << ", #{collection_accessor_args_body_source}"
23
+ end
24
+ source << ')'
25
+ else
26
+ source << ".#{have.collection_accessor}#{collection_accessor_args_parentheses_source}"
27
+ end
28
+ end
29
+ source << ".#{have.query_method}"
30
+ end
31
+
32
+ def replacement_matcher_source(parenthesize_arg = true)
33
+ case have.expectation.current_syntax_type
34
+ when :should
35
+ replacement_matcher_source_for_should
36
+ when :expect
37
+ replacement_matcher_source_for_expect(parenthesize_arg)
38
+ end
39
+ end
40
+
41
+ def replacement_matcher_source_for_should
42
+ case have.method_name
43
+ when :have, :have_exactly then "== #{size_source}"
44
+ when :have_at_least then ">= #{size_source}"
45
+ when :have_at_most then "<= #{size_source}"
46
+ end
47
+ end
48
+
49
+ def replacement_matcher_source_for_expect(parenthesize_arg)
50
+ case have.method_name
51
+ when :have, :have_exactly
52
+ if parenthesize_arg
53
+ "eq(#{size_source})"
54
+ else
55
+ "eq #{size_source}"
56
+ end
57
+ when :have_at_least
58
+ "be >= #{size_source}"
59
+ when :have_at_most
60
+ "be <= #{size_source}"
61
+ end
62
+ end
63
+
64
+ def collection_accessor_args_parentheses_source
65
+ map = have.items_node.loc
66
+ range = map.selector.end.join(map.expression.end)
67
+ range.source
68
+ end
69
+
70
+ def collection_accessor_args_body_source
71
+ arg_nodes = have.items_node.children[2..-1]
72
+ range = arg_nodes.first.loc.expression.begin.join(arg_nodes.last.loc.expression.end)
73
+ range.source
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -13,7 +13,7 @@ module Transpec
13
13
  receiver_node.nil? && method_name == :its
14
14
  end
15
15
 
16
- add_dynamic_analysis_request do |rewriter|
16
+ define_dynamic_analysis_request do |rewriter|
17
17
  key = :project_requires_its?
18
18
  code = 'defined?(RSpec::Its)'
19
19
  rewriter.register_request(@node, key, code, :context)
@@ -42,7 +42,7 @@ module Transpec
42
42
  !receiver_node.nil? && [:stub, :stub!, :stub_chain, :unstub, :unstub!].include?(method_name)
43
43
  end
44
44
 
45
- add_dynamic_analysis_request do |rewriter|
45
+ define_dynamic_analysis_request do |rewriter|
46
46
  register_request_of_syntax_availability_inspection(
47
47
  rewriter,
48
48
  :allow_to_receive_available?,
@@ -13,7 +13,7 @@ module Transpec
13
13
  include Send
14
14
 
15
15
  included do
16
- add_dynamic_analysis_request do |rewriter|
16
+ define_dynamic_analysis_request do |rewriter|
17
17
  if Receive.dynamic_analysis_target_node?(matcher_node)
18
18
  create_receive_matcher.register_request_for_dynamic_analysis(rewriter)
19
19
  end
@@ -10,7 +10,7 @@ module Transpec
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  included do
13
- add_dynamic_analysis_request do |rewriter|
13
+ define_dynamic_analysis_request do |rewriter|
14
14
  if Have.dynamic_analysis_target_node?(matcher_node)
15
15
  create_have_matcher.register_request_for_dynamic_analysis(rewriter)
16
16
  end
@@ -12,7 +12,7 @@ module Transpec
12
12
  include MonkeyPatch, ::AST::Sexp
13
13
 
14
14
  included do
15
- add_dynamic_analysis_request do |rewriter|
15
+ define_dynamic_analysis_request do |rewriter|
16
16
  code = <<-END.gsub(/^\s+\|/, '').chomp
17
17
  |if self.class.name == 'RSpec::Mocks::AnyInstance::Recorder'
18
18
  | if respond_to?(:klass)
@@ -45,7 +45,7 @@ module Transpec
45
45
  end
46
46
 
47
47
  included do
48
- add_dynamic_analysis_request do |rewriter|
48
+ define_dynamic_analysis_request do |rewriter|
49
49
  if receiver_node
50
50
  target_node = receiver_node
51
51
  target_object_type = :object
@@ -14,7 +14,7 @@ module Transpec
14
14
  include Send, HaveMatcherOwner
15
15
 
16
16
  included do
17
- add_dynamic_analysis_request do |rewriter|
17
+ define_dynamic_analysis_request do |rewriter|
18
18
  if OperatorMatcher.dynamic_analysis_target_node?(matcher_node)
19
19
  create_operator_matcher.register_request_for_dynamic_analysis(rewriter)
20
20
  end
@@ -38,7 +38,7 @@ module Transpec
38
38
 
39
39
  insert_example_description!
40
40
 
41
- subject_source = have_matcher.build_replacement_subject_source('subject')
41
+ subject_source = have_matcher.replacement_subject_source('subject')
42
42
  insert_before(expression_range, "#{subject_source}.")
43
43
 
44
44
  have_matcher.convert_to_standard_expectation!
@@ -53,7 +53,7 @@ module Transpec
53
53
 
54
54
  insert_example_description!
55
55
 
56
- subject_source = have_matcher.build_replacement_subject_source('subject')
56
+ subject_source = have_matcher.replacement_subject_source('subject')
57
57
  expect_to_source = "expect(#{subject_source})."
58
58
  expect_to_source << (positive? ? 'to' : negative_form)
59
59
  replace(should_range, expect_to_source)
@@ -72,7 +72,7 @@ module Transpec
72
72
  def build_description(size)
73
73
  description = positive? ? 'has ' : 'does not have '
74
74
 
75
- case have_matcher.have_method_name
75
+ case have_matcher.method_name
76
76
  when :have_at_least then description << 'at least '
77
77
  when :have_at_most then description << 'at most '
78
78
  end
@@ -161,17 +161,19 @@ module Transpec
161
161
  end
162
162
 
163
163
  class OnelinerShouldHaveRecord < Have::HaveRecord
164
+ attr_reader :should, :negative_form_of_to
165
+
164
166
  def initialize(should, have, negative_form_of_to = nil)
167
+ super(have)
165
168
  @should = should
166
- @have = have
167
169
  @negative_form_of_to = negative_form_of_to
168
170
  end
169
171
 
170
172
  def original_syntax
171
173
  @original_syntax ||= begin
172
- syntax = @should.example_has_description? ? "it '...' do" : 'it {'
173
- syntax << " #{@should.method_name} #{@have.have_method_name}(n).#{original_items} "
174
- syntax << (@should.example_has_description? ? 'end' : '}')
174
+ syntax = should.example_has_description? ? "it '...' do" : 'it {'
175
+ syntax << " #{should.method_name} #{have.method_name}(n).#{original_items} "
176
+ syntax << (should.example_has_description? ? 'end' : '}')
175
177
  end
176
178
  end
177
179
 
@@ -181,25 +183,25 @@ module Transpec
181
183
  syntax << ' '
182
184
  syntax << converted_expectation
183
185
  syntax << ' '
184
- syntax << @have.build_replacement_matcher_source('n')
186
+ syntax << source_builder.replacement_matcher_source
185
187
  syntax << ' end'
186
188
  end
187
189
  end
188
190
 
189
191
  def converted_description
190
- if @should.example_has_description?
192
+ if should.example_has_description?
191
193
  "it '...' do"
192
194
  else
193
- "it '#{@should.build_description('n')}' do"
195
+ "it '#{should.build_description('n')}' do"
194
196
  end
195
197
  end
196
198
 
197
199
  def converted_expectation
198
- case @should.current_syntax_type
200
+ case should.current_syntax_type
199
201
  when :should
200
- "#{converted_subject}.#{@should.method_name}"
202
+ "#{converted_subject}.#{should.method_name}"
201
203
  when :expect
202
- "expect(#{converted_subject})." + (@should.positive? ? 'to' : @negative_form_of_to)
204
+ "expect(#{converted_subject})." + (should.positive? ? 'to' : negative_form_of_to)
203
205
  end
204
206
  end
205
207
 
@@ -26,7 +26,7 @@ module Transpec
26
26
  check_target_node_dynamically(node, runtime_data)
27
27
  end
28
28
 
29
- add_dynamic_analysis_request do |rewriter|
29
+ define_dynamic_analysis_request do |rewriter|
30
30
  if method_name == :=~
31
31
  rewriter.register_request(arg_node, :arg_is_enumerable?, 'is_a?(Enumerable)')
32
32
  end
@@ -22,7 +22,7 @@ module Transpec
22
22
  @current_syntax_type = :should
23
23
  end
24
24
 
25
- add_dynamic_analysis_request do |rewriter|
25
+ define_dynamic_analysis_request do |rewriter|
26
26
  register_request_of_syntax_availability_inspection(
27
27
  rewriter,
28
28
  :expect_available?,
@@ -17,7 +17,7 @@ module Transpec
17
17
  !receiver_node.nil? && [:should_receive, :should_not_receive].include?(method_name)
18
18
  end
19
19
 
20
- add_dynamic_analysis_request do |rewriter|
20
+ define_dynamic_analysis_request do |rewriter|
21
21
  register_request_of_syntax_availability_inspection(
22
22
  rewriter,
23
23
  :expect_to_receive_available?,
data/lib/transpec/util.rb CHANGED
@@ -84,7 +84,7 @@ module Transpec
84
84
  loop do
85
85
  child_node = parent_node.children.first
86
86
 
87
- return unless child_node
87
+ return if !child_node || !child_node.is_a?(AST::Node)
88
88
  return unless [:send, :block].include?(child_node.type)
89
89
 
90
90
  if mode == :parent_as_second_arg
@@ -5,7 +5,7 @@ module Transpec
5
5
  module Version
6
6
  MAJOR = 1
7
7
  MINOR = 9
8
- PATCH = 0
8
+ PATCH = 1
9
9
 
10
10
  def self.to_s
11
11
  [MAJOR, MINOR, PATCH].join('.')
data/spec/spec_helper.rb CHANGED
@@ -26,20 +26,21 @@ RSpec.configure do |config|
26
26
  end
27
27
  end
28
28
 
29
- require 'simplecov'
30
- SimpleCov.coverage_dir(File.join('spec', 'coverage'))
31
-
32
- if ENV['TRAVIS']
33
- require 'coveralls'
34
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
35
- elsif ENV['CI']
36
- require 'simplecov-rcov'
37
- SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
38
- end
29
+ if ENV['TRAVIS'] || ENV['CI'] || ENV['COVERAGE']
30
+ require 'simplecov'
31
+
32
+ if ENV['TRAVIS']
33
+ require 'coveralls'
34
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
35
+ elsif ENV['CI']
36
+ require 'simplecov-rcov'
37
+ SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
38
+ end
39
39
 
40
- SimpleCov.start do
41
- add_filter '/spec/'
42
- add_filter '/vendor/bundle/'
40
+ SimpleCov.start do
41
+ add_filter '/spec/'
42
+ add_filter '/vendor/bundle/'
43
+ end
43
44
  end
44
45
 
45
46
  Dir[File.join(File.dirname(__FILE__), 'support', '*')].each do |path|
@@ -47,6 +47,22 @@ module Transpec
47
47
  end
48
48
  end
49
49
 
50
+ describe '#each_forward_chained_node' do
51
+ context 'when a non-send node is passed' do
52
+ let(:source) { ':foo' }
53
+
54
+ it 'does not yield' do
55
+ yielded = false
56
+
57
+ Util.each_forward_chained_node(ast) do
58
+ yielded = true
59
+ end
60
+
61
+ yielded.should be_false
62
+ end
63
+ end
64
+ end
65
+
50
66
  describe '#expand_range_to_adjacent_whitespaces' do
51
67
  let(:node) { ast.each_node.find(&:block_type?) }
52
68
  let(:range) { node.loc.begin }
@@ -28,7 +28,7 @@ class TranspecDemo < TranspecTest
28
28
  def run_demo(transpec_args = [])
29
29
  in_project_dir do
30
30
  with_clean_bundler_env do
31
- sh File.join(Transpec.root, 'bin', 'transpec'), '--force'
31
+ sh File.join(Transpec.root, 'bin', 'transpec'), '--force', '--convert-stub-with-hash'
32
32
  sh 'bundle exec rspec'
33
33
  sh "git checkout --quiet -b #{DEMO_BRANCH}"
34
34
  sh 'git commit --all --file .git/COMMIT_EDITMSG'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transpec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Nakayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-08 00:00:00.000000000 Z
11
+ date: 2014-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -259,6 +259,9 @@ files:
259
259
  - lib/transpec/syntax/example.rb
260
260
  - lib/transpec/syntax/expect.rb
261
261
  - lib/transpec/syntax/have.rb
262
+ - lib/transpec/syntax/have/dynamic_inspector.rb
263
+ - lib/transpec/syntax/have/have_record.rb
264
+ - lib/transpec/syntax/have/source_builder.rb
262
265
  - lib/transpec/syntax/its.rb
263
266
  - lib/transpec/syntax/matcher_definition.rb
264
267
  - lib/transpec/syntax/method_stub.rb