Make mutant run under MRI 1.9.

* Add a Mutant::Loader::Eval that loads code via Kernel#eval
* Move Mutnat::Loader to Mutant::Loader::Rubinius (currently not used)
This commit is contained in:
Markus Schirp 2012-11-21 20:31:01 +01:00
parent d77042c872
commit 001f3c7d99
14 changed files with 154 additions and 86 deletions

View file

@ -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:

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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,6 +24,45 @@ module Mutant
#
def initialize(root)
@root = Helper.deep_clone(root)
run
end
# 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
# Rubinius script node based loaded
class Rubinius < self
private
# Run loader
#
# @return [undefined]
#
# @api private
#
def run(root)
Rubinius.run_script(compiled_code)
end
@ -72,5 +110,20 @@ module Mutant
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
end

View file

@ -75,7 +75,7 @@ module Mutant
def method
scope.instance_method(method_name)
end
memoize :method
memoize :method, :freezer => :noop
end
end

View file

@ -61,7 +61,7 @@ module Mutant
def method
scope.method(method_name)
end
memoize :method
memoize :method, :freezer => :noop
# Test for node match
#

View file

@ -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

View file

@ -100,7 +100,8 @@ module Mutant
# @api private
#
def reset
Loader.run(original_root)
Loader::Eval.run(original_root)
self
end
private

View file

@ -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 }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 }