mutant 0.5.17 → 0.5.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +6 -0
- data/Rakefile +13 -0
- data/config/flay.yml +1 -1
- data/config/reek.yml +8 -1
- data/lib/mutant.rb +18 -3
- data/lib/mutant/cli.rb +6 -3
- data/lib/mutant/constants.rb +3 -0
- data/lib/mutant/expression.rb +110 -0
- data/lib/mutant/expression/method.rb +92 -0
- data/lib/mutant/expression/namespace.rb +90 -0
- data/lib/mutant/matcher/namespace.rb +3 -4
- data/lib/mutant/meta.rb +31 -0
- data/lib/mutant/meta/example.rb +152 -0
- data/lib/mutant/meta/example/dsl.rb +105 -0
- data/lib/mutant/mutator/node.rb +6 -6
- data/lib/mutant/mutator/node/arguments.rb +1 -1
- data/lib/mutant/mutator/node/begin.rb +1 -1
- data/lib/mutant/mutator/node/const.rb +1 -1
- data/lib/mutant/mutator/node/if.rb +6 -6
- data/lib/mutant/mutator/node/literal/array.rb +2 -2
- data/lib/mutant/mutator/node/literal/hash.rb +2 -2
- data/lib/mutant/mutator/node/literal/range.rb +3 -3
- data/lib/mutant/mutator/node/literal/regex.rb +2 -2
- data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
- data/lib/mutant/mutator/node/op_asgn.rb +1 -3
- data/lib/mutant/mutator/node/or_asgn.rb +31 -0
- data/lib/mutant/mutator/node/send.rb +1 -1
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
- data/lib/mutant/reporter/cli/report/mutation.rb +11 -1
- data/lib/mutant/strategy.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- data/meta/and.rb +12 -0
- data/meta/and_asgn.rb +12 -0
- data/meta/array.rb +30 -0
- data/meta/begin.rb +15 -0
- data/meta/binary.rb +12 -0
- data/meta/block.rb +55 -0
- data/meta/block_pass.rb +8 -0
- data/meta/blockarg.rb +10 -0
- data/meta/boolean.rb +15 -0
- data/meta/break.rb +11 -0
- data/meta/case.rb +303 -0
- data/meta/casgn.rb +9 -0
- data/meta/cbase.rb +8 -0
- data/meta/const.rb +9 -0
- data/meta/cvar.rb +7 -0
- data/meta/cvasgn.rb +10 -0
- data/meta/define.rb +118 -0
- data/meta/defined.rb +7 -0
- data/meta/dstr.rb +10 -0
- data/meta/dsym.rb +11 -0
- data/meta/ensure.rb +9 -0
- data/meta/fixnum.rb +19 -0
- data/meta/float.rb +38 -0
- data/meta/gvar.rb +7 -0
- data/meta/gvasgn.rb +10 -0
- data/meta/hash.rb +25 -0
- data/meta/if.rb +57 -0
- data/meta/ivasgn.rb +10 -0
- data/meta/kwbegin.rb +9 -0
- data/meta/lvar.rb +14 -0
- data/meta/lvasgn.rb +10 -0
- data/meta/masgn.rb +7 -0
- data/meta/match_current_line.rb +14 -0
- data/meta/next.rb +11 -0
- data/meta/nil.rb +5 -0
- data/meta/nthref.rb +14 -0
- data/meta/op_assgn.rb +15 -0
- data/meta/or_asgn.rb +22 -0
- data/meta/range.rb +41 -0
- data/meta/redo.rb +5 -0
- data/meta/regex.rb +20 -0
- data/meta/rescue.rb +38 -0
- data/meta/restarg.rb +11 -0
- data/meta/return.rb +15 -0
- data/meta/self.rb +7 -0
- data/meta/send.rb +240 -0
- data/meta/string.rb +7 -0
- data/meta/super.rb +26 -0
- data/meta/symbol.rb +8 -0
- data/meta/unless.rb +15 -0
- data/meta/while.rb +24 -0
- data/meta/yield.rb +10 -0
- data/mutant.gemspec +1 -0
- data/spec/integration/mutant/corpus_spec.rb +29 -25
- data/spec/spec_helper.rb +2 -0
- data/spec/support/mutation_verifier.rb +1 -0
- data/spec/unit/mutant/cli_new_spec.rb +6 -6
- data/spec/unit/mutant/expression/method_spec.rb +50 -0
- data/spec/unit/mutant/expression/namespace/flat_spec.rb +32 -0
- data/spec/unit/mutant/expression/namespace/recursive_spec.rb +37 -0
- data/spec/unit/mutant/matcher/namespace_spec.rb +2 -2
- data/spec/unit/mutant/mutation_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node_spec.rb +14 -0
- metadata +123 -139
- data/lib/mutant/cli/classifier.rb +0 -139
- data/lib/mutant/cli/classifier/method.rb +0 -105
- data/lib/mutant/cli/classifier/namespace.rb +0 -49
- data/spec/unit/mutant/cli/classifier/method_spec.rb +0 -77
- data/spec/unit/mutant/cli/classifier/namespace/flat_spec.rb +0 -58
- data/spec/unit/mutant/cli/classifier/namespace/recursive_spec.rb +0 -58
- data/spec/unit/mutant/cli/classifier_spec.rb +0 -59
- data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/begin_spec.rb +0 -32
- data/spec/unit/mutant/mutator/node/binary_spec.rb +0 -41
- data/spec/unit/mutant/mutator/node/block_pass_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/block_spec.rb +0 -83
- data/spec/unit/mutant/mutator/node/blockarg_spec.rb +0 -17
- data/spec/unit/mutant/mutator/node/case_spec.rb +0 -329
- data/spec/unit/mutant/mutator/node/cbase_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +0 -58
- data/spec/unit/mutant/mutator/node/const_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/define_spec.rb +0 -171
- data/spec/unit/mutant/mutator/node/defined_spec.rb +0 -14
- data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -17
- data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -18
- data/spec/unit/mutant/mutator/node/ensure_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/if_spec.rb +0 -77
- data/spec/unit/mutant/mutator/node/kwbegin_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/literal/array_spec.rb +0 -47
- data/spec/unit/mutant/mutator/node/literal/boolean_spec.rb +0 -25
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +0 -13
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -53
- data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +0 -33
- data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -56
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +0 -36
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/loop_ctrl_spec.rb +0 -37
- data/spec/unit/mutant/mutator/node/masgn_spec.rb +0 -14
- data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +0 -21
- data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +0 -78
- data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +0 -61
- data/spec/unit/mutant/mutator/node/nthref_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -22
- data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/redo_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -63
- data/spec/unit/mutant/mutator/node/restarg_spec.rb +0 -18
- data/spec/unit/mutant/mutator/node/return_spec.rb +0 -31
- data/spec/unit/mutant/mutator/node/send_spec.rb +0 -382
- data/spec/unit/mutant/mutator/node/super_spec.rb +0 -46
- data/spec/unit/mutant/mutator/node/yield_spec.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e86610168e1a64b920f694f5854137186fb808e0
|
4
|
+
data.tar.gz: e33eeafaebdb1a32042f56e03ed0794e25056f16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6237bcc40f7b53097546148fe68488f7b8af9e7c5e9b348cc3fa2811a3fb860f9b92b551ad3daf7aed87158061cc0ade88e894154352f54c6b50a2b0effee5d9
|
7
|
+
data.tar.gz: 42a09a5d0011978606d9ee12fae5bc1b9d4f2919a11aa783dcdc088f22127edd99fbb66a42c1ef7ab2c04efbc842b15c2e8f13af0ffa33ae3c481059ef4495b6
|
data/Changelog.md
CHANGED
data/Rakefile
CHANGED
@@ -15,3 +15,16 @@ if ENV['TRAVIS']
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
|
+
|
19
|
+
desc 'Generate mutation operator listing'
|
20
|
+
task :list do
|
21
|
+
require 'mutant'
|
22
|
+
# TODO: Add a nice public interface
|
23
|
+
registry = Mutant::Mutator::Registry.send(:registry)
|
24
|
+
registry.keys.select do |key|
|
25
|
+
key.is_a?(Symbol)
|
26
|
+
end.sort.each do |type|
|
27
|
+
mutator = registry.fetch(type)
|
28
|
+
puts '%-18s: %s' % [type, mutator.name.sub(/\AMutant::Mutator::Node::/, '')]
|
29
|
+
end
|
30
|
+
end
|
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -10,7 +10,8 @@ ClassVariable:
|
|
10
10
|
exclude: []
|
11
11
|
ControlParameter:
|
12
12
|
enabled: true
|
13
|
-
exclude:
|
13
|
+
exclude:
|
14
|
+
- Mutant::Expression#match_length
|
14
15
|
DataClump:
|
15
16
|
enabled: true
|
16
17
|
exclude: []
|
@@ -33,6 +34,8 @@ FeatureEnvy:
|
|
33
34
|
# Nature of OptionParser :(
|
34
35
|
- Mutant::CLI#add_environmental_options
|
35
36
|
- Mutant::CLI#parse
|
37
|
+
# False positive, its a utility
|
38
|
+
- Mutant::Meta::Example::Verification#format_mutation
|
36
39
|
IrresponsibleModule:
|
37
40
|
enabled: true
|
38
41
|
exclude: []
|
@@ -69,6 +72,7 @@ RepeatedConditional:
|
|
69
72
|
- Mutant::Mutator
|
70
73
|
- Mutant::Rspec::Strategy
|
71
74
|
- Mutant::Reporter::CLI
|
75
|
+
- Mutant::Meta::Example::DSL
|
72
76
|
max_ifs: 1
|
73
77
|
TooManyInstanceVariables:
|
74
78
|
enabled: true
|
@@ -94,6 +98,8 @@ TooManyStatements:
|
|
94
98
|
- Mutant::Reporter::CLI#colorized_diff
|
95
99
|
- Mutant::Reporter::CLI::Report::Config#run
|
96
100
|
- Mutant::Runner#visit_collection
|
101
|
+
- Mutant::Runner#initialize
|
102
|
+
- Mutant::Runner::Mutation#run
|
97
103
|
- Mutant::Zombifier::File#self.find
|
98
104
|
- Mutant::RequireHighjack#infect
|
99
105
|
- Mutant::Reporter::CLI::Registry#included
|
@@ -152,4 +158,5 @@ UtilityFunction:
|
|
152
158
|
- Mutant::Rspec::Strategy#options
|
153
159
|
- Mutant::Rspec::Strategy#world
|
154
160
|
- Mutant::Rspec::Strategy#rspec2
|
161
|
+
- Mutant::Meta::Example::Verification#format_mutation
|
155
162
|
max_helper_calls: 0
|
data/lib/mutant.rb
CHANGED
@@ -26,6 +26,20 @@ module Mutant
|
|
26
26
|
# The frozen empty array used within mutant
|
27
27
|
EMPTY_ARRAY = [].freeze
|
28
28
|
|
29
|
+
# Lookup constant for location
|
30
|
+
#
|
31
|
+
# @param [String] location
|
32
|
+
#
|
33
|
+
# @return [Object]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
def self.constant_lookup(location)
|
38
|
+
location.sub(CBASE_PATTERN, EMPTY_STRING).split(SCOPE_OPERATOR).reduce(Object) do |parent, name|
|
39
|
+
parent.const_get(name, nil)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
29
43
|
# Perform self zombification
|
30
44
|
#
|
31
45
|
# @return [self]
|
@@ -144,6 +158,7 @@ require 'mutant/mutator/node/named_value/constant_assignment'
|
|
144
158
|
require 'mutant/mutator/node/named_value/variable_assignment'
|
145
159
|
require 'mutant/mutator/node/loop_control'
|
146
160
|
require 'mutant/mutator/node/noop'
|
161
|
+
require 'mutant/mutator/node/or_asgn'
|
147
162
|
require 'mutant/mutator/node/op_asgn'
|
148
163
|
require 'mutant/mutator/node/conditional_loop'
|
149
164
|
require 'mutant/mutator/node/yield'
|
@@ -186,6 +201,9 @@ require 'mutant/matcher/namespace'
|
|
186
201
|
require 'mutant/matcher/scope'
|
187
202
|
require 'mutant/matcher/filter'
|
188
203
|
require 'mutant/matcher/null'
|
204
|
+
require 'mutant/expression'
|
205
|
+
require 'mutant/expression/method'
|
206
|
+
require 'mutant/expression/namespace'
|
189
207
|
require 'mutant/killer'
|
190
208
|
require 'mutant/test'
|
191
209
|
require 'mutant/strategy'
|
@@ -195,9 +213,6 @@ require 'mutant/runner/subject'
|
|
195
213
|
require 'mutant/runner/mutation'
|
196
214
|
require 'mutant/runner/killer'
|
197
215
|
require 'mutant/cli'
|
198
|
-
require 'mutant/cli/classifier'
|
199
|
-
require 'mutant/cli/classifier/namespace'
|
200
|
-
require 'mutant/cli/classifier/method'
|
201
216
|
require 'mutant/color'
|
202
217
|
require 'mutant/diff'
|
203
218
|
require 'mutant/reporter'
|
data/lib/mutant/cli.rb
CHANGED
@@ -249,8 +249,11 @@ module Mutant
|
|
249
249
|
#
|
250
250
|
def parse_matchers(patterns)
|
251
251
|
patterns.each do |pattern|
|
252
|
-
|
253
|
-
|
252
|
+
expression = Expression.parse(pattern)
|
253
|
+
unless expression
|
254
|
+
raise Error, "Invalid mutant expression: #{pattern.inspect}"
|
255
|
+
end
|
256
|
+
@builder.add_matcher(expression.matcher(@cache))
|
254
257
|
end
|
255
258
|
end
|
256
259
|
|
@@ -321,7 +324,7 @@ module Mutant
|
|
321
324
|
#
|
322
325
|
def add_filter_options(opts)
|
323
326
|
opts.on('--ignore-subject PATTERN', 'Ignore subjects that match PATTERN') do |pattern|
|
324
|
-
@builder.add_subject_ignore(
|
327
|
+
@builder.add_subject_ignore(Expression.parse(pattern).matcher(@cache))
|
325
328
|
end
|
326
329
|
opts.on('--code CODE', 'Scope execution to subjects with CODE') do |code|
|
327
330
|
@builder.add_subject_selector(Morpher.compile(s(:eql, s(:attribute, :code), s(:static, code))))
|
data/lib/mutant/constants.rb
CHANGED
@@ -4,6 +4,9 @@ module Mutant
|
|
4
4
|
|
5
5
|
symbolset = ->(strings) { strings.map(&:to_sym).to_set.freeze }
|
6
6
|
|
7
|
+
SCOPE_OPERATOR = '::'.freeze
|
8
|
+
CBASE_PATTERN = /\A#{SCOPE_OPERATOR}/.freeze
|
9
|
+
|
7
10
|
# Set of nodes that cannot be on the LHS of an assignment
|
8
11
|
NOT_ASSIGNABLE = symbolset.(%w[int float str dstr class module self])
|
9
12
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Mutant
|
2
|
+
|
3
|
+
# Abstract base class for match expression
|
4
|
+
class Expression
|
5
|
+
include AbstractType, Adamantium, Concord::Public.new(:match)
|
6
|
+
|
7
|
+
include Equalizer.new(:syntax)
|
8
|
+
|
9
|
+
SCOPE_NAME_PATTERN = /[A-Za-z][A-Za-z\d_]*/.freeze
|
10
|
+
|
11
|
+
METHOD_NAME_PATTERN = Regexp.union(
|
12
|
+
/[A-Za-z_][A-Za-z\d_]*[!?=]?/,
|
13
|
+
*OPERATOR_METHODS.map(&:to_s)
|
14
|
+
).freeze
|
15
|
+
|
16
|
+
SCOPE_PATTERN = /
|
17
|
+
(?:#{SCOPE_OPERATOR})?#{SCOPE_NAME_PATTERN}
|
18
|
+
(?:#{SCOPE_OPERATOR}#{SCOPE_NAME_PATTERN})*
|
19
|
+
/x.freeze
|
20
|
+
|
21
|
+
REGISTRY = {}
|
22
|
+
|
23
|
+
# Initialize expression
|
24
|
+
#
|
25
|
+
# @param [MatchData] match
|
26
|
+
def initialize(*)
|
27
|
+
super
|
28
|
+
@syntax = match.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return syntax
|
32
|
+
#
|
33
|
+
# @return [String]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
attr_reader :syntax
|
38
|
+
|
39
|
+
# Return match length for expression
|
40
|
+
#
|
41
|
+
# @param [Expression] neddle
|
42
|
+
#
|
43
|
+
# @return [Fixnum]
|
44
|
+
#
|
45
|
+
def match_length(neddle)
|
46
|
+
if eql?(neddle)
|
47
|
+
syntax.length
|
48
|
+
else
|
49
|
+
0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Register expression
|
54
|
+
#
|
55
|
+
# @return [undefined]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
def self.register(regexp)
|
60
|
+
REGISTRY[regexp] = self
|
61
|
+
end
|
62
|
+
private_class_method :register
|
63
|
+
|
64
|
+
# Parse input into expression
|
65
|
+
#
|
66
|
+
# @param [String] pattern
|
67
|
+
#
|
68
|
+
# @return [Expression]
|
69
|
+
# if expression is valid
|
70
|
+
#
|
71
|
+
# @return [nil]
|
72
|
+
# otherwise
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
def self.parse(pattern)
|
77
|
+
expressions = expressions(pattern)
|
78
|
+
case expressions.length
|
79
|
+
when 0
|
80
|
+
when 1
|
81
|
+
expressions.first
|
82
|
+
else
|
83
|
+
fail "Ambigous expression: #{pattern.inspect}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return expressions for input
|
88
|
+
#
|
89
|
+
# @param [String] input
|
90
|
+
#
|
91
|
+
# @return [Classifier]
|
92
|
+
# if classifier can be found
|
93
|
+
#
|
94
|
+
# @return [nil]
|
95
|
+
# otherwise
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
def self.expressions(input)
|
100
|
+
REGISTRY.each_with_object([]) do |(regexp, klass), expressions|
|
101
|
+
match = regexp.match(input)
|
102
|
+
if match
|
103
|
+
expressions << klass.new(match)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
private_class_method :expressions
|
108
|
+
|
109
|
+
end # Expression
|
110
|
+
end # Mutant
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Expression
|
3
|
+
|
4
|
+
# Explicit method expression
|
5
|
+
class Method < self
|
6
|
+
|
7
|
+
MATCHERS = {
|
8
|
+
'.' => Matcher::Methods::Singleton,
|
9
|
+
'#' => Matcher::Methods::Instance
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
regexp = /
|
13
|
+
\A
|
14
|
+
(?<scope_name>#{SCOPE_PATTERN})
|
15
|
+
(?<scope_symbol>[.#])
|
16
|
+
(?<method_name>#{METHOD_NAME_PATTERN})
|
17
|
+
\z
|
18
|
+
/x.freeze
|
19
|
+
|
20
|
+
register(regexp)
|
21
|
+
|
22
|
+
# Return method matcher
|
23
|
+
#
|
24
|
+
# @param [Cache] cache
|
25
|
+
#
|
26
|
+
# @return [Matcher::Method]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def matcher(cache)
|
31
|
+
methods_matcher = MATCHERS.fetch(scope_symbol).new(cache, scope)
|
32
|
+
method = methods_matcher.methods.detect do |meth|
|
33
|
+
meth.name == method_name
|
34
|
+
end or raise NameError, "Cannot find method #{identifier}"
|
35
|
+
methods_matcher.matcher.build(cache, scope, method)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Return scope name
|
41
|
+
#
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def scope_name
|
47
|
+
match[__method__]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return scope
|
51
|
+
#
|
52
|
+
# @return [Class, Method]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
def scope
|
57
|
+
Mutant.constant_lookup(scope_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return method name
|
61
|
+
#
|
62
|
+
# @return [String]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
#
|
66
|
+
def method_name
|
67
|
+
match[__method__].to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return scope symbol
|
71
|
+
#
|
72
|
+
# @return [Symbol]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
#
|
76
|
+
def scope_symbol
|
77
|
+
match[__method__]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return matcher class
|
81
|
+
#
|
82
|
+
# @return [Class:Mutant::Matcher]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
#
|
86
|
+
def methods_matcher(cache)
|
87
|
+
MATCHERS.fetch(scope_symbol).new(cache, scope)
|
88
|
+
end
|
89
|
+
|
90
|
+
end # Method
|
91
|
+
end # Expression
|
92
|
+
end # Mutant
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Expression
|
3
|
+
# Abstract base class for expressions matching namespaces
|
4
|
+
class Namespace < self
|
5
|
+
include AbstractType
|
6
|
+
|
7
|
+
# Return matcher
|
8
|
+
#
|
9
|
+
# @param [Cache] cache
|
10
|
+
#
|
11
|
+
# @return [Matcher]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def matcher(cache)
|
16
|
+
self.class::MATCHER.new(cache, namespace)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Return namespace
|
22
|
+
#
|
23
|
+
# @return [Class, Module]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def namespace
|
28
|
+
Mutant.constant_lookup(match[__method__].to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Recursive namespace expression
|
32
|
+
class Recursive < self
|
33
|
+
|
34
|
+
register(/\A(?<namespace>#{SCOPE_PATTERN})?\*\z/)
|
35
|
+
|
36
|
+
MATCHER = Matcher::Namespace
|
37
|
+
|
38
|
+
# Initialize object
|
39
|
+
#
|
40
|
+
# @return [undefined]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def initialize(*)
|
44
|
+
super
|
45
|
+
namespace_src = Regexp.escape(namespace)
|
46
|
+
@recursion_pattern = Regexp.union(/\A#{namespace_src}\z/, /\A#{namespace_src}::/)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return length of match
|
50
|
+
#
|
51
|
+
# @param [Expression] expression
|
52
|
+
#
|
53
|
+
# @return [Fixnum]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
def match_length(expression)
|
58
|
+
if @recursion_pattern =~ expression.syntax
|
59
|
+
namespace.length
|
60
|
+
else
|
61
|
+
0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Return matched namespace
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
#
|
73
|
+
def namespace
|
74
|
+
match[__method__] || ''
|
75
|
+
end
|
76
|
+
|
77
|
+
end # Recursive
|
78
|
+
|
79
|
+
# Exact namespace expression
|
80
|
+
class Exact < self
|
81
|
+
|
82
|
+
register(/\A(?<namespace>#{SCOPE_PATTERN})\z/)
|
83
|
+
|
84
|
+
MATCHER = Matcher::Scope
|
85
|
+
|
86
|
+
end # Exact
|
87
|
+
|
88
|
+
end # Namespace
|
89
|
+
end # Namespace
|
90
|
+
end # Mutant
|