mutant 0.5.17 → 0.5.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +6 -0
  3. data/Rakefile +13 -0
  4. data/config/flay.yml +1 -1
  5. data/config/reek.yml +8 -1
  6. data/lib/mutant.rb +18 -3
  7. data/lib/mutant/cli.rb +6 -3
  8. data/lib/mutant/constants.rb +3 -0
  9. data/lib/mutant/expression.rb +110 -0
  10. data/lib/mutant/expression/method.rb +92 -0
  11. data/lib/mutant/expression/namespace.rb +90 -0
  12. data/lib/mutant/matcher/namespace.rb +3 -4
  13. data/lib/mutant/meta.rb +31 -0
  14. data/lib/mutant/meta/example.rb +152 -0
  15. data/lib/mutant/meta/example/dsl.rb +105 -0
  16. data/lib/mutant/mutator/node.rb +6 -6
  17. data/lib/mutant/mutator/node/arguments.rb +1 -1
  18. data/lib/mutant/mutator/node/begin.rb +1 -1
  19. data/lib/mutant/mutator/node/const.rb +1 -1
  20. data/lib/mutant/mutator/node/if.rb +6 -6
  21. data/lib/mutant/mutator/node/literal/array.rb +2 -2
  22. data/lib/mutant/mutator/node/literal/hash.rb +2 -2
  23. data/lib/mutant/mutator/node/literal/range.rb +3 -3
  24. data/lib/mutant/mutator/node/literal/regex.rb +2 -2
  25. data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
  26. data/lib/mutant/mutator/node/op_asgn.rb +1 -3
  27. data/lib/mutant/mutator/node/or_asgn.rb +31 -0
  28. data/lib/mutant/mutator/node/send.rb +1 -1
  29. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
  30. data/lib/mutant/reporter/cli/report/mutation.rb +11 -1
  31. data/lib/mutant/strategy.rb +1 -1
  32. data/lib/mutant/version.rb +1 -1
  33. data/meta/and.rb +12 -0
  34. data/meta/and_asgn.rb +12 -0
  35. data/meta/array.rb +30 -0
  36. data/meta/begin.rb +15 -0
  37. data/meta/binary.rb +12 -0
  38. data/meta/block.rb +55 -0
  39. data/meta/block_pass.rb +8 -0
  40. data/meta/blockarg.rb +10 -0
  41. data/meta/boolean.rb +15 -0
  42. data/meta/break.rb +11 -0
  43. data/meta/case.rb +303 -0
  44. data/meta/casgn.rb +9 -0
  45. data/meta/cbase.rb +8 -0
  46. data/meta/const.rb +9 -0
  47. data/meta/cvar.rb +7 -0
  48. data/meta/cvasgn.rb +10 -0
  49. data/meta/define.rb +118 -0
  50. data/meta/defined.rb +7 -0
  51. data/meta/dstr.rb +10 -0
  52. data/meta/dsym.rb +11 -0
  53. data/meta/ensure.rb +9 -0
  54. data/meta/fixnum.rb +19 -0
  55. data/meta/float.rb +38 -0
  56. data/meta/gvar.rb +7 -0
  57. data/meta/gvasgn.rb +10 -0
  58. data/meta/hash.rb +25 -0
  59. data/meta/if.rb +57 -0
  60. data/meta/ivasgn.rb +10 -0
  61. data/meta/kwbegin.rb +9 -0
  62. data/meta/lvar.rb +14 -0
  63. data/meta/lvasgn.rb +10 -0
  64. data/meta/masgn.rb +7 -0
  65. data/meta/match_current_line.rb +14 -0
  66. data/meta/next.rb +11 -0
  67. data/meta/nil.rb +5 -0
  68. data/meta/nthref.rb +14 -0
  69. data/meta/op_assgn.rb +15 -0
  70. data/meta/or_asgn.rb +22 -0
  71. data/meta/range.rb +41 -0
  72. data/meta/redo.rb +5 -0
  73. data/meta/regex.rb +20 -0
  74. data/meta/rescue.rb +38 -0
  75. data/meta/restarg.rb +11 -0
  76. data/meta/return.rb +15 -0
  77. data/meta/self.rb +7 -0
  78. data/meta/send.rb +240 -0
  79. data/meta/string.rb +7 -0
  80. data/meta/super.rb +26 -0
  81. data/meta/symbol.rb +8 -0
  82. data/meta/unless.rb +15 -0
  83. data/meta/while.rb +24 -0
  84. data/meta/yield.rb +10 -0
  85. data/mutant.gemspec +1 -0
  86. data/spec/integration/mutant/corpus_spec.rb +29 -25
  87. data/spec/spec_helper.rb +2 -0
  88. data/spec/support/mutation_verifier.rb +1 -0
  89. data/spec/unit/mutant/cli_new_spec.rb +6 -6
  90. data/spec/unit/mutant/expression/method_spec.rb +50 -0
  91. data/spec/unit/mutant/expression/namespace/flat_spec.rb +32 -0
  92. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +37 -0
  93. data/spec/unit/mutant/matcher/namespace_spec.rb +2 -2
  94. data/spec/unit/mutant/mutation_spec.rb +1 -1
  95. data/spec/unit/mutant/mutator/node_spec.rb +14 -0
  96. metadata +123 -139
  97. data/lib/mutant/cli/classifier.rb +0 -139
  98. data/lib/mutant/cli/classifier/method.rb +0 -105
  99. data/lib/mutant/cli/classifier/namespace.rb +0 -49
  100. data/spec/unit/mutant/cli/classifier/method_spec.rb +0 -77
  101. data/spec/unit/mutant/cli/classifier/namespace/flat_spec.rb +0 -58
  102. data/spec/unit/mutant/cli/classifier/namespace/recursive_spec.rb +0 -58
  103. data/spec/unit/mutant/cli/classifier_spec.rb +0 -59
  104. data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +0 -19
  105. data/spec/unit/mutant/mutator/node/begin_spec.rb +0 -32
  106. data/spec/unit/mutant/mutator/node/binary_spec.rb +0 -41
  107. data/spec/unit/mutant/mutator/node/block_pass_spec.rb +0 -15
  108. data/spec/unit/mutant/mutator/node/block_spec.rb +0 -83
  109. data/spec/unit/mutant/mutator/node/blockarg_spec.rb +0 -17
  110. data/spec/unit/mutant/mutator/node/case_spec.rb +0 -329
  111. data/spec/unit/mutant/mutator/node/cbase_spec.rb +0 -15
  112. data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +0 -58
  113. data/spec/unit/mutant/mutator/node/const_spec.rb +0 -16
  114. data/spec/unit/mutant/mutator/node/define_spec.rb +0 -171
  115. data/spec/unit/mutant/mutator/node/defined_spec.rb +0 -14
  116. data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -17
  117. data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -18
  118. data/spec/unit/mutant/mutator/node/ensure_spec.rb +0 -16
  119. data/spec/unit/mutant/mutator/node/if_spec.rb +0 -77
  120. data/spec/unit/mutant/mutator/node/kwbegin_spec.rb +0 -16
  121. data/spec/unit/mutant/mutator/node/literal/array_spec.rb +0 -47
  122. data/spec/unit/mutant/mutator/node/literal/boolean_spec.rb +0 -25
  123. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +0 -13
  124. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -53
  125. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +0 -33
  126. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +0 -10
  127. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -56
  128. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +0 -36
  129. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +0 -15
  130. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +0 -15
  131. data/spec/unit/mutant/mutator/node/loop_ctrl_spec.rb +0 -37
  132. data/spec/unit/mutant/mutator/node/masgn_spec.rb +0 -14
  133. data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +0 -21
  134. data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +0 -78
  135. data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +0 -16
  136. data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +0 -61
  137. data/spec/unit/mutant/mutator/node/nthref_spec.rb +0 -19
  138. data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -22
  139. data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +0 -19
  140. data/spec/unit/mutant/mutator/node/redo_spec.rb +0 -10
  141. data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -63
  142. data/spec/unit/mutant/mutator/node/restarg_spec.rb +0 -18
  143. data/spec/unit/mutant/mutator/node/return_spec.rb +0 -31
  144. data/spec/unit/mutant/mutator/node/send_spec.rb +0 -382
  145. data/spec/unit/mutant/mutator/node/super_spec.rb +0 -46
  146. 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: 5ed19319f31c14a3b2677f67cda130f8ae053af1
4
- data.tar.gz: 6cb628e6e446ed9d1f0c14ad88cfd254d49ee216
3
+ metadata.gz: e86610168e1a64b920f694f5854137186fb808e0
4
+ data.tar.gz: e33eeafaebdb1a32042f56e03ed0794e25056f16
5
5
  SHA512:
6
- metadata.gz: 482eeee0d39d0e9b869b6a0625d71bf7b08bbdf8acff2fc9f29b44a9b74472cd038e166f053e17323dd41d46295f802245db69d7bb6dc7085336243bc448351b
7
- data.tar.gz: f332afc9b4404fbcb8ee20e5e74fe6789df531c856d1fc4562d5cb92dee1d771d900405ba044f5360bad39f6400002786584da7f0f4c6efce0be2c5bd4ba5f64
6
+ metadata.gz: 6237bcc40f7b53097546148fe68488f7b8af9e7c5e9b348cc3fa2811a3fb860f9b92b551ad3daf7aed87158061cc0ade88e894154352f54c6b50a2b0effee5d9
7
+ data.tar.gz: 42a09a5d0011978606d9ee12fae5bc1b9d4f2919a11aa783dcdc088f22127edd99fbb66a42c1ef7ab2c04efbc842b15c2e8f13af0ffa33ae3c481059ef4495b6
data/Changelog.md CHANGED
@@ -1,3 +1,9 @@
1
+ # v0.5.18 2014-06-04
2
+
3
+ Changes:
4
+
5
+ * Do not rename lhs of or assigns when lhs is a ivasgn. Closes #150
6
+
1
7
  # v0.5.17 2014-05-27
2
8
 
3
9
  Changes:
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
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 801
3
+ total_score: 849
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
- matcher = Classifier.run(@cache, pattern)
253
- @builder.add_matcher(matcher)
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(Classifier.run(@cache, pattern))
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))))
@@ -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