mutant 0.3.0.rc1 → 0.3.0.rc2
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/.rspec +0 -1
- data/.travis.yml +5 -4
- data/Gemfile.devtools +4 -4
- data/Guardfile +7 -5
- data/README.md +8 -8
- data/config/flay.yml +2 -2
- data/config/reek.yml +1 -0
- data/config/rubocop.yml +0 -4
- data/lib/mutant/cli/builder.rb +177 -0
- data/lib/mutant/cli/classifier/method.rb +10 -14
- data/lib/mutant/cli/classifier/namespace.rb +7 -9
- data/lib/mutant/cli/classifier.rb +29 -31
- data/lib/mutant/cli.rb +34 -96
- data/lib/mutant/color.rb +1 -1
- data/lib/mutant/config.rb +9 -3
- data/lib/mutant/constants.rb +1 -1
- data/lib/mutant/context/scope.rb +2 -2
- data/lib/mutant/differ.rb +0 -1
- data/lib/mutant/killer/rspec.rb +3 -8
- data/lib/mutant/killer.rb +1 -22
- data/lib/mutant/matcher/chain.rb +2 -2
- data/lib/mutant/matcher/filter.rb +32 -0
- data/lib/mutant/matcher/method/instance.rb +2 -2
- data/lib/mutant/matcher/method.rb +3 -3
- data/lib/mutant/matcher/methods.rb +1 -1
- data/lib/mutant/matcher.rb +1 -0
- data/lib/mutant/mutation/evil.rb +0 -10
- data/lib/mutant/mutation/neutral.rb +0 -23
- data/lib/mutant/mutation.rb +13 -23
- data/lib/mutant/mutator/node/begin.rb +12 -10
- data/lib/mutant/mutator/node/block.rb +1 -0
- data/lib/mutant/mutator/node/blockarg.rb +15 -0
- data/lib/mutant/mutator/node/case.rb +1 -0
- data/lib/mutant/mutator/node/connective/binary.rb +2 -2
- data/lib/mutant/mutator/node/const.rb +2 -1
- data/lib/mutant/mutator/node/dstr.rb +28 -0
- data/lib/mutant/mutator/node/dsym.rb +28 -0
- data/lib/mutant/mutator/node/generic.rb +3 -4
- data/lib/mutant/mutator/node/if.rb +1 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +2 -2
- data/lib/mutant/mutator/node/literal/range.rb +8 -6
- data/lib/mutant/mutator/node/literal.rb +0 -17
- data/lib/mutant/mutator/node/masgn.rb +1 -1
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +5 -4
- data/lib/mutant/mutator/node/op_asgn.rb +30 -0
- data/lib/mutant/mutator/node/restarg.rb +15 -0
- data/lib/mutant/mutator/node/return.rb +1 -2
- data/lib/mutant/mutator/node/send.rb +6 -5
- data/lib/mutant/mutator/node/super.rb +1 -0
- data/lib/mutant/mutator/node/while.rb +1 -0
- data/lib/mutant/mutator/node.rb +11 -1
- data/lib/mutant/node_helpers.rb +3 -3
- data/lib/mutant/predicate/attribute.rb +85 -0
- data/lib/mutant/predicate/blacklist.rb +27 -0
- data/lib/mutant/predicate/matcher.rb +36 -0
- data/lib/mutant/predicate/whitelist.rb +28 -0
- data/lib/mutant/predicate.rb +91 -0
- data/lib/mutant/reporter/cli/printer/config.rb +3 -3
- data/lib/mutant/reporter/cli/printer/killer.rb +1 -1
- data/lib/mutant/reporter/cli/printer/mutation.rb +12 -14
- data/lib/mutant/reporter/cli/printer/subject.rb +1 -3
- data/lib/mutant/reporter/cli/printer.rb +31 -7
- data/lib/mutant/runner/mutation.rb +9 -1
- data/lib/mutant/runner/subject.rb +9 -1
- data/lib/mutant/runner.rb +5 -6
- data/lib/mutant/strategy/rspec.rb +4 -4
- data/lib/mutant/strategy.rb +2 -0
- data/lib/mutant/support/method_object.rb +0 -1
- data/lib/mutant/version.rb +1 -2
- data/lib/mutant/zombifier.rb +6 -3
- data/lib/mutant.rb +12 -4
- data/mutant.gemspec +7 -7
- data/spec/integration/mutant/rspec_spec.rb +12 -5
- data/spec/shared/mutator_behavior.rb +2 -1
- data/spec/spec_helper.rb +11 -9
- data/spec/unit/mutant/cli/builder/rspec_spec.rb +38 -0
- data/spec/unit/mutant/cli/classifier/{method/each_spec.rb → method_spec.rb} +2 -14
- data/spec/unit/mutant/cli/classifier/namespace/{flat/each_spec.rb → flat_spec.rb} +1 -1
- data/spec/unit/mutant/cli/classifier/namespace/{recursive/each_spec.rb → recursive_spec.rb} +1 -1
- data/spec/unit/mutant/cli/classifier_spec.rb +59 -0
- data/spec/unit/mutant/{cli/class_methods/new_spec.rb → cli_new_spec.rb} +22 -23
- data/spec/unit/mutant/{cli/class_methods/run_spec.rb → cli_run_spec.rb} +8 -8
- data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +6 -6
- data/spec/unit/mutant/killer/success_predicate_spec.rb +5 -5
- data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +1 -1
- data/spec/unit/mutant/matcher/filter_spec.rb +19 -0
- data/spec/unit/mutant/matcher/namespace/each_spec.rb +5 -5
- data/spec/unit/mutant/mutation_spec.rb +42 -0
- data/spec/unit/mutant/mutator/each_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/and_asgn/mutation_spec.rb +3 -2
- data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +7 -2
- data/spec/unit/mutant/mutator/node/block_pass/mutation_spec.rb +1 -0
- data/spec/unit/mutant/mutator/node/blockarg/mutation_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/case/mutation_spec.rb +5 -1
- data/spec/unit/mutant/mutator/node/cbase/mutation_spec.rb +1 -0
- data/spec/unit/mutant/mutator/node/const/mutation_spec.rb +3 -2
- data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +3 -3
- data/spec/unit/mutant/mutator/node/defined_predicate/mutation_spec.rb +6 -2
- data/spec/unit/mutant/mutator/node/dstr/mutation_spec.rb +4 -2
- data/spec/unit/mutant/mutator/node/dsym/mutation_spec.rb +4 -2
- data/spec/unit/mutant/mutator/node/if/mutation_spec.rb +6 -1
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +31 -0
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +4 -2
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/masgn/mutation_spec.rb +6 -2
- data/spec/unit/mutant/mutator/node/match_current_line/mutation_spec.rb +1 -0
- data/spec/unit/mutant/mutator/node/named_value/access/mutation_spec.rb +5 -1
- data/spec/unit/mutant/mutator/node/named_value/constant_assignment/mutation_spec.rb +1 -2
- data/spec/unit/mutant/mutator/node/named_value/variable_assignment/mutation_spec.rb +5 -5
- data/spec/unit/mutant/mutator/node/op_assgn/mutation_spec.rb +3 -2
- data/spec/unit/mutant/mutator/node/or_asgn/mutation_spec.rb +3 -2
- data/spec/unit/mutant/mutator/node/rescue/mutation_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/restarg/mutation_spec.rb +3 -1
- data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +7 -3
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +37 -2
- data/spec/unit/mutant/mutator/node/super/mutation_spec.rb +4 -0
- data/spec/unit/mutant/mutator/node/while/mutation_spec.rb +3 -0
- data/spec/unit/mutant/predicate_spec.rb +135 -0
- data/spec/unit/mutant/runner/config/subjects_spec.rb +11 -11
- data/spec/unit/mutant/runner/config/success_predicate_spec.rb +6 -6
- data/spec/unit/mutant/runner/mutation/killer_spec.rb +11 -11
- data/spec/unit/mutant/runner/subject/success_predicate_spec.rb +9 -9
- data/spec/unit/mutant/strategy_spec.rb +21 -0
- data/spec/unit/mutant/subject_spec.rb +39 -0
- data/test_app/spec/shared/method_filter_parse_behavior.rb +1 -1
- metadata +54 -36
- data/lib/mutant/cli/classifier/scope.rb +0 -37
- data/lib/mutant/mutation/filter/code.rb +0 -49
- data/lib/mutant/mutation/filter/regexp.rb +0 -29
- data/lib/mutant/mutation/filter/whitelist.rb +0 -52
- data/lib/mutant/mutation/filter.rb +0 -78
- data/lib/mutant/strategy/static.rb +0 -20
- data/spec/unit/mutant/cli/classifier/class_methods/build_spec.rb +0 -48
- data/spec/unit/mutant/cli/classifier/scope/each_spec.rb +0 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5aa8cc60b0b68e67f1c9a253bfce5c7bd7aa7920
|
|
4
|
+
data.tar.gz: 60323d0b1d1d2230a62a3f9b7a28d50eb8014d7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21ce19cfa4bfddf01eb471a3c8685d3e3468c1c5dd1c9504ecc00f6e43f5a096e64573d3ff6ebb13ed0720b224ba51b3c9588a03d127255a43494e4517bdf755
|
|
7
|
+
data.tar.gz: 91157f59a4f81ff1957168ee0300fa4b33869fcd975ed9b3461a5e50fc9e7c7a629d2e1aa6ee83d47c48b21c824b3e8a20a5f7fb2feefd67fe8e1bf6d7e8d605
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
|
@@ -2,12 +2,13 @@ language: ruby
|
|
|
2
2
|
before_install: gem install bundler
|
|
3
3
|
bundler_args: --without yard guard benchmarks
|
|
4
4
|
script: "bundle exec rake ci"
|
|
5
|
+
rvm:
|
|
6
|
+
- 1.9.3
|
|
7
|
+
- 2.0.0
|
|
8
|
+
- ruby-head
|
|
9
|
+
- rbx-19mode
|
|
5
10
|
matrix:
|
|
6
11
|
include:
|
|
7
|
-
- rvm: 1.9.3
|
|
8
|
-
- rvm: 2.0.0
|
|
9
|
-
- rvm: ruby-head
|
|
10
|
-
- rvm: rbx-19mode
|
|
11
12
|
- rvm: jruby-19mode
|
|
12
13
|
env: JRUBY_OPTS="$JRUBY_OPTS --debug"
|
|
13
14
|
- rvm: jruby-head
|
data/Gemfile.devtools
CHANGED
|
@@ -18,7 +18,7 @@ group :guard do
|
|
|
18
18
|
gem 'guard-mutant', '~> 0.0.1'
|
|
19
19
|
|
|
20
20
|
# file system change event handling
|
|
21
|
-
gem 'listen', '~> 1.
|
|
21
|
+
gem 'listen', '~> 1.3.0'
|
|
22
22
|
gem 'rb-fchange', '~> 0.0.6', require: false
|
|
23
23
|
gem 'rb-fsevent', '~> 0.9.3', require: false
|
|
24
24
|
gem 'rb-inotify', '~> 0.9.0', require: false
|
|
@@ -33,10 +33,10 @@ group :metrics do
|
|
|
33
33
|
gem 'coveralls', '~> 0.6.7'
|
|
34
34
|
gem 'flay', '~> 2.4.0'
|
|
35
35
|
gem 'flog', '~> 4.1.1'
|
|
36
|
-
gem 'reek', '~> 1.3.
|
|
37
|
-
gem 'rubocop', '~> 0.
|
|
36
|
+
gem 'reek', '~> 1.3.2'
|
|
37
|
+
gem 'rubocop', '~> 0.11.0'
|
|
38
38
|
gem 'simplecov', '~> 0.7.1'
|
|
39
|
-
gem 'yardstick', '~> 0.9.
|
|
39
|
+
gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
|
|
40
40
|
|
|
41
41
|
platforms :ruby_19, :ruby_20 do
|
|
42
42
|
gem 'yard-spellcheck', '~> 0.1.5'
|
data/Guardfile
CHANGED
|
@@ -25,8 +25,10 @@ guard :rspec, cli: File.read('.rspec').split.push('--fail-fast').join(' '), keep
|
|
|
25
25
|
watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
# Deactivated for now. Somehow it disables the rspec guard.
|
|
29
|
+
#
|
|
30
|
+
# guard :rubocop, cli: %w[--config config/rubocop.yml] do
|
|
31
|
+
# watch(%r{.+\.(?:rb|rake)\z})
|
|
32
|
+
# watch(%r{\Aconfig/rubocop\.yml\z}) { |m| File.dirname(m[0]) }
|
|
33
|
+
# watch(%r{(?:.+/)?\.rubocop\.yml\z}) { |m| File.dirname(m[0]) }
|
|
34
|
+
# end
|
data/README.md
CHANGED
|
@@ -62,14 +62,14 @@ Currently mutant covers the majority of ruby's complex nodes that often occur in
|
|
|
62
62
|
Some stats from the [axiom](https://github.com/dkubb/axiom) library:
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
Subjects:
|
|
66
|
-
Mutations:
|
|
67
|
-
Kills:
|
|
68
|
-
Runtime:
|
|
69
|
-
Killtime:
|
|
70
|
-
Overhead: 0.
|
|
71
|
-
Coverage: 98.
|
|
72
|
-
Alive:
|
|
65
|
+
Subjects: 424 # Amount of subjects being mutated (currently only methods)
|
|
66
|
+
Mutations: 6760 # Amount of mutations mutant generated (~13 mutations per method)
|
|
67
|
+
Kills: 6664 # Amount of successfully killed mutations
|
|
68
|
+
Runtime: 5123.13s # Total runtime
|
|
69
|
+
Killtime: 5092.63s # Time spend killing mutations
|
|
70
|
+
Overhead: 0.60%
|
|
71
|
+
Coverage: 98.58% # Coverage score
|
|
72
|
+
Alive: 96 # Amount of alive mutations.
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
|
data/config/flay.yml
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
---
|
|
2
|
-
threshold:
|
|
3
|
-
total_score:
|
|
2
|
+
threshold: 18
|
|
3
|
+
total_score: 748
|
data/config/reek.yml
CHANGED
data/config/rubocop.yml
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Mutant
|
|
4
|
+
class CLI
|
|
5
|
+
# Abstract base class for strategy builders
|
|
6
|
+
class Builder
|
|
7
|
+
include AbstractType
|
|
8
|
+
|
|
9
|
+
# Return cache
|
|
10
|
+
#
|
|
11
|
+
# @return [Cache]
|
|
12
|
+
#
|
|
13
|
+
# @api private
|
|
14
|
+
#
|
|
15
|
+
attr_reader :cache
|
|
16
|
+
private :cache
|
|
17
|
+
|
|
18
|
+
# Return parser
|
|
19
|
+
#
|
|
20
|
+
# @return [OptionParser]
|
|
21
|
+
#
|
|
22
|
+
# @api private
|
|
23
|
+
#
|
|
24
|
+
attr_reader :parser
|
|
25
|
+
private :parser
|
|
26
|
+
|
|
27
|
+
# Initialize builder
|
|
28
|
+
#
|
|
29
|
+
# @param [OptionParser] parser
|
|
30
|
+
#
|
|
31
|
+
# @api privateo
|
|
32
|
+
#
|
|
33
|
+
def initialize(cache, parser)
|
|
34
|
+
@cache, @parser = cache, parser
|
|
35
|
+
add_options
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Add cli options
|
|
39
|
+
#
|
|
40
|
+
# @param [OptionParser]
|
|
41
|
+
#
|
|
42
|
+
# @return [self]
|
|
43
|
+
#
|
|
44
|
+
# @api private
|
|
45
|
+
#
|
|
46
|
+
abstract_method :add_options
|
|
47
|
+
|
|
48
|
+
# Return build output
|
|
49
|
+
#
|
|
50
|
+
# @return [Object]
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
#
|
|
54
|
+
abstract_method :output
|
|
55
|
+
|
|
56
|
+
# Rspec strategy builder
|
|
57
|
+
class Rspec < self
|
|
58
|
+
|
|
59
|
+
# Initialize object
|
|
60
|
+
#
|
|
61
|
+
# @return [undefined]
|
|
62
|
+
#
|
|
63
|
+
# @api private
|
|
64
|
+
#
|
|
65
|
+
def initialize(*)
|
|
66
|
+
@level = 0
|
|
67
|
+
@rspec = false
|
|
68
|
+
super
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Return strategy
|
|
72
|
+
#
|
|
73
|
+
# @return [Strategy::Rspec]
|
|
74
|
+
#
|
|
75
|
+
# @api private
|
|
76
|
+
#
|
|
77
|
+
def output
|
|
78
|
+
unless @rspec
|
|
79
|
+
raise Error, 'No strategy given'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
Strategy::Rspec.new(@level)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# Set rspec level
|
|
88
|
+
#
|
|
89
|
+
# @return [self]
|
|
90
|
+
#
|
|
91
|
+
# @api private
|
|
92
|
+
#
|
|
93
|
+
def set_level(level)
|
|
94
|
+
@level = level
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Add cli options
|
|
99
|
+
#
|
|
100
|
+
# @param [OptionParser] parser
|
|
101
|
+
#
|
|
102
|
+
# @return [undefined]
|
|
103
|
+
#
|
|
104
|
+
# @api private
|
|
105
|
+
#
|
|
106
|
+
def add_options
|
|
107
|
+
parser.on('--rspec', 'kills mutations with rspec') do
|
|
108
|
+
@rspec = true
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
parser.on('--rspec-level LEVEL', 'set rspec expansion level') do |level|
|
|
112
|
+
@level = level.to_i
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end # Rspec
|
|
117
|
+
|
|
118
|
+
# Abstract predicate builder
|
|
119
|
+
class Predicate < self
|
|
120
|
+
|
|
121
|
+
class Subject < self
|
|
122
|
+
|
|
123
|
+
# Initialize object
|
|
124
|
+
#
|
|
125
|
+
# @api private
|
|
126
|
+
#
|
|
127
|
+
# @return [undefined]
|
|
128
|
+
#
|
|
129
|
+
def initialize(*)
|
|
130
|
+
super
|
|
131
|
+
@predicates = []
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Return predicate
|
|
135
|
+
#
|
|
136
|
+
# @api private
|
|
137
|
+
#
|
|
138
|
+
def output
|
|
139
|
+
if @predicates.empty?
|
|
140
|
+
Mutant::Predicate::CONTRADICTION
|
|
141
|
+
else
|
|
142
|
+
Mutant::Predicate::Whitelist.new(@predicates)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
# Add cli options
|
|
149
|
+
#
|
|
150
|
+
# @return [undefined]
|
|
151
|
+
#
|
|
152
|
+
# @api private
|
|
153
|
+
#
|
|
154
|
+
def add_options
|
|
155
|
+
parser.on('--ignore-subject MATCHER', 'ignores subjects that matches MATCHER') do |pattern|
|
|
156
|
+
add_pattern(pattern)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Add matcher to predicates
|
|
161
|
+
#
|
|
162
|
+
# @param [String] pattern
|
|
163
|
+
#
|
|
164
|
+
# @api private
|
|
165
|
+
#
|
|
166
|
+
def add_pattern(pattern)
|
|
167
|
+
matcher = Classifier.run(@cache, pattern)
|
|
168
|
+
@predicates << Mutant::Predicate::Matcher.new(matcher)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end # Predicate
|
|
174
|
+
|
|
175
|
+
end # Builder
|
|
176
|
+
end # CLI
|
|
177
|
+
end # Mutant
|
|
@@ -6,7 +6,6 @@ module Mutant
|
|
|
6
6
|
|
|
7
7
|
# Explicit method classifier
|
|
8
8
|
class Method < self
|
|
9
|
-
register
|
|
10
9
|
|
|
11
10
|
TABLE = {
|
|
12
11
|
'.' => Matcher::Methods::Singleton,
|
|
@@ -15,18 +14,13 @@ module Mutant
|
|
|
15
14
|
|
|
16
15
|
REGEXP = /
|
|
17
16
|
\A
|
|
18
|
-
(
|
|
19
|
-
([.#])
|
|
20
|
-
(
|
|
17
|
+
(?<scope_name>#{SCOPE_PATTERN})
|
|
18
|
+
(?<scope_symbol>[.#])
|
|
19
|
+
(?<method_name>#{METHOD_NAME_PATTERN})
|
|
21
20
|
\z
|
|
22
21
|
/x.freeze
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
SCOPE_NAME_POSITION = 1
|
|
26
|
-
SCOPE_SYMBOL_POSITION = 2
|
|
27
|
-
METHOD_NAME_POSITION = 3
|
|
28
|
-
|
|
29
|
-
private
|
|
23
|
+
register(REGEXP)
|
|
30
24
|
|
|
31
25
|
# Return method matcher
|
|
32
26
|
#
|
|
@@ -39,6 +33,8 @@ module Mutant
|
|
|
39
33
|
end
|
|
40
34
|
memoize :matcher
|
|
41
35
|
|
|
36
|
+
private
|
|
37
|
+
|
|
42
38
|
# Return method
|
|
43
39
|
#
|
|
44
40
|
# @return [Method, UnboundMethod]
|
|
@@ -50,7 +46,7 @@ module Mutant
|
|
|
50
46
|
method.name == method_name
|
|
51
47
|
end or raise NameError, "Cannot find method #{identifier}"
|
|
52
48
|
end
|
|
53
|
-
memoize :method, :
|
|
49
|
+
memoize :method, freezer: :noop
|
|
54
50
|
|
|
55
51
|
# Return scope name
|
|
56
52
|
#
|
|
@@ -59,7 +55,7 @@ module Mutant
|
|
|
59
55
|
# @api private
|
|
60
56
|
#
|
|
61
57
|
def scope_name
|
|
62
|
-
match[
|
|
58
|
+
match[__method__]
|
|
63
59
|
end
|
|
64
60
|
|
|
65
61
|
# Return scope
|
|
@@ -79,7 +75,7 @@ module Mutant
|
|
|
79
75
|
# @api private
|
|
80
76
|
#
|
|
81
77
|
def method_name
|
|
82
|
-
match[
|
|
78
|
+
match[__method__].to_sym
|
|
83
79
|
end
|
|
84
80
|
|
|
85
81
|
# Return scope symbol
|
|
@@ -89,7 +85,7 @@ module Mutant
|
|
|
89
85
|
# @api private
|
|
90
86
|
#
|
|
91
87
|
def scope_symbol
|
|
92
|
-
match[
|
|
88
|
+
match[__method__]
|
|
93
89
|
end
|
|
94
90
|
|
|
95
91
|
# Return matcher class
|
|
@@ -7,8 +7,6 @@ module Mutant
|
|
|
7
7
|
# Namespace classifier
|
|
8
8
|
class Namespace < self
|
|
9
9
|
|
|
10
|
-
private
|
|
11
|
-
|
|
12
10
|
# Return matcher
|
|
13
11
|
#
|
|
14
12
|
# @return [Matcher]
|
|
@@ -19,6 +17,8 @@ module Mutant
|
|
|
19
17
|
self.class::MATCHER.new(cache, namespace)
|
|
20
18
|
end
|
|
21
19
|
|
|
20
|
+
private
|
|
21
|
+
|
|
22
22
|
# Return namespace
|
|
23
23
|
#
|
|
24
24
|
# @return [Class, Module]
|
|
@@ -26,23 +26,21 @@ module Mutant
|
|
|
26
26
|
# @api private
|
|
27
27
|
#
|
|
28
28
|
def namespace
|
|
29
|
-
Classifier.constant_lookup(match[
|
|
29
|
+
Classifier.constant_lookup(match[__method__].to_s)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Recursive namespace classifier
|
|
33
33
|
class Recursive < self
|
|
34
|
-
REGEXP = /\A(
|
|
34
|
+
REGEXP = /\A(?<namespace>#{SCOPE_PATTERN})\*\z/.freeze
|
|
35
35
|
MATCHER = Matcher::Namespace
|
|
36
|
-
|
|
37
|
-
register
|
|
36
|
+
register(REGEXP)
|
|
38
37
|
end # Recursive
|
|
39
38
|
|
|
40
39
|
# Recursive namespace classifier
|
|
41
40
|
class Flat < self
|
|
42
|
-
REGEXP = /\A(
|
|
41
|
+
REGEXP = /\A(?<namespace>#{SCOPE_PATTERN})\z/.freeze
|
|
43
42
|
MATCHER = Matcher::Scope
|
|
44
|
-
|
|
45
|
-
register
|
|
43
|
+
register(REGEXP)
|
|
46
44
|
end # Flat
|
|
47
45
|
|
|
48
46
|
end # Namespace
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Mutant
|
|
4
4
|
class CLI
|
|
5
5
|
# A classifier for input strings
|
|
6
|
-
class Classifier
|
|
6
|
+
class Classifier
|
|
7
7
|
include AbstractType, Adamantium::Flat, Concord.new(:cache, :match)
|
|
8
8
|
|
|
9
9
|
include Equalizer.new(:identifier)
|
|
@@ -22,7 +22,7 @@ module Mutant
|
|
|
22
22
|
(?:#{SCOPE_OPERATOR}#{SCOPE_NAME_PATTERN})*
|
|
23
23
|
/x.freeze
|
|
24
24
|
|
|
25
|
-
REGISTRY =
|
|
25
|
+
REGISTRY = {}
|
|
26
26
|
|
|
27
27
|
# Register classifier
|
|
28
28
|
#
|
|
@@ -30,8 +30,8 @@ module Mutant
|
|
|
30
30
|
#
|
|
31
31
|
# @api private
|
|
32
32
|
#
|
|
33
|
-
def self.register
|
|
34
|
-
REGISTRY
|
|
33
|
+
def self.register(regexp)
|
|
34
|
+
REGISTRY[regexp] = self
|
|
35
35
|
end
|
|
36
36
|
private_class_method :register
|
|
37
37
|
|
|
@@ -54,47 +54,45 @@ module Mutant
|
|
|
54
54
|
|
|
55
55
|
# Return matchers for input
|
|
56
56
|
#
|
|
57
|
-
# @
|
|
57
|
+
# @param [Cache] cache
|
|
58
|
+
# @param [String] pattern
|
|
59
|
+
#
|
|
60
|
+
# @return [Matcher]
|
|
58
61
|
# if a classifier handles the input
|
|
59
62
|
#
|
|
60
|
-
# @
|
|
63
|
+
# @raise [RuntimeError]
|
|
61
64
|
# otherwise
|
|
62
65
|
#
|
|
63
66
|
# @api private
|
|
64
67
|
#
|
|
65
|
-
def self.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
def self.run(cache, pattern)
|
|
69
|
+
matches = find(pattern)
|
|
70
|
+
case matches.length
|
|
71
|
+
when 0
|
|
72
|
+
raise Error, "No matcher handles: #{pattern.inspect}"
|
|
73
|
+
when 1
|
|
74
|
+
klass, match = matches.first
|
|
75
|
+
klass.new(cache, match).matcher
|
|
76
|
+
else
|
|
77
|
+
raise Error, "More than one matcher found for: #{pattern.inspect}"
|
|
78
|
+
end
|
|
73
79
|
end
|
|
74
80
|
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# @param [Cache] cache
|
|
81
|
+
# Find classifiers
|
|
78
82
|
#
|
|
79
83
|
# @param [String] input
|
|
80
84
|
#
|
|
81
|
-
# @return [Classifier]
|
|
82
|
-
# if input is handled by classifier
|
|
83
|
-
#
|
|
84
|
-
# @return [nil]
|
|
85
|
-
# otherwise
|
|
86
|
-
#
|
|
87
85
|
# @api private
|
|
88
86
|
#
|
|
89
|
-
def self.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
def self.find(input)
|
|
88
|
+
REGISTRY.each_with_object([]) do |(regexp, klass), matches|
|
|
89
|
+
match = regexp.match(input)
|
|
90
|
+
if match
|
|
91
|
+
matches << [klass, match]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
94
|
end
|
|
95
|
-
|
|
96
|
-
# No protected_class_method in ruby :(
|
|
97
|
-
class << self; protected :run; end
|
|
95
|
+
private_class_method :find
|
|
98
96
|
|
|
99
97
|
# Enumerate subjects
|
|
100
98
|
#
|