From 8190bce8bc7249b7b9f3680195336eb3ca9508ee Mon Sep 17 00:00:00 2001
From: David Heinemeier Hansson <david@loudthinking.com>
Date: Tue, 17 Jun 2008 14:01:37 -0500
Subject: Added block-call style to link_to [Sam Stephenson/DHH]

---
 actionpack/CHANGELOG                             |  6 +++
 actionpack/lib/action_view/helpers/url_helper.rb | 60 +++++++++++++++++-------
 actionpack/test/template/url_helper_test.rb      |  8 ++++
 3 files changed, 56 insertions(+), 18 deletions(-)

diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index affefabe4b..3e977e1519 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,11 @@
 *Edge*
 
+* Added block-call style to link_to [Sam Stephenson/DHH]. Example:
+
+    <% link_to(@profile) do %>
+      <strong><%= @profile.name %></strong> -- <span>Check it out!!</span>
+    <% end %>
+
 * Performance: integration test benchmarking and profiling.  [Jeremy Kemper]
 
 * Make caching more aware of mime types. Ensure request format is not considered while expiring cache.  [Jonathan del Strother]
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 4b12adf225..baecd304cd 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -90,6 +90,13 @@ module ActionView
       # link will be used in place of a referrer if none exists. If nil is passed as
       # a name, the link itself will become the name.
       #
+      # ==== Signatures
+      #
+      #   link_to(name, options = {}, html_options = nil)
+      #   link_to(options = {}, html_options = nil) do
+      #     # name
+      #   end
+      #
       # ==== Options
       # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
       #   prompt with the question specified. If the user accepts, the link is
@@ -147,6 +154,13 @@ module ActionView
       #   link_to "Profiles", :controller => "profiles"
       #   # => <a href="/profiles">Profiles</a>
       #
+      # You can use a block as well if your link target is hard to fit into the name parameter. ERb example:
+      #
+      #   <% link_to(@profile) do %>
+      #     <strong><%= @profile.name %></strong> -- <span>Check it out!!</span>
+      #   <% end %>
+      #   # => <a href="/profiles/1"><strong>David</strong> -- <span>Check it out!!</span></a>
+      #
       # Classes and ids for CSS are easy to produce:
       #
       #   link_to "Articles", articles_path, :id => "news", :class => "article"
@@ -189,27 +203,37 @@ module ActionView
       #        f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
       #        var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); 
       #        m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>
-      def link_to(name, options = {}, html_options = nil)
-        url = case options
-          when String
-            options
-          when :back
-            @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
+      def link_to(*args, &block)
+        if block_given?
+          options      = args.first || {}
+          html_options = args.second
+          concat(link_to(capture(&block), options, html_options))
+        else
+          name         = args.first
+          options      = args.second || {}
+          html_options = args.third
+
+          url = case options
+            when String
+              options
+            when :back
+              @controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
+            else
+              self.url_for(options)
+            end
+
+          if html_options
+            html_options = html_options.stringify_keys
+            href = html_options['href']
+            convert_options_to_javascript!(html_options, url)
+            tag_options = tag_options(html_options)
           else
-            self.url_for(options)
+            tag_options = nil
           end
-
-        if html_options
-          html_options = html_options.stringify_keys
-          href = html_options['href']
-          convert_options_to_javascript!(html_options, url)
-          tag_options = tag_options(html_options)
-        else
-          tag_options = nil
+      
+          href_attr = "href=\"#{url}\"" unless href
+          "<a #{href_attr}#{tag_options}>#{name || url}</a>"
         end
-        
-        href_attr = "href=\"#{url}\"" unless href
-        "<a #{href_attr}#{tag_options}>#{name || url}</a>"
       end
 
       # Generates a form containing a single button that submits to the URL created
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index d45ea08a6f..0713cea8ac 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -211,6 +211,14 @@ class UrlHelperTest < ActionView::TestCase
   def test_link_tag_using_post_javascript_and_popup
     assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :method => :post, :confirm => "Are you serious?") }
   end
+
+  def test_link_tag_using_block
+    self.output_buffer = ''
+
+    link_to("http://example.com") { concat("Example site") }
+
+    assert_equal '<a href="http://example.com">Example site</a>', output_buffer
+  end
   
   def test_link_to_unless
     assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
-- 
cgit v1.2.3