transpec 1.5.0 → 1.5.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Guardfile +18 -14
- data/README.md +1 -1
- data/README.md.erb +1 -1
- data/lib/transpec/cli.rb +2 -2
- data/lib/transpec/context_error.rb +23 -0
- data/lib/transpec/converter.rb +5 -5
- data/lib/transpec/dynamic_analyzer/rewriter.rb +1 -2
- data/lib/transpec/report.rb +5 -5
- data/lib/transpec/rspec_version.rb +10 -7
- data/lib/transpec/syntax.rb +76 -49
- data/lib/transpec/syntax/expect.rb +2 -6
- data/lib/transpec/syntax/have.rb +1 -2
- data/lib/transpec/syntax/its.rb +1 -1
- data/lib/transpec/syntax/method_stub.rb +29 -3
- data/lib/transpec/syntax/mixin/any_instance.rb +19 -18
- data/lib/transpec/syntax/mixin/have_matcher_owner.rb +35 -0
- data/lib/transpec/syntax/mixin/send.rb +33 -33
- data/lib/transpec/syntax/mixin/should_base.rb +22 -8
- data/lib/transpec/syntax/oneliner_should.rb +2 -7
- data/lib/transpec/syntax/operator_matcher.rb +4 -3
- data/lib/transpec/syntax/should.rb +4 -9
- data/lib/transpec/syntax/should_receive.rb +3 -5
- data/lib/transpec/version.rb +1 -1
- data/spec/support/shared_context.rb +2 -3
- data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +1 -1
- data/spec/transpec/report_spec.rb +1 -2
- data/spec/transpec/rspec_version_spec.rb +7 -1
- data/spec/transpec/syntax/double_spec.rb +4 -4
- data/spec/transpec/syntax/example_spec.rb +1 -1
- data/spec/transpec/syntax/method_stub_spec.rb +65 -11
- data/spec/transpec/syntax/should_receive_spec.rb +14 -14
- data/spec/transpec/syntax/should_spec.rb +10 -10
- data/transpec.gemspec +2 -2
- metadata +6 -5
- data/lib/transpec/syntax/mixin/have_matcher.rb +0 -23
data/lib/transpec/syntax/its.rb
CHANGED
@@ -13,7 +13,7 @@ module Transpec
|
|
13
13
|
receiver_node.nil? && method_name == :its
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
add_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)
|
@@ -13,17 +13,43 @@ module Transpec
|
|
13
13
|
class MethodStub < Syntax
|
14
14
|
include Mixin::Send, Mixin::MonkeyPatch, Mixin::AllowNoMessage, Mixin::AnyInstance, Util
|
15
15
|
|
16
|
+
# rubocop:disable LineLength
|
17
|
+
CLASSES_DEFINING_OWN_STUB_METHOD = [
|
18
|
+
'Typhoeus', # https://github.com/typhoeus/typhoeus/blob/6a59c62/lib/typhoeus.rb#L66-L85
|
19
|
+
'Excon', # https://github.com/geemus/excon/blob/6af4f9c/lib/excon.rb#L143-L178
|
20
|
+
'Factory' # https://github.com/thoughtbot/factory_girl/blob/v3.6.2/lib/factory_girl/syntax/vintage.rb#L112
|
21
|
+
]
|
22
|
+
# rubocop:enable LineLength
|
23
|
+
|
24
|
+
def self.dynamic_analysis_target_node?(node)
|
25
|
+
target_node?(node)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.conversion_target_node?(node, runtime_data = nil)
|
29
|
+
return false unless check_target_node_statically(node)
|
30
|
+
|
31
|
+
# Check if the method is RSpec's one or not.
|
32
|
+
if source_location(node, runtime_data)
|
33
|
+
# If we have a source location runtime data, check with it.
|
34
|
+
check_target_node_dynamically(node, runtime_data)
|
35
|
+
else
|
36
|
+
# Otherwise check with a static whitelist.
|
37
|
+
receiver_node = node.children.first
|
38
|
+
const_name = Util.const_name(receiver_node)
|
39
|
+
!CLASSES_DEFINING_OWN_STUB_METHOD.include?(const_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
16
43
|
def self.target_method?(receiver_node, method_name)
|
17
44
|
!receiver_node.nil? && [:stub, :stub!, :stub_chain, :unstub, :unstub!].include?(method_name)
|
18
45
|
end
|
19
46
|
|
20
|
-
|
47
|
+
add_dynamic_analysis_request do |rewriter|
|
21
48
|
register_request_of_syntax_availability_inspection(
|
22
49
|
rewriter,
|
23
50
|
:allow_to_receive_available?,
|
24
51
|
[:allow, :receive]
|
25
52
|
)
|
26
|
-
register_request_of_any_instance_inspection(rewriter)
|
27
53
|
end
|
28
54
|
|
29
55
|
def allow_to_receive_available?
|
@@ -36,7 +62,7 @@ module Transpec
|
|
36
62
|
return if method_name == :stub_chain && !rspec_version.receive_message_chain_available?
|
37
63
|
|
38
64
|
unless allow_to_receive_available?
|
39
|
-
fail
|
65
|
+
fail ContextError.new(selector_range, "##{method_name}", '#allow')
|
40
66
|
end
|
41
67
|
|
42
68
|
source, type = replacement_source_and_conversion_type(rspec_version)
|
@@ -8,29 +8,30 @@ module Transpec
|
|
8
8
|
module AnyInstance
|
9
9
|
include ::AST::Sexp
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
11
|
+
def self.included(syntax)
|
12
|
+
syntax.add_dynamic_analysis_request do |rewriter|
|
13
|
+
key = :any_instance_target_class_name
|
14
|
+
code = <<-END.gsub(/^\s+\|/, '').chomp
|
15
|
+
|if self.class.name == 'RSpec::Mocks::AnyInstance::Recorder'
|
16
|
+
| if respond_to?(:klass)
|
17
|
+
| klass.name
|
18
|
+
| elsif instance_variable_defined?(:@klass)
|
19
|
+
| instance_variable_get(:@klass).name
|
20
|
+
| else
|
21
|
+
| nil
|
22
|
+
| end
|
23
|
+
|else
|
24
|
+
| nil
|
25
|
+
|end
|
26
|
+
END
|
27
|
+
rewriter.register_request(subject_node, key, code)
|
28
|
+
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def any_instance?
|
30
32
|
return true unless any_instance_target_node.nil?
|
31
33
|
node_data = runtime_node_data(subject_node)
|
32
|
-
return false unless node_data
|
33
|
-
return false unless node_data[:any_instance_target_class_name]
|
34
|
+
return false unless node_data && node_data[:any_instance_target_class_name]
|
34
35
|
!node_data[:any_instance_target_class_name].result.nil?
|
35
36
|
end
|
36
37
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/syntax/have'
|
4
|
+
|
5
|
+
module Transpec
|
6
|
+
class Syntax
|
7
|
+
module Mixin
|
8
|
+
module HaveMatcherOwner
|
9
|
+
def self.included(syntax)
|
10
|
+
syntax.add_dynamic_analysis_request do |rewriter|
|
11
|
+
if Have.dynamic_analysis_target_node?(matcher_node)
|
12
|
+
create_have_matcher.register_request_for_dynamic_analysis(rewriter)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def have_matcher
|
18
|
+
return @have_matcher if instance_variable_defined?(:@have_matcher)
|
19
|
+
|
20
|
+
@have_matcher ||= if Have.conversion_target_node?(matcher_node, @runtime_data)
|
21
|
+
create_have_matcher
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def create_have_matcher
|
30
|
+
Have.new(matcher_node, self, @source_rewriter, @runtime_data, @report)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,58 +1,42 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
3
5
|
module Transpec
|
4
6
|
class Syntax
|
5
7
|
module Mixin
|
6
8
|
module Send
|
7
|
-
|
8
|
-
klass.extend(ClassMethods)
|
9
|
-
end
|
9
|
+
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
-
def register_request_for_dynamic_analysis(node, rewriter)
|
13
|
-
return unless target_node?(node)
|
14
|
-
|
15
|
-
receiver_node, method_name, *_ = *node
|
16
|
-
|
17
|
-
if receiver_node
|
18
|
-
target_node = receiver_node
|
19
|
-
target_object_type = :object
|
20
|
-
else
|
21
|
-
target_node = node
|
22
|
-
target_object_type = :context
|
23
|
-
end
|
24
|
-
|
25
|
-
key = source_location_key(method_name)
|
26
|
-
code = "method(#{method_name.inspect}).source_location"
|
27
|
-
rewriter.register_request(target_node, key, code, target_object_type)
|
28
|
-
end
|
29
|
-
|
30
12
|
def target_node?(node, runtime_data = nil)
|
31
13
|
check_target_node_statically(node) && check_target_node_dynamically(node, runtime_data)
|
32
14
|
end
|
33
15
|
|
34
|
-
def target_method?(receiver_node, method_name)
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
16
|
def check_target_node_statically(node)
|
39
17
|
return false unless node && node.type == :send
|
40
18
|
receiver_node, method_name, *_ = *node
|
41
19
|
target_method?(receiver_node, method_name)
|
42
20
|
end
|
43
21
|
|
22
|
+
def target_method?(receiver_node, method_name)
|
23
|
+
NotImplementedError
|
24
|
+
end
|
25
|
+
|
44
26
|
def check_target_node_dynamically(node, runtime_data)
|
45
|
-
|
27
|
+
source_location = source_location(node, runtime_data)
|
28
|
+
return true unless source_location
|
29
|
+
file_path = source_location.first
|
30
|
+
!file_path.match(%r{/gems/rspec\-[^/]+/lib/rspec/}).nil?
|
31
|
+
end
|
46
32
|
|
33
|
+
def source_location(node, runtime_data)
|
34
|
+
return unless runtime_data
|
47
35
|
receiver_node, method_name, *_ = *node
|
48
36
|
target_node = receiver_node ? receiver_node : node
|
49
|
-
|
50
|
-
return
|
51
|
-
|
52
|
-
return true unless (source_location = eval_data.result)
|
53
|
-
|
54
|
-
file_path = source_location.first
|
55
|
-
!file_path.match(%r{/gems/rspec\-[^/]+/lib/rspec/}).nil?
|
37
|
+
return unless (node_data = runtime_data[target_node])
|
38
|
+
return unless (eval_data = node_data[source_location_key(method_name)])
|
39
|
+
eval_data.result
|
56
40
|
end
|
57
41
|
|
58
42
|
def source_location_key(method_name)
|
@@ -60,6 +44,22 @@ module Transpec
|
|
60
44
|
end
|
61
45
|
end
|
62
46
|
|
47
|
+
def self.included(syntax)
|
48
|
+
syntax.add_dynamic_analysis_request do |rewriter|
|
49
|
+
if receiver_node
|
50
|
+
target_node = receiver_node
|
51
|
+
target_object_type = :object
|
52
|
+
else
|
53
|
+
target_node = @node
|
54
|
+
target_object_type = :context
|
55
|
+
end
|
56
|
+
|
57
|
+
key = self.class.source_location_key(method_name)
|
58
|
+
code = "method(#{method_name.inspect}).source_location"
|
59
|
+
rewriter.register_request(target_node, key, code, target_object_type)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
63
|
def receiver_node
|
64
64
|
@node.children[0]
|
65
65
|
end
|
@@ -6,6 +6,14 @@ module Transpec
|
|
6
6
|
class Syntax
|
7
7
|
module Mixin
|
8
8
|
module ShouldBase
|
9
|
+
def self.included(syntax)
|
10
|
+
syntax.add_dynamic_analysis_request do |rewriter|
|
11
|
+
if OperatorMatcher.dynamic_analysis_target_node?(matcher_node)
|
12
|
+
create_operator_matcher.register_request_for_dynamic_analysis(rewriter)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
def positive?
|
10
18
|
method_name == :should
|
11
19
|
end
|
@@ -14,24 +22,30 @@ module Transpec
|
|
14
22
|
arg_node || parent_node
|
15
23
|
end
|
16
24
|
|
25
|
+
def should_range
|
26
|
+
if arg_node
|
27
|
+
selector_range
|
28
|
+
else
|
29
|
+
selector_range.join(expression_range.end)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
17
33
|
def operator_matcher
|
18
34
|
return @operator_matcher if instance_variable_defined?(:@operator_matcher)
|
19
35
|
|
20
36
|
@operator_matcher ||= begin
|
21
|
-
if OperatorMatcher.
|
22
|
-
|
37
|
+
if OperatorMatcher.conversion_target_node?(matcher_node, @runtime_data)
|
38
|
+
create_operator_matcher
|
23
39
|
else
|
24
40
|
nil
|
25
41
|
end
|
26
42
|
end
|
27
43
|
end
|
28
44
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
selector_range.join(expression_range.end)
|
34
|
-
end
|
45
|
+
private
|
46
|
+
|
47
|
+
def create_operator_matcher
|
48
|
+
OperatorMatcher.new(matcher_node, @source_rewriter, @runtime_data, @report)
|
35
49
|
end
|
36
50
|
end
|
37
51
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'transpec/syntax'
|
4
4
|
require 'transpec/syntax/mixin/should_base'
|
5
5
|
require 'transpec/syntax/mixin/send'
|
6
|
-
require 'transpec/syntax/mixin/
|
6
|
+
require 'transpec/syntax/mixin/have_matcher_owner'
|
7
7
|
require 'transpec/rspec_dsl'
|
8
8
|
require 'transpec/util'
|
9
9
|
require 'active_support/inflector/methods'
|
@@ -11,7 +11,7 @@ require 'active_support/inflector/methods'
|
|
11
11
|
module Transpec
|
12
12
|
class Syntax
|
13
13
|
class OnelinerShould < Syntax
|
14
|
-
include Mixin::ShouldBase, Mixin::Send, Mixin::
|
14
|
+
include Mixin::ShouldBase, Mixin::Send, Mixin::HaveMatcherOwner, RSpecDSL, Util
|
15
15
|
|
16
16
|
attr_reader :current_syntax_type
|
17
17
|
|
@@ -24,11 +24,6 @@ module Transpec
|
|
24
24
|
@current_syntax_type = :should
|
25
25
|
end
|
26
26
|
|
27
|
-
def register_request_for_dynamic_analysis(rewriter)
|
28
|
-
operator_matcher.register_request_for_dynamic_analysis(rewriter) if operator_matcher
|
29
|
-
have_matcher.register_request_for_dynamic_analysis(rewriter) if have_matcher
|
30
|
-
end
|
31
|
-
|
32
27
|
def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
|
33
28
|
replacement = 'is_expected.'
|
34
29
|
replacement << (positive? ? 'to' : negative_form)
|
@@ -20,9 +20,10 @@ module Transpec
|
|
20
20
|
!receiver_node.nil? && OPERATORS.include?(method_name)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
add_dynamic_analysis_request do |rewriter|
|
24
|
+
if method_name == :=~
|
25
|
+
rewriter.register_request(arg_node, :arg_is_enumerable?, 'is_a?(Enumerable)')
|
26
|
+
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def convert_operator!(parenthesize_arg = true)
|
@@ -5,14 +5,14 @@ require 'transpec/syntax/mixin/should_base'
|
|
5
5
|
require 'transpec/syntax/mixin/send'
|
6
6
|
require 'transpec/syntax/mixin/monkey_patch'
|
7
7
|
require 'transpec/syntax/mixin/expectizable'
|
8
|
-
require 'transpec/syntax/mixin/
|
8
|
+
require 'transpec/syntax/mixin/have_matcher_owner'
|
9
9
|
require 'transpec/util'
|
10
10
|
|
11
11
|
module Transpec
|
12
12
|
class Syntax
|
13
13
|
class Should < Syntax
|
14
14
|
include Mixin::ShouldBase, Mixin::Send, Mixin::MonkeyPatch, Mixin::Expectizable,
|
15
|
-
Mixin::
|
15
|
+
Mixin::HaveMatcherOwner, Util
|
16
16
|
|
17
17
|
attr_reader :current_syntax_type
|
18
18
|
|
@@ -25,15 +25,12 @@ module Transpec
|
|
25
25
|
@current_syntax_type = :should
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
add_dynamic_analysis_request do |rewriter|
|
29
29
|
register_request_of_syntax_availability_inspection(
|
30
30
|
rewriter,
|
31
31
|
:expect_available?,
|
32
32
|
[:expect]
|
33
33
|
)
|
34
|
-
|
35
|
-
operator_matcher.register_request_for_dynamic_analysis(rewriter) if operator_matcher
|
36
|
-
have_matcher.register_request_for_dynamic_analysis(rewriter) if have_matcher
|
37
34
|
end
|
38
35
|
|
39
36
|
def expect_available?
|
@@ -41,9 +38,7 @@ module Transpec
|
|
41
38
|
end
|
42
39
|
|
43
40
|
def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
|
44
|
-
unless expect_available?
|
45
|
-
fail InvalidContextError.new(selector_range, "##{method_name}", '#expect')
|
46
|
-
end
|
41
|
+
fail ContextError.new(selector_range, "##{method_name}", '#expect') unless expect_available?
|
47
42
|
|
48
43
|
if proc_literal?(subject_node)
|
49
44
|
replace(range_of_subject_method_taking_block, 'expect')
|
@@ -19,7 +19,7 @@ module Transpec
|
|
19
19
|
!receiver_node.nil? && [:should_receive, :should_not_receive].include?(method_name)
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
add_dynamic_analysis_request do |rewriter|
|
23
23
|
register_request_of_syntax_availability_inspection(
|
24
24
|
rewriter,
|
25
25
|
:expect_to_receive_available?,
|
@@ -31,8 +31,6 @@ module Transpec
|
|
31
31
|
:allow_to_receive_available?,
|
32
32
|
[:allow, :receive]
|
33
33
|
)
|
34
|
-
|
35
|
-
register_request_of_any_instance_inspection(rewriter)
|
36
34
|
end
|
37
35
|
|
38
36
|
def expect_to_receive_available?
|
@@ -49,7 +47,7 @@ module Transpec
|
|
49
47
|
|
50
48
|
def expectize!(negative_form = 'not_to')
|
51
49
|
unless expect_to_receive_available?
|
52
|
-
fail
|
50
|
+
fail ContextError.new(selector_range, "##{method_name}", '#expect')
|
53
51
|
end
|
54
52
|
|
55
53
|
convert_to_syntax!('expect', negative_form)
|
@@ -60,7 +58,7 @@ module Transpec
|
|
60
58
|
return unless useless_expectation?
|
61
59
|
|
62
60
|
unless allow_to_receive_available?
|
63
|
-
fail
|
61
|
+
fail ContextError.new(selector_range, "##{method_name}", '#allow')
|
64
62
|
end
|
65
63
|
|
66
64
|
convert_to_syntax!('allow', negative_form)
|
data/lib/transpec/version.rb
CHANGED
@@ -60,7 +60,7 @@ end
|
|
60
60
|
shared_context 'syntax object' do |syntax_class, name|
|
61
61
|
let(name) do
|
62
62
|
ast.each_node do |node|
|
63
|
-
next unless syntax_class.
|
63
|
+
next unless syntax_class.conversion_target_node?(node)
|
64
64
|
return syntax_class.new(node, source_rewriter, runtime_data)
|
65
65
|
end
|
66
66
|
|
@@ -70,6 +70,7 @@ end
|
|
70
70
|
|
71
71
|
shared_context 'isolated environment' do
|
72
72
|
around do |example|
|
73
|
+
require 'tmpdir'
|
73
74
|
Dir.mktmpdir do |tmpdir|
|
74
75
|
Dir.chdir(tmpdir) do
|
75
76
|
example.run
|
@@ -79,8 +80,6 @@ shared_context 'isolated environment' do
|
|
79
80
|
end
|
80
81
|
|
81
82
|
shared_context 'inside of git repository' do
|
82
|
-
require 'tmpdir'
|
83
|
-
|
84
83
|
around do |example|
|
85
84
|
Dir.mkdir('repo')
|
86
85
|
Dir.chdir('repo') do
|