mutant 0.1.1 → 0.2.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.
- data/.gitignore +5 -11
- data/.rspec +0 -1
- data/.travis.yml +14 -3
- data/Changelog.md +3 -0
- data/Gemfile +5 -1
- data/Gemfile.devtools +49 -0
- data/Guardfile +18 -0
- data/README.md +67 -0
- data/Rakefile +4 -1
- data/TODO +13 -0
- data/bin/mutant +14 -0
- data/bin/zombie +14 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/roodi.yml +26 -0
- data/config/site.reek +93 -0
- data/config/yardstick.yml +2 -0
- data/lib/inflector.rb +7 -0
- data/lib/inflector/defaults.rb +62 -0
- data/lib/inflector/inflections.rb +209 -0
- data/lib/inflector/methods.rb +149 -0
- data/lib/inflector/version.rb +3 -0
- data/lib/mutant.rb +96 -21
- data/lib/mutant/cli.rb +309 -0
- data/lib/mutant/color.rb +61 -0
- data/lib/mutant/context.rb +36 -0
- data/lib/mutant/context/scope.rb +138 -0
- data/lib/mutant/differ.rb +100 -0
- data/lib/mutant/helper.rb +38 -0
- data/lib/mutant/killer.rb +136 -0
- data/lib/mutant/killer/forking.rb +41 -0
- data/lib/mutant/killer/rspec.rb +49 -0
- data/lib/mutant/killer/static.rb +19 -0
- data/lib/mutant/loader.rb +129 -0
- data/lib/mutant/matcher.rb +55 -0
- data/lib/mutant/matcher/chain.rb +66 -0
- data/lib/mutant/matcher/method.rb +173 -0
- data/lib/mutant/matcher/method/classifier.rb +126 -0
- data/lib/mutant/matcher/method/instance.rb +67 -0
- data/lib/mutant/matcher/method/singleton.rb +141 -0
- data/lib/mutant/matcher/object_space.rb +114 -0
- data/lib/mutant/matcher/scope_methods.rb +127 -0
- data/lib/mutant/mutation.rb +101 -12
- data/lib/mutant/mutation/filter.rb +75 -0
- data/lib/mutant/mutation/filter/code.rb +68 -0
- data/lib/mutant/mutation/filter/regexp.rb +39 -0
- data/lib/mutant/mutation/filter/whitelist.rb +47 -0
- data/lib/mutant/mutator.rb +134 -30
- data/lib/mutant/mutator/node.rb +163 -0
- data/lib/mutant/mutator/node/arguments.rb +24 -0
- data/lib/mutant/mutator/node/block.rb +24 -0
- data/lib/mutant/mutator/node/define.rb +24 -0
- data/lib/mutant/mutator/node/if_statement.rb +93 -0
- data/lib/mutant/mutator/node/literal.rb +54 -0
- data/lib/mutant/mutator/node/literal/array.rb +28 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +49 -0
- data/lib/mutant/mutator/node/literal/dynamic.rb +24 -0
- data/lib/mutant/mutator/node/literal/empty_array.rb +26 -0
- data/lib/mutant/mutator/node/literal/fixnum.rb +37 -0
- data/lib/mutant/mutator/node/literal/float.rb +48 -0
- data/lib/mutant/mutator/node/literal/hash.rb +89 -0
- data/lib/mutant/mutator/node/literal/nil.rb +25 -0
- data/lib/mutant/mutator/node/literal/range.rb +94 -0
- data/lib/mutant/mutator/node/literal/regex.rb +43 -0
- data/lib/mutant/mutator/node/literal/string.rb +26 -0
- data/lib/mutant/mutator/node/literal/symbol.rb +26 -0
- data/lib/mutant/mutator/node/noop.rb +55 -0
- data/lib/mutant/mutator/node/receiver_case.rb +140 -0
- data/lib/mutant/mutator/node/return.rb +31 -0
- data/lib/mutant/mutator/node/send.rb +112 -0
- data/lib/mutant/mutator/registry.rb +48 -0
- data/lib/mutant/mutator/util.rb +87 -0
- data/lib/mutant/random.rb +24 -27
- data/lib/mutant/reporter.rb +48 -30
- data/lib/mutant/reporter/cli.rb +221 -0
- data/lib/mutant/reporter/null.rb +42 -0
- data/lib/mutant/reporter/stats.rb +64 -0
- data/lib/mutant/runner.rb +112 -0
- data/lib/mutant/strategy.rb +42 -0
- data/lib/mutant/strategy/rspec.rb +59 -0
- data/lib/mutant/strategy/rspec/example_lookup.rb +122 -0
- data/lib/mutant/subject.rb +115 -0
- data/lib/mutant/support/method_object.rb +31 -0
- data/locator.rb +87 -0
- data/mutant.gemspec +21 -21
- data/spec/integration/mutant/differ_spec.rb +15 -0
- data/spec/integration/mutant/loader_spec.rb +21 -0
- data/spec/integration/mutant/method_matching_spec.rb +269 -0
- data/spec/integration/mutant/rspec_killer_spec.rb +24 -0
- data/spec/integration/mutant/runner_spec.rb +26 -0
- data/spec/integration/mutant/zombie_spec.rb +8 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/command_method_behavior.rb +7 -0
- data/spec/shared/each_method_behaviour.rb +15 -0
- data/spec/shared/hash_method_behavior.rb +17 -0
- data/spec/shared/idempotent_method_behavior.rb +7 -0
- data/spec/shared/invertible_method_behaviour.rb +9 -0
- data/spec/shared/method_filter_parse_behavior.rb +16 -0
- data/spec/shared/method_match_behavior.rb +39 -0
- data/spec/shared/mutator_behavior.rb +46 -0
- data/spec/spec_helper.rb +11 -14
- data/spec/support/compress_helper.rb +10 -0
- data/spec/support/rspec.rb +22 -0
- data/spec/support/test_app.rb +5 -0
- data/spec/support/zombie.rb +141 -0
- data/spec/unit/mutant/cli/class_methods/new_spec.rb +87 -0
- data/spec/unit/mutant/cli/class_methods/run_spec.rb +38 -0
- data/spec/unit/mutant/context/root_spec.rb +11 -0
- data/spec/unit/mutant/context/scope/class_methods/build_spec.rb +29 -0
- data/spec/unit/mutant/context/scope/root_spec.rb +22 -0
- data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +27 -0
- data/spec/unit/mutant/killer/fail_ques_spec.rb +39 -0
- data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +32 -0
- data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +33 -0
- data/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb +42 -0
- data/spec/unit/mutant/matcher/chain/each_spec.rb +37 -0
- data/spec/unit/mutant/matcher/chain/matchers_spec.rb +12 -0
- data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +49 -0
- data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +12 -0
- data/spec/unit/mutant/matcher/each_spec.rb +14 -0
- data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +21 -0
- data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +34 -0
- data/spec/unit/mutant/matcher/method/method_spec.rb +11 -0
- data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +24 -0
- data/spec/unit/mutant/matcher/object_space/each_spec.rb +31 -0
- data/spec/unit/mutant/mutator/each_spec.rb +25 -0
- data/spec/unit/mutant/mutator/emit_new_spec.rb +51 -0
- data/spec/unit/mutant/mutator/emit_spec.rb +52 -0
- data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +36 -0
- data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +47 -0
- data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +30 -0
- data/spec/unit/mutant/mutator/node/literal/array_spec.rb +30 -0
- data/spec/unit/mutant/mutator/node/literal/boolean/mutation_spec.rb +23 -0
- data/spec/unit/mutant/mutator/node/literal/empty_array_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +25 -0
- data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +34 -0
- data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +13 -0
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +35 -0
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +23 -0
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +27 -0
- data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +21 -0
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +78 -0
- data/spec/unit/mutant/mutator/self_spec.rb +7 -0
- data/spec/unit/mutant/subject/class_methods/new_spec.rb +13 -0
- data/spec/unit/mutant/subject/context_spec.rb +14 -0
- data/spec/unit/mutant/subject/each_spec.rb +35 -0
- data/spec/unit/mutant/subject/node_spec.rb +13 -0
- data/tasks/metrics/ci.rake +7 -0
- data/tasks/metrics/flay.rake +41 -0
- data/tasks/metrics/flog.rake +43 -0
- data/tasks/metrics/heckle.rake +216 -0
- data/tasks/metrics/metric_fu.rake +31 -0
- data/tasks/metrics/reek.rake +15 -0
- data/tasks/metrics/roodi.rake +15 -0
- data/tasks/metrics/yardstick.rake +23 -0
- data/tasks/spec.rake +45 -0
- data/tasks/yard.rake +9 -0
- data/test_app/.rspec +1 -0
- data/test_app/lib/test_app.rb +5 -0
- data/test_app/lib/test_app/literal.rb +32 -0
- data/test_app/spec/shared/command_method_behavior.rb +7 -0
- data/test_app/spec/shared/each_method_behaviour.rb +15 -0
- data/test_app/spec/shared/hash_method_behavior.rb +17 -0
- data/test_app/spec/shared/idempotent_method_behavior.rb +7 -0
- data/test_app/spec/shared/invertible_method_behaviour.rb +9 -0
- data/test_app/spec/shared/method_filter_parse_behavior.rb +16 -0
- data/test_app/spec/shared/method_match_behavior.rb +39 -0
- data/test_app/spec/shared/mutator_behavior.rb +44 -0
- data/test_app/spec/spec_helper.rb +7 -0
- data/test_app/spec/unit/test_app/literal/command_spec.rb +9 -0
- data/test_app/spec/unit/test_app/literal/string_spec.rb +9 -0
- metadata +346 -124
- data/.rvmrc +0 -1
- data/Readme.md +0 -13
- data/exe/mutate +0 -6
- data/lib/mutant/extensions.rb +0 -8
- data/lib/mutant/formatter.rb +0 -19
- data/lib/mutant/implementation.rb +0 -70
- data/lib/mutant/literal.rb +0 -147
- data/lib/mutant/method.rb +0 -31
- data/lib/mutant/mutatee.rb +0 -61
- data/lib/mutant/node.rb +0 -26
- data/lib/mutant/runners/rspec.rb +0 -34
- data/lib/mutant/version.rb +0 -3
- data/spec/functional/class_spec.rb +0 -46
- data/spec/functional/instance_method/array_spec.rb +0 -53
- data/spec/functional/instance_method/boolean_spec.rb +0 -101
- data/spec/functional/instance_method/call_spec.rb +0 -161
- data/spec/functional/instance_method/fixnum_spec.rb +0 -53
- data/spec/functional/instance_method/float_spec.rb +0 -53
- data/spec/functional/instance_method/hash_spec.rb +0 -53
- data/spec/functional/instance_method/if_spec.rb +0 -57
- data/spec/functional/instance_method/ivar_assign_spec.rb +0 -62
- data/spec/functional/instance_method/range_spec.rb +0 -53
- data/spec/functional/instance_method/regex_spec.rb +0 -55
- data/spec/functional/instance_method/string_spec.rb +0 -53
- data/spec/functional/instance_method/symbol_spec.rb +0 -53
- data/spec/functional/reporter/method_loaded_spec.rb +0 -62
- data/spec/functional/reporter/running_mutations_spec.rb +0 -60
- data/spec/functional/runners/rspec_spec.rb +0 -26
- data/spec/functional/singleton_method/array_spec.rb +0 -53
- data/spec/functional/singleton_method/boolean_spec.rb +0 -101
- data/spec/functional/singleton_method/call_spec.rb +0 -161
- data/spec/functional/singleton_method/fixnum_spec.rb +0 -53
- data/spec/functional/singleton_method/float_spec.rb +0 -53
- data/spec/functional/singleton_method/hash_spec.rb +0 -53
- data/spec/functional/singleton_method/if_spec.rb +0 -57
- data/spec/functional/singleton_method/ivar_assign_spec.rb +0 -60
- data/spec/functional/singleton_method/range_spec.rb +0 -53
- data/spec/functional/singleton_method/regex_spec.rb +0 -55
- data/spec/functional/singleton_method/string_spec.rb +0 -53
- data/spec/functional/singleton_method/symbol_spec.rb +0 -53
- data/spec/mutant/extensions_spec.rb +0 -13
- data/spec/mutant/implementation_spec.rb +0 -223
- data/spec/mutant/literal_spec.rb +0 -129
- data/spec/mutant/mutatee_spec.rb +0 -28
- data/spec/mutant/node_spec.rb +0 -41
- data/spec/mutant/random_spec.rb +0 -33
- data/spec/mutant/reporter_spec.rb +0 -17
- data/spec/mutant_spec.rb +0 -28
- data/spec/support/example_group_helpers.rb +0 -11
- data/spec/support/example_helpers.rb +0 -5
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
# Abstract matcher to find ASTs to mutate
|
|
3
|
+
class Matcher
|
|
4
|
+
include Adamantium::Flat, Enumerable, AbstractType
|
|
5
|
+
extend DescendantsTracker
|
|
6
|
+
|
|
7
|
+
# Enumerate subjects
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
#
|
|
11
|
+
# @return [undefined]
|
|
12
|
+
#
|
|
13
|
+
abstract_method :each
|
|
14
|
+
|
|
15
|
+
# Return identification
|
|
16
|
+
#
|
|
17
|
+
# @return [String
|
|
18
|
+
#
|
|
19
|
+
# @api private
|
|
20
|
+
#
|
|
21
|
+
abstract_method :identification
|
|
22
|
+
|
|
23
|
+
# Return matcher
|
|
24
|
+
#
|
|
25
|
+
# @param [String] input
|
|
26
|
+
#
|
|
27
|
+
# @return [nil]
|
|
28
|
+
# returns nil as default implementation
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
#
|
|
32
|
+
def self.parse(input)
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Return match from string
|
|
37
|
+
#
|
|
38
|
+
# @param [String] input
|
|
39
|
+
#
|
|
40
|
+
# @return [Matcher]
|
|
41
|
+
# returns matcher input if successful
|
|
42
|
+
#
|
|
43
|
+
# @return [nil]
|
|
44
|
+
# returns nil otherwise
|
|
45
|
+
#
|
|
46
|
+
def self.from_string(input)
|
|
47
|
+
descendants.each do |descendant|
|
|
48
|
+
matcher = descendant.parse(input)
|
|
49
|
+
return matcher if matcher
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
class Matcher
|
|
3
|
+
# A chain of matchers
|
|
4
|
+
class Chain < self
|
|
5
|
+
include Equalizer.new(:matchers)
|
|
6
|
+
|
|
7
|
+
# Enumerate subjects
|
|
8
|
+
#
|
|
9
|
+
# @return [Enumerator<Subject]
|
|
10
|
+
# returns subject enumerator if no block given
|
|
11
|
+
#
|
|
12
|
+
# @return [self]
|
|
13
|
+
# returnns self otherwise
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
#
|
|
17
|
+
def each(&block)
|
|
18
|
+
return to_enum unless block_given?
|
|
19
|
+
|
|
20
|
+
matchers.each do |matcher|
|
|
21
|
+
matcher.each(&block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Return the chain of matchers
|
|
28
|
+
#
|
|
29
|
+
# @return [Enumerable<Chain>]
|
|
30
|
+
#
|
|
31
|
+
# @api private
|
|
32
|
+
#
|
|
33
|
+
attr_reader :matchers
|
|
34
|
+
|
|
35
|
+
# Build matcher chain
|
|
36
|
+
#
|
|
37
|
+
# @param [Enumerable<Matcher>] matchers
|
|
38
|
+
#
|
|
39
|
+
# @return [Matcher]
|
|
40
|
+
#
|
|
41
|
+
# @api private
|
|
42
|
+
#
|
|
43
|
+
def self.build(matchers)
|
|
44
|
+
if matchers.length == 1
|
|
45
|
+
return matchers.first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
new(matchers)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# Initialize chain matcher
|
|
54
|
+
#
|
|
55
|
+
# @param [Enumerable<Matcher>] matchers
|
|
56
|
+
#
|
|
57
|
+
# @return [undefined]
|
|
58
|
+
#
|
|
59
|
+
# @api private
|
|
60
|
+
#
|
|
61
|
+
def initialize(matchers)
|
|
62
|
+
@matchers = matchers
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
class Matcher
|
|
3
|
+
# Matcher for subjects that are a specific method
|
|
4
|
+
class Method < self
|
|
5
|
+
include Adamantium::Flat, Equalizer.new(:identification)
|
|
6
|
+
|
|
7
|
+
# Parse a method string into filter
|
|
8
|
+
#
|
|
9
|
+
# @param [String] input
|
|
10
|
+
#
|
|
11
|
+
# @return [Matcher::Method]
|
|
12
|
+
#
|
|
13
|
+
# @api private
|
|
14
|
+
#
|
|
15
|
+
def self.parse(input)
|
|
16
|
+
Classifier.run(input)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Enumerate matches
|
|
20
|
+
#
|
|
21
|
+
# @return [Enumerable]
|
|
22
|
+
# returns enumerable when no block given
|
|
23
|
+
#
|
|
24
|
+
# @return [self]
|
|
25
|
+
# returns self when block given
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
#
|
|
29
|
+
def each(&block)
|
|
30
|
+
return to_enum unless block_given?
|
|
31
|
+
subject.tap do |subject|
|
|
32
|
+
yield subject if subject
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Return scope
|
|
39
|
+
#
|
|
40
|
+
# @return [Class|Module]
|
|
41
|
+
#
|
|
42
|
+
# @api private
|
|
43
|
+
#
|
|
44
|
+
attr_reader :scope
|
|
45
|
+
|
|
46
|
+
# Return context
|
|
47
|
+
#
|
|
48
|
+
# @return [Context::Scope]
|
|
49
|
+
#
|
|
50
|
+
# @api private
|
|
51
|
+
#
|
|
52
|
+
attr_reader :context
|
|
53
|
+
|
|
54
|
+
# Return method name
|
|
55
|
+
#
|
|
56
|
+
# @return [String]
|
|
57
|
+
#
|
|
58
|
+
# @api private
|
|
59
|
+
#
|
|
60
|
+
attr_reader :method_name
|
|
61
|
+
|
|
62
|
+
# Test if method is public
|
|
63
|
+
#
|
|
64
|
+
# @return [true]
|
|
65
|
+
# if method is public
|
|
66
|
+
#
|
|
67
|
+
# @retur [false]
|
|
68
|
+
# otherwise
|
|
69
|
+
#
|
|
70
|
+
# @api private
|
|
71
|
+
#
|
|
72
|
+
abstract_method :public?
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
# Initialize method filter
|
|
77
|
+
#
|
|
78
|
+
# @param [Class|Module] scope
|
|
79
|
+
# @param [Symbol] method_name
|
|
80
|
+
#
|
|
81
|
+
# @return [undefined]
|
|
82
|
+
#
|
|
83
|
+
# @api private
|
|
84
|
+
#
|
|
85
|
+
def initialize(scope, method_name)
|
|
86
|
+
@scope, @method_name = scope, method_name.to_sym
|
|
87
|
+
@context = Context::Scope.build(scope, source_path)
|
|
88
|
+
# FIXME: cache public private should not be needed, loader should not override visibility! (But does currently) :(
|
|
89
|
+
public?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Return method
|
|
93
|
+
#
|
|
94
|
+
# @return [UnboundMethod, Method]
|
|
95
|
+
#
|
|
96
|
+
# @api private
|
|
97
|
+
#
|
|
98
|
+
abstract_method :method
|
|
99
|
+
|
|
100
|
+
# Return full ast
|
|
101
|
+
#
|
|
102
|
+
# @return [Rubinius::AST::Node]
|
|
103
|
+
#
|
|
104
|
+
# @api private
|
|
105
|
+
#
|
|
106
|
+
def ast
|
|
107
|
+
File.read(source_path).to_ast
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Return path to source
|
|
111
|
+
#
|
|
112
|
+
# @return [String]
|
|
113
|
+
#
|
|
114
|
+
# @api private
|
|
115
|
+
#
|
|
116
|
+
def source_path
|
|
117
|
+
source_location.first
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Return source file line
|
|
121
|
+
#
|
|
122
|
+
# @return [Integer]
|
|
123
|
+
#
|
|
124
|
+
# @api private
|
|
125
|
+
#
|
|
126
|
+
def source_line
|
|
127
|
+
source_location.last
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Return source location
|
|
131
|
+
#
|
|
132
|
+
# @return [Array]
|
|
133
|
+
#
|
|
134
|
+
# @api private
|
|
135
|
+
#
|
|
136
|
+
def source_location
|
|
137
|
+
method.source_location
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Return subject
|
|
141
|
+
#
|
|
142
|
+
# @return [Subject]
|
|
143
|
+
# returns subject if there is a matched node
|
|
144
|
+
#
|
|
145
|
+
# @return [nil]
|
|
146
|
+
# otherwise
|
|
147
|
+
#
|
|
148
|
+
# @api private
|
|
149
|
+
#
|
|
150
|
+
def subject
|
|
151
|
+
node = matched_node
|
|
152
|
+
return unless node
|
|
153
|
+
Subject.new(self, context, node)
|
|
154
|
+
end
|
|
155
|
+
memoize :subject
|
|
156
|
+
|
|
157
|
+
# Return matched node
|
|
158
|
+
#
|
|
159
|
+
# @return [Rubinus::AST::Node]
|
|
160
|
+
#
|
|
161
|
+
# @api private
|
|
162
|
+
#
|
|
163
|
+
def matched_node
|
|
164
|
+
last_match = nil
|
|
165
|
+
ast.walk do |predicate, node|
|
|
166
|
+
last_match = node if match?(node)
|
|
167
|
+
predicate
|
|
168
|
+
end
|
|
169
|
+
last_match
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
class Matcher
|
|
3
|
+
class Method < self
|
|
4
|
+
# A classifier for input strings
|
|
5
|
+
class Classifier
|
|
6
|
+
include Adamantium::Flat
|
|
7
|
+
|
|
8
|
+
TABLE = {
|
|
9
|
+
'.' => Matcher::Method::Singleton,
|
|
10
|
+
'#' => Matcher::Method::Instance
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
SCOPE_FORMAT = /\A([^#.]+)(\.|#)(.+)\z/.freeze
|
|
14
|
+
|
|
15
|
+
# Positions of captured regexp groups
|
|
16
|
+
# Freezing fixnums to avoid their singleton classes are patched.
|
|
17
|
+
SCOPE_NAME_POSITION = 1.freeze
|
|
18
|
+
SCOPE_SYMBOL_POSITION = 2.freeze
|
|
19
|
+
METHOD_NAME_POSITION = 3.freeze
|
|
20
|
+
|
|
21
|
+
private_class_method :new
|
|
22
|
+
|
|
23
|
+
# Run classifier
|
|
24
|
+
#
|
|
25
|
+
# @param [String] input
|
|
26
|
+
#
|
|
27
|
+
# @return [Matcher::Method]
|
|
28
|
+
# returns matcher when input is in
|
|
29
|
+
#
|
|
30
|
+
# @return [nil]
|
|
31
|
+
# returns nil otherwise
|
|
32
|
+
#
|
|
33
|
+
# @api private
|
|
34
|
+
#
|
|
35
|
+
def self.run(input)
|
|
36
|
+
match = SCOPE_FORMAT.match(input)
|
|
37
|
+
return unless match
|
|
38
|
+
new(match).matcher
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Return method matcher
|
|
42
|
+
#
|
|
43
|
+
# @return [Matcher::Method]
|
|
44
|
+
#
|
|
45
|
+
# @api private
|
|
46
|
+
#
|
|
47
|
+
def matcher
|
|
48
|
+
matcher_class.new(scope, method_name)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Return match
|
|
52
|
+
#
|
|
53
|
+
# @return [Matche]
|
|
54
|
+
#
|
|
55
|
+
# @api private
|
|
56
|
+
#
|
|
57
|
+
attr_reader :match
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
# Initialize matcher
|
|
62
|
+
#
|
|
63
|
+
# @param [MatchData] match
|
|
64
|
+
#
|
|
65
|
+
# @api private
|
|
66
|
+
#
|
|
67
|
+
def initialize(match)
|
|
68
|
+
@match = match
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Return scope
|
|
72
|
+
#
|
|
73
|
+
# @return [Class|Module]
|
|
74
|
+
#
|
|
75
|
+
# @api private
|
|
76
|
+
#
|
|
77
|
+
def scope
|
|
78
|
+
scope_name.gsub(%r(\A::), '').split('::').inject(::Object) do |parent, name|
|
|
79
|
+
parent.const_get(name)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
memoize :scope
|
|
83
|
+
|
|
84
|
+
# Return scope name
|
|
85
|
+
#
|
|
86
|
+
# @return [String]
|
|
87
|
+
#
|
|
88
|
+
# @api private
|
|
89
|
+
#
|
|
90
|
+
def scope_name
|
|
91
|
+
match[SCOPE_NAME_POSITION]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Return method name
|
|
95
|
+
#
|
|
96
|
+
# @return [String]
|
|
97
|
+
#
|
|
98
|
+
# @api private
|
|
99
|
+
#
|
|
100
|
+
def method_name
|
|
101
|
+
match[METHOD_NAME_POSITION].to_sym
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Return scope symbol
|
|
105
|
+
#
|
|
106
|
+
# @return [Symbol]
|
|
107
|
+
#
|
|
108
|
+
# @api private
|
|
109
|
+
#
|
|
110
|
+
def scope_symbol
|
|
111
|
+
match[SCOPE_SYMBOL_POSITION]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Return matcher class
|
|
115
|
+
#
|
|
116
|
+
# @return [Class:Mutant::Matcher]
|
|
117
|
+
#
|
|
118
|
+
# @api private
|
|
119
|
+
#
|
|
120
|
+
def matcher_class
|
|
121
|
+
TABLE.fetch(scope_symbol)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
class Matcher
|
|
3
|
+
class Method < self
|
|
4
|
+
# Matcher for instance methods
|
|
5
|
+
class Instance < self
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Return identification
|
|
9
|
+
#
|
|
10
|
+
# @return [String]
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
#
|
|
14
|
+
def identification
|
|
15
|
+
"#{scope.name}##{method_name}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Test if method is public
|
|
19
|
+
#
|
|
20
|
+
# @return [true]
|
|
21
|
+
# if method is public
|
|
22
|
+
#
|
|
23
|
+
# @return [false]
|
|
24
|
+
# otherwise
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
#
|
|
28
|
+
def public?
|
|
29
|
+
scope.public_method_defined?(method_name)
|
|
30
|
+
end
|
|
31
|
+
memoize :public?
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# Check if node is matched
|
|
36
|
+
#
|
|
37
|
+
# @param [Rubinius::AST::Node] node
|
|
38
|
+
#
|
|
39
|
+
# @return [true]
|
|
40
|
+
# returns true if node matches method
|
|
41
|
+
#
|
|
42
|
+
# @return [false]
|
|
43
|
+
# returns false if node NOT matches method
|
|
44
|
+
#
|
|
45
|
+
# @api private
|
|
46
|
+
#
|
|
47
|
+
def match?(node)
|
|
48
|
+
node.line == source_line &&
|
|
49
|
+
node.class == Rubinius::AST::Define &&
|
|
50
|
+
node.name == method_name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Return method instance
|
|
54
|
+
#
|
|
55
|
+
# @return [UnboundMethod]
|
|
56
|
+
#
|
|
57
|
+
# @api private
|
|
58
|
+
#
|
|
59
|
+
def method
|
|
60
|
+
scope.instance_method(method_name)
|
|
61
|
+
end
|
|
62
|
+
memoize :method, :freezer => :noop
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|