Object#instance_exec for Ruby 1.8.6

Not thread safe! But I don't think we care.

We want to evaluate the env DSL block in the context of ENV for asthetic
reasons, but we also want access to methods on the requirement instance.
We can use #instance_exec to pass the requirement itself into the block:

  class Foo < Requirement
    env do |req|
      append 'PATH', req.some_path
    end

    def some_path
      which 'something'
    end
  end

Also add a simplified version of Object#instance_exec for Ruby 1.8.6.
This commit is contained in:
Jack Nagel 2013-01-19 20:45:58 -06:00
parent c53af42117
commit 2503cedf2c
6 changed files with 53 additions and 3 deletions

View File

@ -18,9 +18,9 @@ class BuildEnvironment
@settings.include? :userpaths @settings.include? :userpaths
end end
def modify_build_environment def modify_build_environment(context=nil)
p = @settings.find { |s| Proc === s } p = @settings.find { |s| Proc === s }
ENV.instance_eval(&p) unless p.nil? ENV.instance_exec(context, &p) unless p.nil?
end end
def _dump(*) def _dump(*)

View File

@ -190,7 +190,7 @@ class Requirement
# Overriding modify_build_environment is deprecated, pass a block to # Overriding modify_build_environment is deprecated, pass a block to
# the env DSL method instead. # the env DSL method instead.
def modify_build_environment def modify_build_environment
env.modify_build_environment env.modify_build_environment(self)
end end
def env def env

View File

@ -0,0 +1,15 @@
class Object
def instance_exec(*args, &block)
method_name = :__temp_instance_exec_method
singleton_class = (class << self; self; end)
singleton_class.class_eval do
define_method(method_name, &block)
end
send(method_name, *args)
ensure
singleton_class.class_eval do
remove_method(method_name) if method_defined?(method_name)
end
end unless method_defined?(:instance_exec)
end

View File

@ -3,6 +3,7 @@ require 'extend/pathname'
require 'extend/ARGV' require 'extend/ARGV'
require 'extend/string' require 'extend/string'
require 'extend/symbol' require 'extend/symbol'
require 'extend/object'
require 'utils' require 'utils'
require 'exceptions' require 'exceptions'
require 'set' require 'set'

View File

@ -31,6 +31,20 @@ class BuildEnvironmentTests < Test::Unit::TestCase
dump = Marshal.dump(@env) dump = Marshal.dump(@env)
assert Marshal.load(dump).userpaths? assert Marshal.load(dump).userpaths?
end end
def test_env_block
foo = mock("foo")
@env << Proc.new { foo.some_message }
foo.expects(:some_message)
@env.modify_build_environment
end
def test_env_block_with_argument
foo = mock("foo")
@env << Proc.new { |x| x.some_message }
foo.expects(:some_message)
@env.modify_build_environment(foo)
end
end end
class BuildEnvironmentDSLTests < Test::Unit::TestCase class BuildEnvironmentDSLTests < Test::Unit::TestCase

View File

@ -0,0 +1,20 @@
require 'testing_env'
require 'extend/object'
class InstanceExecTests < Test::Unit::TestCase
def test_evaluates_in_context_of_receiver
assert_equal 1, [1].instance_exec { first }
end
def test_passes_arguments_to_block
assert_equal 2, [1].instance_exec(1) { |x| first + x }
end
def test_does_not_persist_temporary_singleton_method
obj = Object.new
before = obj.methods
obj.instance_exec { methods }
after = obj.methods
assert_equal before, after
end
end