Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/plataformatec/show_for
Browse files Browse the repository at this point in the history
  • Loading branch information
grimen committed Jan 9, 2010
2 parents eff32cd + 9ff396a commit 2d6d195
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 67 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.rdoc
@@ -0,0 +1,17 @@
== 0.1.2

* enhancements
* allow f.attribute :nickname, :in => :profile as association shortcut

* deprecations
* :method now becomes :using

== 0.1.1

* enhancements
* HAML compatibility (by github.com/grimen)
* blank_content support (by github.com/grimen)

== 0.1

* First release
12 changes: 9 additions & 3 deletions README.rdoc
Expand Up @@ -4,6 +4,7 @@ ShowFor allows you to quickly show a model information with I18n features.

<% show_for @user do |u| %>
<%= u.attribute :name %>
<%= u.attribute :nickname, :in => :profile %>
<%= u.attribute :confirmed? %>
<%= u.attribute :created_at, :format => :short %>
<%= u.attribute :last_sign_in_at, :if_blank => "User did not access yet"
Expand Down Expand Up @@ -109,7 +110,8 @@ show_for also supports associations.

<% show_for @artwork do |a| %>
<%= a.association :artist %>
<%= a.association :artist, :method => :name_with_title %>
<%= a.association :artist, :using => :name_with_title %>
<%= a.attribute :name_with_title, :in => :artist %>

<%= a.association :tags %>
<%= a.association :tags, :to_sentence => true %>
Expand All @@ -125,7 +127,7 @@ show_for also supports associations.
The first is a has_one or belongs_to association, which works like an attribute
to show_for, except it will retrieve the artist association and try to find a
proper method from ShowFor.association_methods to be used. You can pass
the option :method to tell (and not guess) which method from the association
the option :using to tell (and not guess) which method from the association
to use.

:tags is a has_and_belongs_to_many association which will return a collection.
Expand All @@ -137,10 +139,14 @@ You can also pass a block which expects an argument to association. In such case
a wrapper for the collection is still created and the block just iterates over the
collection objects.

== Contributors
== Maintainers

* José Valim (http://github.com/josevalim)

== Contributors

* Jonas Grimfelt (http://github.com/grimen)

== Bugs and Feedback

If you discover any bugs or want to drop a line, feel free to create an issue on GitHub.
Expand Down
3 changes: 0 additions & 3 deletions generators/show_for_install/templates/show_for.rb
Expand Up @@ -15,9 +15,6 @@
# The DOM class set for blank content tags. Default is "blank".
# config.blank_content_class = 'no_content'

# The default content for blank content tags. Default is "".
# config.blank_content = I18n.t(:'show_for.blank', :default => "Not specified")

# The separator between label and content. Default is "<br />".
# config.separator = "<br />"

Expand Down
52 changes: 52 additions & 0 deletions lib/show_for/association.rb
@@ -0,0 +1,52 @@
module ShowFor
module Association
def attribute(attribute_name, options={}, &block)
if association_name = options.delete(:in)
options[:using] = attribute_name
association(association_name, options, &block)
else
super
end
end

def association(association_name, options={}, &block)
apply_default_options!(association_name, options)

# If a block with an iterator was given, no need to calculate the labels
# since we want the collection to be yielded. Otherwise, calculate the values.
value = if collection_block?(block)
collection_block = block
@object.send(association_name)
elsif block
block
else
association = @object.send(association_name)
values = retrieve_values_from_association(association, options)

if options.delete(:to_sentence)
values.to_sentence
elsif joiner = options.delete(:join)
values.join(joiner)
else
values
end
end

wrap_label_and_content(association_name, value, options, &collection_block)
end

protected

def retrieve_values_from_association(association, options) #:nodoc:
sample = association.is_a?(Array) ? association.first : association

if options[:method]
options[:using] = options.delete(:method)
ActiveSupport::Deprecation.warn ":method is deprecated. Please use :using instead", caller
end

method = options.delete(:using) || ShowFor.association_methods.find { |m| sample.respond_to?(m) }
association.is_a?(Array) ? association.map(&method) : association.try(method)
end
end
end
18 changes: 18 additions & 0 deletions lib/show_for/attribute.rb
@@ -0,0 +1,18 @@
module ShowFor
module Attribute
def attribute(attribute_name, options={}, &block)
apply_default_options!(attribute_name, options)
collection_block, block = block, nil if collection_block?(block)

value = if block
block
elsif @object.respond_to?(:"human_#{attribute_name}")
@object.send :"human_#{attribute_name}"
else
@object.send(attribute_name)
end

wrap_label_and_content(attribute_name, value, options, &collection_block)
end
end
end
53 changes: 8 additions & 45 deletions lib/show_for/builder.rb
@@ -1,8 +1,12 @@
require 'show_for/attribute'
require 'show_for/association'
require 'show_for/content'
require 'show_for/label'

module ShowFor
class Builder
include ShowFor::Attribute
include ShowFor::Association
include ShowFor::Content
include ShowFor::Label

Expand All @@ -12,47 +16,6 @@ def initialize(object, template)
@object, @template = object, template
end

def attribute(attribute_name, options={}, &block)
apply_default_options!(attribute_name, options)
collection_block, block = block, nil if collection_block?(block)

value = if block
block
elsif @object.respond_to?(:"human_#{attribute_name}")
@object.send :"human_#{attribute_name}"
else
@object.send(attribute_name)
end

wrap_label_and_content(attribute_name, value, options, &collection_block)
end

def association(association_name, options={}, &block)
apply_default_options!(association_name, options)

# If a block with an iterator was given, no need to calculate the labels
# since we want the collection to be yielded. Otherwise, calculate the values.
value = if collection_block?(block)
collection_block = block
@object.send(association_name)
elsif block
block
else
association = @object.send(association_name)
values = retrieve_values_from_association(association, options)

if options.delete(:to_sentence)
values.to_sentence
elsif joiner = options.delete(:join)
values.join(joiner)
else
values
end
end

wrap_label_and_content(association_name, value, options, &collection_block)
end

protected

def object_name #:nodoc:
Expand Down Expand Up @@ -89,10 +52,10 @@ def wrap_with(type, content, options, safe=false, concat=false) #:nodoc:
concat ? @template.concat(html) : html
end

def retrieve_values_from_association(association, options) #:nodoc:
sample = association.is_a?(Array) ? association.first : association
method = options[:method] || ShowFor.association_methods.find { |m| sample.respond_to?(m) }
association.is_a?(Array) ? association.map(&method) : association.try(method)
# Returns true if the block is supposed to iterate through a collection,
# i.e. it has arity equals to one.
def collection_block?(block) #:nodoc:
block && block.arity == 1
end
end
end
12 changes: 4 additions & 8 deletions lib/show_for/content.rb
@@ -1,8 +1,10 @@
module ShowFor
module Content
def content(value, options={}, apply_options=true, &block)
value = options.delete(:if_blank) || ShowFor.blank_content if value.blank? && value != false
options[:class] = [options[:class], ShowFor.blank_content_class].join(' ') if value.blank?
if value.blank? && value != false
value = options.delete(:if_blank) || I18n.t(:'show_for.blank', :default => "Not specified")
options[:class] = [options[:class], ShowFor.blank_content_class].join(' ')
end

content = case value
when Date, Time, DateTime
Expand Down Expand Up @@ -40,11 +42,5 @@ def collection_handler(value, options, &block) #:nodoc:

wrap_with(:collection, response, options)
end

# Returns true if the block is supposed to iterate through a collection,
# i.e. it has arity equals to one.
def collection_block?(block) #:nodoc:
block && block.arity == 1
end
end
end
5 changes: 3 additions & 2 deletions lib/show_for/locale/en.yml
@@ -1,4 +1,5 @@
en:
show_for:
"yes": 'Yes'
"no": 'No'
blank: "Not specified"
"yes": "Yes"
"no": "No""
2 changes: 1 addition & 1 deletion lib/show_for/version.rb
@@ -1,3 +1,3 @@
module ShowFor
VERSION = "0.1".freeze
VERSION = "0.1.2".freeze
end
28 changes: 23 additions & 5 deletions test/builder_test.rb
Expand Up @@ -169,7 +169,14 @@ def with_content_for(object, value, options={})

test "show_for accepts nil and or blank attributes" do
with_attribute_for @user, :description
assert_select "div.show_for p.wrapper", "Description"
assert_select "div.show_for p.wrapper", /Not specified/
end

test "show_for accepts not spcified message can be localized" do
store_translations(:en, :show_for => { :blank => "OMG! It's blank!" }) do
with_attribute_for @user, :description
assert_select "div.show_for p.wrapper", /OMG! It's blank!/
end
end

test "show_for uses :if_blank if attribute is blank" do
Expand Down Expand Up @@ -264,11 +271,22 @@ def with_content_for(object, value, options={})
assert_select "div.show_for p.wrapper", /PlataformaTec/
end

test "show_for accepts :method as option to tell how to retrieve association value" do
with_association_for @user, :company, :method => :alternate_name
test "show_for accepts :using as option to tell how to retrieve association value" do
with_association_for @user, :company, :using => :alternate_name
assert_select "div.show_for p.wrapper", /Alternate PlataformaTec/
end

test "show_for accepts :in to tell to retrieve an attribute from association" do
with_attribute_for @user, :alternate_name, :in => :company
assert_select "div.show_for p.wrapper", /Alternate PlataformaTec/
end

test "show_for forwards all options send with :in to association" do
with_attribute_for @user, :alternate_name, :in => :tags, :to_sentence => true
assert_no_select "div.show_for p.wrapper ul.collection"
assert_select "div.show_for p.wrapper", /Alternate Tag 1, Alternate Tag 2, and Alternate Tag 3/
end

test "show_for works with has_many/has_and_belongs_to_many associations" do
with_association_for @user, :tags
assert_select "div.show_for p.wrapper ul.collection"
Expand All @@ -277,8 +295,8 @@ def with_content_for(object, value, options={})
assert_select "div.show_for p.wrapper ul.collection li", "Tag 3"
end

test "show_for accepts :method as option to tell how to retrieve association values" do
with_association_for @user, :tags, :method => :alternate_name
test "show_for accepts :using as option to tell how to retrieve association values" do
with_association_for @user, :tags, :using => :alternate_name
assert_select "div.show_for p.wrapper ul.collection"
assert_select "div.show_for p.wrapper ul.collection li", "Alternate Tag 1"
assert_select "div.show_for p.wrapper ul.collection li", "Alternate Tag 2"
Expand Down

0 comments on commit 2d6d195

Please sign in to comment.