diff --git a/.travis.yml b/.travis.yml index 4a4353be..47fb4896 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ language: ruby script: 'bundle exec rake spec' rvm: # - 1.8.7 disabled while spiking mutations + - 1.9.2 + - 1.9.3 - rbx-18mode - rbx-19mode notifications: diff --git a/Gemfile b/Gemfile index c5124238..8bb68843 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,7 @@ gem 'abstract_class', :git => 'https://github.com/dkubb/abstract_class.git' gem 'equalizer', :git => 'https://github.com/dkubb/equalizer.git' gem 'anima', :git => 'https://github.com/mbj/anima.git' gem 'to_source', :git => 'https://github.com/mbj/to_source.git' +gem 'melbourne', :git => 'https://github.com/mbj/melbourne.git' group :development do gem 'rake', '~> 0.9.2' diff --git a/lib/mutant/context.rb b/lib/mutant/context.rb index ee0c13d7..e8f097e0 100644 --- a/lib/mutant/context.rb +++ b/lib/mutant/context.rb @@ -5,8 +5,6 @@ module Mutant # Return root ast node # - # @param [Rubinius::AST::Node] node - # # @return [Rubinis::AST::Script] # # @api private @@ -34,19 +32,5 @@ module Mutant def initialize(source_path) @source_path = source_path end - - # Return script node - # - # @param [Rubinius::AST::Node] node - # - # @return [Rubinius::AST::Script] - # - # @api private - # - def script(node) - Rubinius::AST::Script.new(node).tap do |script| - script.file = source_path - end - end end end diff --git a/lib/mutant/context/scope.rb b/lib/mutant/context/scope.rb index ab9c48ab..d99d587e 100644 --- a/lib/mutant/context/scope.rb +++ b/lib/mutant/context/scope.rb @@ -48,7 +48,7 @@ module Mutant root = root_ast block = Rubinius::AST::Block.new(1, [node]) root.body = scope_class.new(1, root.name, block) - script(root) + root end # Return unqualified name of scope diff --git a/lib/mutant/loader.rb b/lib/mutant/loader.rb index c25bf95d..dc72bea5 100644 --- a/lib/mutant/loader.rb +++ b/lib/mutant/loader.rb @@ -1,20 +1,19 @@ module Mutant - # A method object for inserting an AST into the Rubinius VM - # - # The idea is to split the steps for a mutation into documented - # methods. Also subclasses can override the steps. Also passing - # around the root node is not needed with a method object. - # - # As the initializer does the work there is no need for the - # instances of this class to be used outside of this class, hence - # the Loader.new method is private and the Loader.run method - # returns self. - # + # Base class for code loaders class Loader + include AbstractClass extend MethodObject private + # Run the loader + # + # @return [undefined] + # + # @api private + # + abstract_method :run + # Initialize and insert mutation into vm # # @param [Rubinius::AST::Script] root @@ -25,51 +24,105 @@ module Mutant # def initialize(root) @root = Helper.deep_clone(root) - Rubinius.run_script(compiled_code) + run end - # Return compiled code - # - # @return [Rubinius::CompiledCode] - # - # @api private - # - # FIXME: rbx on travis is older than on my devbox. - # - def compiled_code - _script = script - _script.respond_to?(:compiled_code) ? _script.compiled_code : _script.compiled_method + # Eval based loader + class Eval < self + private + + # Run loader + # + # @return [undefined] + # + # @api private + # + def run + eval(source, TOPLEVEL_BINDING) + end + + # Return source + # + # @return [String] + # + # @api private + # + def source + ToSource.to_source(@root) + end end - # Return code script - # - # @return [Rubinius::CompiledCode::Script] - # - # @api private - # - def script - compiled_code_raw.create_script - end + # Rubinius script node based loaded + class Rubinius < self + private - # Return compiled code for node - # - # @return [Rubinius::CompiledCode] - # - # @api private - # - def compiled_code_raw - compiler.run - end + # Run loader + # + # @return [undefined] + # + # @api private + # + def run(root) + Rubinius.run_script(compiled_code) + end - # Return compiler loaded with mutated ast - # - # @return [Rubinius::Compiler] - # - # @api private - # - def compiler - Rubinius::Compiler.new(:bytecode, :compiled_method).tap do |compiler| - compiler.generator.input(@root) + # Return compiled code + # + # @return [Rubinius::CompiledCode] + # + # @api private + # + # FIXME: rbx on travis is older than on my devbox. + # + def compiled_code + _script = script + _script.respond_to?(:compiled_code) ? _script.compiled_code : _script.compiled_method + end + + # Return code script + # + # @return [Rubinius::CompiledCode::Script] + # + # @api private + # + def script + compiled_code_raw.create_script + end + + # Return compiled code for node + # + # @return [Rubinius::CompiledCode] + # + # @api private + # + def compiled_code_raw + compiler.run + end + + # Return compiler loaded with mutated ast + # + # @return [Rubinius::Compiler] + # + # @api private + # + def compiler + Rubinius::Compiler.new(:bytecode, :compiled_method).tap do |compiler| + compiler.generator.input(@root) + end + end + + # Return script node + # + # @param [Rubinius::AST::Node] node + # + # @return [Rubinius::AST::Script] + # + # @api private + # + def script(node) + Rubinius::AST::Script.new(node).tap do |script| + script.file = source_path + end end end end diff --git a/lib/mutant/matcher/method/instance.rb b/lib/mutant/matcher/method/instance.rb index f953461e..805fe794 100644 --- a/lib/mutant/matcher/method/instance.rb +++ b/lib/mutant/matcher/method/instance.rb @@ -75,7 +75,7 @@ module Mutant def method scope.instance_method(method_name) end - memoize :method + memoize :method, :freezer => :noop end end diff --git a/lib/mutant/matcher/method/singleton.rb b/lib/mutant/matcher/method/singleton.rb index 48c4e947..769d38d0 100644 --- a/lib/mutant/matcher/method/singleton.rb +++ b/lib/mutant/matcher/method/singleton.rb @@ -61,7 +61,7 @@ module Mutant def method scope.method(method_name) end - memoize :method + memoize :method, :freezer => :noop # Test for node match # diff --git a/lib/mutant/mutation.rb b/lib/mutant/mutation.rb index 840d7bb5..b4c3f037 100644 --- a/lib/mutant/mutation.rb +++ b/lib/mutant/mutation.rb @@ -21,7 +21,7 @@ module Mutant # Return mutated root node # - # @return [Rubinius::AST::Script] + # @return [Rubinius::AST::Node] # # @api private # @@ -37,7 +37,7 @@ module Mutant # @api private # def insert - Loader.run(root) + Loader::Eval.run(root) self end diff --git a/lib/mutant/subject.rb b/lib/mutant/subject.rb index d042d545..bd673c07 100644 --- a/lib/mutant/subject.rb +++ b/lib/mutant/subject.rb @@ -100,7 +100,8 @@ module Mutant # @api private # def reset - Loader.run(original_root) + Loader::Eval.run(original_root) + self end private diff --git a/spec/integration/mutant/loader_spec.rb b/spec/integration/mutant/loader_spec.rb index d0714912..1fb02b27 100644 --- a/spec/integration/mutant/loader_spec.rb +++ b/spec/integration/mutant/loader_spec.rb @@ -11,7 +11,7 @@ describe Mutant, 'code loading' do let(:node) { 'def foo; :bar; end'.to_ast } let(:root) { context.root(node) } - subject { Mutant::Loader.run(root) } + subject { Mutant::Loader::Eval.run(root) } before { subject } diff --git a/spec/support/zombie.rb b/spec/support/zombie.rb index 45771898..a4ec68dd 100644 --- a/spec/support/zombie.rb +++ b/spec/support/zombie.rb @@ -51,13 +51,7 @@ module Zombie node.body = Rubinius::AST::ModuleScope.new(scope.line, node.name, scope.body) end - script = Rubinius::AST::Script.new(root) - script.file = path - - # For some reason loading is not the same as eval...? - # eval(root.to_source) - - ::Mutant::Loader.run(script) + ::Mutant::Loader::Eval.run(root) end private_class_method :zombify diff --git a/spec/unit/mutant/context/scope/root_spec.rb b/spec/unit/mutant/context/scope/root_spec.rb index 8a1ebc35..e6e89a8c 100644 --- a/spec/unit/mutant/context/scope/root_spec.rb +++ b/spec/unit/mutant/context/scope/root_spec.rb @@ -7,13 +7,9 @@ describe Mutant::Context::Scope, '#root' do let(:path) { mock('Path') } let(:node) { mock('Node') } - let(:constant) { subject.body } - let(:scope) { constant.body } + let(:scope) { subject.body } let(:scope_body) { scope.body } - it { should be_a(Rubinius::AST::Script) } - its(:file) { should be(path) } - it 'should wrap the ast under constant' do scope.should be_kind_of(Rubinius::AST::ClassScope) end diff --git a/spec/unit/mutant/loader/eval/class_methods/run_spec.rb b/spec/unit/mutant/loader/eval/class_methods/run_spec.rb new file mode 100644 index 00000000..cb222449 --- /dev/null +++ b/spec/unit/mutant/loader/eval/class_methods/run_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Mutant::Loader::Eval, '.run' do + + subject { object.run(node) } + + let(:object) { described_class } + + let(:source) do + # This test case will blow up when not executed + # under toplevel binding. + <<-RUBY + class SomeNamespace + class Bar + end + + class SomeOther + class Foo < Bar + end + end + end + RUBY + end + + let(:node) do + source.to_ast + end + + it 'should load nodes into vm' do + subject + ::SomeNamespace::SomeOther::Foo + end +end diff --git a/spec/unit/mutant/loader/class_methods/run_spec.rb b/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb similarity index 89% rename from spec/unit/mutant/loader/class_methods/run_spec.rb rename to spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb index 120d60be..3171049f 100644 --- a/spec/unit/mutant/loader/class_methods/run_spec.rb +++ b/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb @@ -1,6 +1,10 @@ require 'spec_helper' -describe Mutant::Loader, '.run' do +describe Mutant::Loader::Rubinius, '.run' do + before do + pending + end + subject { object.run(node) } let(:object) { described_class }