diff --git a/config/flay.yml b/config/flay.yml index 4362efe3..a191eae4 100644 --- a/config/flay.yml +++ b/config/flay.yml @@ -1,3 +1,3 @@ --- threshold: 18 -total_score: 968 +total_score: 976 diff --git a/lib/mutant.rb b/lib/mutant.rb index 2c5f8c6c..f73ed49e 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -79,6 +79,7 @@ module Mutant end # Mutant require 'mutant/version' +require 'mutant/env' require 'mutant/ast' require 'mutant/ast/sexp' require 'mutant/ast/types' diff --git a/lib/mutant/cache.rb b/lib/mutant/cache.rb index ca65d550..e5a80598 100644 --- a/lib/mutant/cache.rb +++ b/lib/mutant/cache.rb @@ -1,7 +1,7 @@ module Mutant # An AST cache class Cache - include Equalizer.new + include Equalizer.new, Adamantium::Mutable # Initialize object # diff --git a/lib/mutant/cli.rb b/lib/mutant/cli.rb index ded2fb62..3edd0f49 100644 --- a/lib/mutant/cli.rb +++ b/lib/mutant/cli.rb @@ -39,7 +39,7 @@ module Mutant # @api private # def initialize(arguments = []) - @builder = Matcher::Builder.new(Cache.new) + @builder = Matcher::Builder.new(Env::Boot.new(Reporter::CLI.new($stderr), Cache.new)) @debug = @fail_fast = @zombie = false @expected_coverage = 100.0 @integration = Integration::Null.new diff --git a/lib/mutant/env.rb b/lib/mutant/env.rb new file mode 100644 index 00000000..fd290fde --- /dev/null +++ b/lib/mutant/env.rb @@ -0,0 +1,36 @@ +module Mutant + # Abstract base class for mutant environments + class Env + include AbstractType, Adamantium + + # Return config + # + # @return [Config] + # + # @api private + # + abstract_method :config + + # Return cache + # + # @return [Cache] + # + # @api private + # + abstract_method :cache + + # Return reporter + # + # @return [Reporter] + # + # @api private + # + abstract_method :reporter + + # Boot environment used for matching + class Boot < self + include Concord::Public.new(:reporter, :cache) + end # Boot + + end # ENV +end # Mutant diff --git a/lib/mutant/matcher.rb b/lib/mutant/matcher.rb index dc32dc51..a07393e4 100644 --- a/lib/mutant/matcher.rb +++ b/lib/mutant/matcher.rb @@ -5,7 +5,7 @@ module Mutant # Default matcher build implementation # - # @param [Cache] cache + # @param [Env] env # @param [Object] input # # @return [undefined] diff --git a/lib/mutant/matcher/builder.rb b/lib/mutant/matcher/builder.rb index 1d603fb4..34048276 100644 --- a/lib/mutant/matcher/builder.rb +++ b/lib/mutant/matcher/builder.rb @@ -2,17 +2,17 @@ module Mutant class Matcher # Builder for complex matchers class Builder - include Concord.new(:cache), AST::Sexp + include Concord.new(:env), AST::Sexp # Initalize object # - # @param [Cache] cache + # @param [Cache] env # # @return [undefined] # # @api private # - def initialize(cache) + def initialize(env) super @matchers = [] @subject_ignores = [] @@ -28,7 +28,7 @@ module Mutant # @api private # def add_subject_ignore(expression) - @subject_ignores << expression.matcher(cache) + @subject_ignores << expression.matcher(env) self end @@ -54,7 +54,7 @@ module Mutant # @api private # def add_match_expression(expression) - @matchers << expression.matcher(cache) + @matchers << expression.matcher(env) self end diff --git a/lib/mutant/matcher/method.rb b/lib/mutant/matcher/method.rb index 280cd37d..8eaea01c 100644 --- a/lib/mutant/matcher/method.rb +++ b/lib/mutant/matcher/method.rb @@ -2,7 +2,7 @@ module Mutant class Matcher # Matcher for subjects that are a specific method class Method < self - include Adamantium::Flat, Concord::Public.new(:cache, :scope, :method) + include Adamantium::Flat, Concord::Public.new(:env, :scope, :method) include Equalizer.new(:identification) # Methods within rbx kernel directory are precompiled and their source @@ -78,7 +78,7 @@ module Mutant # @api private # def ast - cache.parse(source_path) + env.cache.parse(source_path) end # Return path to source diff --git a/lib/mutant/matcher/method/instance.rb b/lib/mutant/matcher/method/instance.rb index 8cb15f35..398ae288 100644 --- a/lib/mutant/matcher/method/instance.rb +++ b/lib/mutant/matcher/method/instance.rb @@ -7,7 +7,7 @@ module Mutant # Dispatching builder, detects memoizable case # - # @param [Cache] cache + # @param [Env] env # @param [Class, Module] scope # @param [UnboundMethod] method # @@ -15,10 +15,10 @@ module Mutant # # @api private # - def self.build(cache, scope, method) + def self.build(env, scope, method) name = method.name if scope.ancestors.include?(::Memoizable) && scope.memoized?(name) - return Memoized.new(cache, scope, method) + return Memoized.new(env, scope, method) end super end diff --git a/lib/mutant/matcher/methods.rb b/lib/mutant/matcher/methods.rb index 247400f3..0b21ab1c 100644 --- a/lib/mutant/matcher/methods.rb +++ b/lib/mutant/matcher/methods.rb @@ -2,7 +2,7 @@ module Mutant class Matcher # Abstract base class for matcher that returns method subjects from scope class Methods < self - include AbstractType, Concord::Public.new(:cache, :scope) + include AbstractType, Concord::Public.new(:env, :scope) # Enumerate subjects # @@ -56,7 +56,7 @@ module Mutant # def subjects methods.map do |method| - matcher.build(cache, scope, method) + matcher.build(env, scope, method) end.flat_map(&:to_a) end memoize :subjects diff --git a/lib/mutant/matcher/namespace.rb b/lib/mutant/matcher/namespace.rb index 40a109cf..1a665324 100644 --- a/lib/mutant/matcher/namespace.rb +++ b/lib/mutant/matcher/namespace.rb @@ -5,7 +5,7 @@ module Mutant # # rubocop:disable LineLength class Namespace < self - include Concord::Public.new(:cache, :expression) + include Concord::Public.new(:env, :expression) # Enumerate subjects # @@ -36,7 +36,7 @@ module Mutant # def scopes ::ObjectSpace.each_object(Module).each_with_object([]) do |scope, aggregate| - aggregate << Scope.new(cache, scope) if match?(scope) + aggregate << Scope.new(env, scope) if match?(scope) end.sort_by(&:identification) end memoize :scopes diff --git a/lib/mutant/matcher/scope.rb b/lib/mutant/matcher/scope.rb index 92b28f34..e7c3d2f5 100644 --- a/lib/mutant/matcher/scope.rb +++ b/lib/mutant/matcher/scope.rb @@ -2,7 +2,7 @@ module Mutant class Matcher # Matcher for specific namespace class Scope < self - include Concord::Public.new(:cache, :scope) + include Concord::Public.new(:env, :scope) MATCHERS = [ Matcher::Methods::Singleton, @@ -34,7 +34,7 @@ module Mutant return to_enum unless block_given? MATCHERS.each do |matcher| - matcher.new(cache, scope).each(&block) + matcher.new(env, scope).each(&block) end self diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 20e6bdd4..5f3a8a66 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,8 +30,8 @@ $LOAD_PATH << File.join(TestApp.root, 'lib') require 'test_app' module Fixtures - AST_CACHE = Mutant::Cache.new -end + BOOT_ENV = Mutant::Env::Boot.new(Mutant::Reporter::CLI.new(STDERR), Mutant::Cache.new) +end # Fixtures module ParserHelper def generate(node) diff --git a/spec/unit/mutant/cli_new_spec.rb b/spec/unit/mutant/cli_new_spec.rb index 4733033d..a67e7091 100644 --- a/spec/unit/mutant/cli_new_spec.rb +++ b/spec/unit/mutant/cli_new_spec.rb @@ -29,8 +29,8 @@ describe Mutant::CLI, '.new' do let(:expected_integration) { Mutant::Integration::Null.new } let(:expected_reporter) { Mutant::Reporter::CLI.new($stdout) } - let(:ns) { Mutant::Matcher } - let(:cache) { Mutant::Cache.new } + let(:ns) { Mutant::Matcher } + let(:env) { Fixtures::BOOT_ENV } let(:cli) { object.new(arguments) } @@ -71,7 +71,7 @@ describe Mutant::CLI, '.new' do let(:arguments) { %w[TestApp::Literal#float] } let(:expected_matcher) do - ns::Method::Instance.new(cache, TestApp::Literal, TestApp::Literal.instance_method(:float)) + ns::Method::Instance.new(env, TestApp::Literal, TestApp::Literal.instance_method(:float)) end it_should_behave_like 'a cli parser' @@ -80,7 +80,7 @@ describe Mutant::CLI, '.new' do context 'with debug flag' do let(:pattern) { 'TestApp*' } let(:arguments) { %W[--debug #{pattern}] } - let(:expected_matcher) { ns::Namespace.new(cache, Mutant::Expression.parse(pattern)) } + let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) } it_should_behave_like 'a cli parser' @@ -92,7 +92,7 @@ describe Mutant::CLI, '.new' do context 'with zombie flag' do let(:pattern) { 'TestApp*' } let(:arguments) { %W[--zombie #{pattern}] } - let(:expected_matcher) { ns::Namespace.new(cache, Mutant::Expression.parse(pattern)) } + let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) } it_should_behave_like 'a cli parser' @@ -104,7 +104,7 @@ describe Mutant::CLI, '.new' do context 'with namespace pattern' do let(:pattern) { 'TestApp*' } let(:arguments) { [pattern] } - let(:expected_matcher) { ns::Namespace.new(cache, Mutant::Expression.parse(pattern)) } + let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) } it_should_behave_like 'a cli parser' end @@ -124,7 +124,7 @@ describe Mutant::CLI, '.new' do let(:expected_matcher) do matcher = ns::Method::Instance.new( - cache, + env, TestApp::Literal, TestApp::Literal.instance_method(:float) ) predicate = Morpher.compile( diff --git a/spec/unit/mutant/matcher/method/instance_spec.rb b/spec/unit/mutant/matcher/method/instance_spec.rb index 33478417..d432b5b7 100644 --- a/spec/unit/mutant/matcher/method/instance_spec.rb +++ b/spec/unit/mutant/matcher/method/instance_spec.rb @@ -3,12 +3,12 @@ require 'spec_helper' # rubocop:disable ClassAndModuleChildren describe Mutant::Matcher::Method::Instance do - let(:cache) { Fixtures::AST_CACHE } + let(:env) { Fixtures::BOOT_ENV } describe '#each' do subject { object.each { |subject| yields << subject } } - let(:object) { described_class.new(cache, scope, method) } + let(:object) { described_class.new(env, scope, method) } let(:method) { scope.instance_method(method_name) } let(:yields) { [] } let(:namespace) { self.class } @@ -118,7 +118,7 @@ describe Mutant::Matcher::Method::Instance do describe '.build' do let(:object) { described_class } - subject { object.build(cache, scope, method) } + subject { object.build(env, scope, method) } let(:scope) do Class.new do @@ -141,13 +141,13 @@ describe Mutant::Matcher::Method::Instance do context 'with unmemoized method' do let(:method_name) { :bar } - it { should eql(described_class.new(cache, scope, method)) } + it { should eql(described_class.new(env, scope, method)) } end context 'with memoized method' do let(:method_name) { :foo } - it { should eql(described_class::Memoized.new(cache, scope, method)) } + it { should eql(described_class::Memoized.new(env, scope, method)) } end end end diff --git a/spec/unit/mutant/matcher/method/singleton_spec.rb b/spec/unit/mutant/matcher/method/singleton_spec.rb index e12e89b0..d8a48634 100644 --- a/spec/unit/mutant/matcher/method/singleton_spec.rb +++ b/spec/unit/mutant/matcher/method/singleton_spec.rb @@ -4,14 +4,14 @@ require 'spec_helper' describe Mutant::Matcher::Method::Singleton, '#each' do subject { object.each { |subject| yields << subject } } - let(:object) { described_class.new(cache, scope, method) } - let(:method) { scope.method(method_name) } - let(:cache) { Fixtures::AST_CACHE } - let(:yields) { [] } - let(:namespace) { self.class } - let(:scope) { self.class::Foo } - let(:type) { :defs } - let(:method_arity) { 0 } + let(:object) { described_class.new(env, scope, method) } + let(:method) { scope.method(method_name) } + let(:env) { Fixtures::BOOT_ENV } + let(:yields) { [] } + let(:namespace) { self.class } + let(:scope) { self.class::Foo } + let(:type) { :defs } + let(:method_arity) { 0 } def name node.children[1] diff --git a/spec/unit/mutant/matcher/methods/instance_spec.rb b/spec/unit/mutant/matcher/methods/instance_spec.rb index adb8cb94..1c5e4c2b 100644 --- a/spec/unit/mutant/matcher/methods/instance_spec.rb +++ b/spec/unit/mutant/matcher/methods/instance_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Mutant::Matcher::Methods::Instance, '#each' do - let(:object) { described_class.new(cache, Foo) } - let(:cache) { Mutant::Cache.new } + let(:object) { described_class.new(env, Foo) } + let(:env) { Fixtures::BOOT_ENV } subject { object.each { |matcher| yields << matcher } } @@ -46,9 +46,9 @@ describe Mutant::Matcher::Methods::Instance, '#each' do before do matcher = Mutant::Matcher::Method::Instance - allow(matcher).to receive(:new).with(cache, Foo, Foo.instance_method(:method_a)).and_return([subject_a]) - allow(matcher).to receive(:new).with(cache, Foo, Foo.instance_method(:method_b)).and_return([subject_b]) - allow(matcher).to receive(:new).with(cache, Foo, Foo.instance_method(:method_c)).and_return([subject_c]) + allow(matcher).to receive(:new).with(env, Foo, Foo.instance_method(:method_a)).and_return([subject_a]) + allow(matcher).to receive(:new).with(env, Foo, Foo.instance_method(:method_b)).and_return([subject_b]) + allow(matcher).to receive(:new).with(env, Foo, Foo.instance_method(:method_c)).and_return([subject_c]) end it 'should yield expected subjects' do diff --git a/spec/unit/mutant/matcher/methods/singleton_spec.rb b/spec/unit/mutant/matcher/methods/singleton_spec.rb index 82aa4b6a..4e9718f2 100644 --- a/spec/unit/mutant/matcher/methods/singleton_spec.rb +++ b/spec/unit/mutant/matcher/methods/singleton_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Mutant::Matcher::Methods::Singleton, '#each' do - let(:object) { described_class.new(cache, Foo) } - let(:cache) { Mutant::Cache.new } + let(:object) { described_class.new(env, Foo) } + let(:env) { Fixtures::BOOT_ENV } subject { object.each { |matcher| yields << matcher } } @@ -41,11 +41,11 @@ describe Mutant::Matcher::Methods::Singleton, '#each' do before do matcher = Mutant::Matcher::Method::Singleton matcher.stub(:new) - .with(cache, Foo, Foo.method(:method_a)).and_return([subject_a]) + .with(env, Foo, Foo.method(:method_a)).and_return([subject_a]) matcher.stub(:new) - .with(cache, Foo, Foo.method(:method_b)).and_return([subject_b]) + .with(env, Foo, Foo.method(:method_b)).and_return([subject_b]) matcher.stub(:new) - .with(cache, Foo, Foo.method(:method_c)).and_return([subject_c]) + .with(env, Foo, Foo.method(:method_c)).and_return([subject_c]) end it 'should yield expected subjects' do diff --git a/spec/unit/mutant/matcher/namespace_spec.rb b/spec/unit/mutant/matcher/namespace_spec.rb index 591d3175..62ef763d 100644 --- a/spec/unit/mutant/matcher/namespace_spec.rb +++ b/spec/unit/mutant/matcher/namespace_spec.rb @@ -1,10 +1,9 @@ require 'spec_helper' describe Mutant::Matcher::Namespace do - let(:object) { described_class.new(cache, Mutant::Expression.parse('TestApp*')) } - let(:yields) { [] } - - let(:cache) { Mutant::Cache.new } + let(:object) { described_class.new(env, Mutant::Expression.parse('TestApp*')) } + let(:yields) { [] } + let(:env) { Fixtures::BOOT_ENV } subject { object.each { |item| yields << item } } @@ -17,11 +16,11 @@ describe Mutant::Matcher::Namespace do let(:subject_b) { double('SubjectB') } before do - allow(Mutant::Matcher::Methods::Singleton).to receive(:new).with(cache, singleton_a).and_return([subject_a]) - allow(Mutant::Matcher::Methods::Instance).to receive(:new).with(cache, singleton_a).and_return([]) + allow(Mutant::Matcher::Methods::Singleton).to receive(:new).with(env, singleton_a).and_return([subject_a]) + allow(Mutant::Matcher::Methods::Instance).to receive(:new).with(env, singleton_a).and_return([]) - allow(Mutant::Matcher::Methods::Singleton).to receive(:new).with(cache, singleton_b).and_return([subject_b]) - allow(Mutant::Matcher::Methods::Instance).to receive(:new).with(cache, singleton_b).and_return([]) + allow(Mutant::Matcher::Methods::Singleton).to receive(:new).with(env, singleton_b).and_return([subject_b]) + allow(Mutant::Matcher::Methods::Instance).to receive(:new).with(env, singleton_b).and_return([]) allow(ObjectSpace).to receive(:each_object).with(Module).and_return([singleton_a, singleton_b, singleton_c]) end