Skip to content

Instantly share code, notes, and snippets.

@nathankleyn
Created February 13, 2012 21:05
Show Gist options
  • Save nathankleyn/1820476 to your computer and use it in GitHub Desktop.
Save nathankleyn/1820476 to your computer and use it in GitHub Desktop.
A writer addition for Rails' delagate feature.
diff --git a/.gitignore b/.gitignore
index 2dfdf96..79d884c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,5 @@ railties/test/initializer/root/log
railties/doc
railties/guides/output
railties/tmp
+.DS_Store
+nbproject
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 3a7652f..9ccb2b6 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -109,11 +109,12 @@ class Module
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
end
- if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
- raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
+ if (options[:prefix] == true || options[:writer]) && options[:to].to_s =~ /^[^a-z_]/
+ raise ArgumentError, "Can only automatically set the delegation prefix or make a writer method when delegating to a method."
end
prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
+ writer = !!options[:writer]
file, line = caller.first.split(':', 2)
line = line.to_i
@@ -141,6 +142,24 @@ class Module
end # end
end # end
EOS
+
+ if writer
+ module_eval(<<-EOS, file, line - 5)
+ if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}=")
+ remove_possible_method("#{prefix}#{method}=")
+ end
+
+ def #{prefix}#{method}=(*args, &block) # def customer_name=(*args, &block)
+ #{to}.__send__(#{method.inspect}=, *args, &block) # client.__send__(:name=, *args, &block)
+ rescue NoMethodError # rescue NoMethodError
+ if #{to}.nil? # if client.nil?
+ #{on_nil} # return # depends on :allow_nil
+ else # else
+ raise # raise
+ end # end
+ end # end
+ EOS
+ end
end
end
end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 75404ec..0841711 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -42,6 +42,10 @@ Invoice = Struct.new(:client) do
delegate :street, :city, :name, :to => :client, :prefix => :customer
end
+Bill = Struct.new(:client) do
+ delegate :name, :to => :client, :prefix => true, :writer => true
+end
+
Project = Struct.new(:description, :person) do
delegate :name, :to => :person, :allow_nil => true
delegate :to_f, :to => :description, :allow_nil => true
@@ -82,6 +86,12 @@ class ModuleTest < Test::Unit::TestCase
assert_equal "DAVID HANSSON", david.upcase
end
+ def test_delegation_to_methods_with_writer
+ bill = Bill.new(@david)
+ bill.client_name = "Nathan"
+ assert_equal "Nathan", bill.client_name
+ end
+
def test_missing_delegation_target
assert_raise(ArgumentError) do
Name.send :delegate, :nowhere
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment