From 2503cedf2c9ebb7e15029f126518f42ff0e5ee1c Mon Sep 17 00:00:00 2001 From: Jack Nagel Date: Sat, 19 Jan 2013 20:45:58 -0600 Subject: [PATCH] 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. --- Library/Homebrew/build_environment.rb | 4 ++-- Library/Homebrew/dependencies.rb | 2 +- Library/Homebrew/extend/object.rb | 15 ++++++++++++++ Library/Homebrew/global.rb | 1 + .../Homebrew/test/test_build_environment.rb | 14 +++++++++++++ Library/Homebrew/test/test_object.rb | 20 +++++++++++++++++++ 6 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Library/Homebrew/extend/object.rb create mode 100644 Library/Homebrew/test/test_object.rb diff --git a/Library/Homebrew/build_environment.rb b/Library/Homebrew/build_environment.rb index 18876f9542..60e0999773 100644 --- a/Library/Homebrew/build_environment.rb +++ b/Library/Homebrew/build_environment.rb @@ -18,9 +18,9 @@ class BuildEnvironment @settings.include? :userpaths end - def modify_build_environment + def modify_build_environment(context=nil) p = @settings.find { |s| Proc === s } - ENV.instance_eval(&p) unless p.nil? + ENV.instance_exec(context, &p) unless p.nil? end def _dump(*) diff --git a/Library/Homebrew/dependencies.rb b/Library/Homebrew/dependencies.rb index c2dd63d7dc..54de50f390 100644 --- a/Library/Homebrew/dependencies.rb +++ b/Library/Homebrew/dependencies.rb @@ -190,7 +190,7 @@ class Requirement # Overriding modify_build_environment is deprecated, pass a block to # the env DSL method instead. def modify_build_environment - env.modify_build_environment + env.modify_build_environment(self) end def env diff --git a/Library/Homebrew/extend/object.rb b/Library/Homebrew/extend/object.rb new file mode 100644 index 0000000000..8ffe5dc90d --- /dev/null +++ b/Library/Homebrew/extend/object.rb @@ -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 diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index 6440506f8a..50d30e877d 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -3,6 +3,7 @@ require 'extend/pathname' require 'extend/ARGV' require 'extend/string' require 'extend/symbol' +require 'extend/object' require 'utils' require 'exceptions' require 'set' diff --git a/Library/Homebrew/test/test_build_environment.rb b/Library/Homebrew/test/test_build_environment.rb index d8a227f51b..6710662b56 100644 --- a/Library/Homebrew/test/test_build_environment.rb +++ b/Library/Homebrew/test/test_build_environment.rb @@ -31,6 +31,20 @@ class BuildEnvironmentTests < Test::Unit::TestCase dump = Marshal.dump(@env) assert Marshal.load(dump).userpaths? 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 class BuildEnvironmentDSLTests < Test::Unit::TestCase diff --git a/Library/Homebrew/test/test_object.rb b/Library/Homebrew/test/test_object.rb new file mode 100644 index 0000000000..debdd6c42c --- /dev/null +++ b/Library/Homebrew/test/test_object.rb @@ -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