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' script: 'bundle exec rake spec'
rvm: rvm:
# - 1.8.7 disabled while spiking mutations # - 1.8.7 disabled while spiking mutations
- 1.9.2
- 1.9.3
- rbx-18mode - rbx-18mode
- rbx-19mode - rbx-19mode
notifications: 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 'equalizer', :git => 'https://github.com/dkubb/equalizer.git'
gem 'anima', :git => 'https://github.com/mbj/anima.git' gem 'anima', :git => 'https://github.com/mbj/anima.git'
gem 'to_source', :git => 'https://github.com/mbj/to_source.git' gem 'to_source', :git => 'https://github.com/mbj/to_source.git'
gem 'melbourne', :git => 'https://github.com/mbj/melbourne.git'
group :development do group :development do
gem 'rake', '~> 0.9.2' gem 'rake', '~> 0.9.2'

View file

@ -5,8 +5,6 @@ module Mutant
# Return root ast node # Return root ast node
# #
# @param [Rubinius::AST::Node] node
#
# @return [Rubinis::AST::Script] # @return [Rubinis::AST::Script]
# #
# @api private # @api private
@ -34,19 +32,5 @@ module Mutant
def initialize(source_path) def initialize(source_path)
@source_path = source_path @source_path = source_path
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 end

View file

@ -48,7 +48,7 @@ module Mutant
root = root_ast root = root_ast
block = Rubinius::AST::Block.new(1, [node]) block = Rubinius::AST::Block.new(1, [node])
root.body = scope_class.new(1, root.name, block) root.body = scope_class.new(1, root.name, block)
script(root) root
end end
# Return unqualified name of scope # Return unqualified name of scope

View file

@ -1,20 +1,19 @@
module Mutant module Mutant
# A method object for inserting an AST into the Rubinius VM # Base class for code loaders
#
# 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.
#
class Loader class Loader
include AbstractClass
extend MethodObject extend MethodObject
private private
# Run the loader
#
# @return [undefined]
#
# @api private
#
abstract_method :run
# Initialize and insert mutation into vm # Initialize and insert mutation into vm
# #
# @param [Rubinius::AST::Script] root # @param [Rubinius::AST::Script] root
@ -25,51 +24,105 @@ module Mutant
# #
def initialize(root) def initialize(root)
@root = Helper.deep_clone(root) @root = Helper.deep_clone(root)
Rubinius.run_script(compiled_code) run
end end
# Return compiled code # Eval based loader
# class Eval < self
# @return [Rubinius::CompiledCode] private
#
# @api private # Run loader
# #
# FIXME: rbx on travis is older than on my devbox. # @return [undefined]
# #
def compiled_code # @api private
_script = script #
_script.respond_to?(:compiled_code) ? _script.compiled_code : _script.compiled_method def run
eval(source, TOPLEVEL_BINDING)
end
# Return source
#
# @return [String]
#
# @api private
#
def source
ToSource.to_source(@root)
end
end end
# Return code script # Rubinius script node based loaded
# class Rubinius < self
# @return [Rubinius::CompiledCode::Script] private
#
# @api private
#
def script
compiled_code_raw.create_script
end
# Return compiled code for node # Run loader
# #
# @return [Rubinius::CompiledCode] # @return [undefined]
# #
# @api private # @api private
# #
def compiled_code_raw def run(root)
compiler.run Rubinius.run_script(compiled_code)
end end
# Return compiler loaded with mutated ast # Return compiled code
# #
# @return [Rubinius::Compiler] # @return [Rubinius::CompiledCode]
# #
# @api private # @api private
# #
def compiler # FIXME: rbx on travis is older than on my devbox.
Rubinius::Compiler.new(:bytecode, :compiled_method).tap do |compiler| #
compiler.generator.input(@root) 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 end
end end

View file

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

View file

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

View file

@ -21,7 +21,7 @@ module Mutant
# Return mutated root node # Return mutated root node
# #
# @return [Rubinius::AST::Script] # @return [Rubinius::AST::Node]
# #
# @api private # @api private
# #
@ -37,7 +37,7 @@ module Mutant
# @api private # @api private
# #
def insert def insert
Loader.run(root) Loader::Eval.run(root)
self self
end end

View file

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

View file

@ -11,7 +11,7 @@ describe Mutant, 'code loading' do
let(:node) { 'def foo; :bar; end'.to_ast } let(:node) { 'def foo; :bar; end'.to_ast }
let(:root) { context.root(node) } let(:root) { context.root(node) }
subject { Mutant::Loader.run(root) } subject { Mutant::Loader::Eval.run(root) }
before { subject } before { subject }

View file

@ -51,13 +51,7 @@ module Zombie
node.body = Rubinius::AST::ModuleScope.new(scope.line, node.name, scope.body) node.body = Rubinius::AST::ModuleScope.new(scope.line, node.name, scope.body)
end end
script = Rubinius::AST::Script.new(root) ::Mutant::Loader::Eval.run(root)
script.file = path
# For some reason loading is not the same as eval...?
# eval(root.to_source)
::Mutant::Loader.run(script)
end end
private_class_method :zombify private_class_method :zombify

View file

@ -7,13 +7,9 @@ describe Mutant::Context::Scope, '#root' do
let(:path) { mock('Path') } let(:path) { mock('Path') }
let(:node) { mock('Node') } let(:node) { mock('Node') }
let(:constant) { subject.body } let(:scope) { subject.body }
let(:scope) { constant.body }
let(:scope_body) { scope.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 it 'should wrap the ast under constant' do
scope.should be_kind_of(Rubinius::AST::ClassScope) scope.should be_kind_of(Rubinius::AST::ClassScope)
end 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' require 'spec_helper'
describe Mutant::Loader, '.run' do describe Mutant::Loader::Rubinius, '.run' do
before do
pending
end
subject { object.run(node) } subject { object.run(node) }
let(:object) { described_class } let(:object) { described_class }