Repository: plataformatec/show_for
Branch: main
Commit: 0c847172d160
Files: 40
Total size: 62.1 KB
Directory structure:
gitextract_7x2s2uzu/
├── .github/
│ ├── code-scanning.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── gemfiles/
│ ├── Gemfile-rails-7-0
│ ├── Gemfile-rails-7-1
│ ├── Gemfile-rails-7-2
│ ├── Gemfile-rails-8-0
│ └── Gemfile-rails-main
├── lib/
│ ├── generators/
│ │ └── show_for/
│ │ ├── USAGE
│ │ ├── install_generator.rb
│ │ └── templates/
│ │ ├── en.yml
│ │ ├── show.html.erb
│ │ ├── show.html.haml
│ │ ├── show.html.slim
│ │ └── show_for.rb
│ ├── show_for/
│ │ ├── association.rb
│ │ ├── attribute.rb
│ │ ├── builder.rb
│ │ ├── content.rb
│ │ ├── helper.rb
│ │ ├── label.rb
│ │ └── version.rb
│ └── show_for.rb
├── show_for.gemspec
└── test/
├── association_test.rb
├── attribute_test.rb
├── builder_test.rb
├── content_test.rb
├── generators/
│ └── show_for_generator_test.rb
├── helper_test.rb
├── label_test.rb
├── support/
│ ├── misc_helpers.rb
│ └── models.rb
├── test_helper.rb
└── value_test.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/code-scanning.yml
================================================
paths-ignore:
- test/**
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
jobs:
test:
strategy:
fail-fast: false
matrix:
gemfile:
- Gemfile
- gemfiles/Gemfile-rails-main
- gemfiles/Gemfile-rails-8-0
- gemfiles/Gemfile-rails-7-2
- gemfiles/Gemfile-rails-7-1
- gemfiles/Gemfile-rails-7-0
ruby:
- '4.0'
- '3.4'
- '3.3'
- '3.2'
- '3.1'
- '3.0'
- '2.7'
exclude:
- gemfile: Gemfile
ruby: '3.1'
- gemfile: Gemfile
ruby: '3.0'
- gemfile: Gemfile
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.2'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.1'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '3.1'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-7-2
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-7-2
ruby: '2.7'
runs-on: ubuntu-latest
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true # runs bundle install and caches installed gems automatically
- run: bundle exec rake
================================================
FILE: .gitignore
================================================
.bundle/
pkg/
gemfiles/*.lock
================================================
FILE: CHANGELOG.md
================================================
## Unreleased
* Ruby 4.0 support (no changes required)
## 0.9.0
* Add support for Ruby 3.3/3.4 and Rails 7.2/8.0/8.1. (no changes required)
* Drop support for Rails < 7 and Ruby < 2.7.
## 0.8.1
* Add support for Rails 7.0/7.1 and Ruby 3.1/3.2 (no changes required)
* Remove test files from the gem package.
## 0.8.0
* Respect `nil` value when provided, by skipping model attribute value.
* Add support for Ruby 3.0, drop support for Ruby < 2.5.
* Add support for Rails 6.1, drop support for Rails < 5.2.
* Move CI to GitHub Actions.
## 0.7.0
* Add support for Rails 6.0.
* Drop support for Rails < 5.0 and Ruby < 2.4.
## 0.6.1
* Add support for Rails 5.2.
* Fix issue causing blank class not being applied to field wrapper when the result of a Proc is empty.
## 0.6.0
* Relaxed dependencies to support Rails 5.1.
## 0.5.0
* Relaxed dependencies to support Rails 5.
* Removed support for Rails `3.2` and `4.0` and Ruby `1.9.3` and `2.0.0`.
### enhancements
* Do not generate label/content/wrapper/collection classes when config is set to `nil`.
## 0.4.0
### enhancements
* Change default `wrapper_tag` to generate a `div` instead of `p`. The `p` tag generates
invalid HTML with collections: `p > ul`, and failed tests on Rails 4.2. If you depend
on the `p` tag being generated, change your Show For config to set `wrapper_tag` to `:p`.
* Remove deprecated `:method` in favor of `:using`.
* Improve support to Rails 4.x associations with more duck typing instead of Array checks.
* Support Rails 4.1/4.2 and Ruby 2.1/2.2.
* Add `skip_blanks` configuration option to skip generating blank attributes
instead of generating them with a default message. (by github.com/moktin)
* Add `slim` template for the install generator. (by github.com/voanhduy1512)
* Add `separator` option that overrides the global configuration (by github.com/bernardofire)
### bugfix
* Do not yield default blank value to the block when using an empty association. (by github.com/aptinio)
## 0.3.0
### bug fix
* Fix blank value not being applied when using a block. (by github.com/tfwright)
## 0.3.0.rc
### enhancements
* Support Rails 4.
* Drop support to Rails < 3.2 and Ruby 1.8.
## 0.2.6
### enhancements
* Ruby 2.0 support.
* Add Haml template. (by github.com/nashby) Closes #12.
* Add `blank_html` tanslation. (by github.com/nashby)
* Add `show_for_class` configuration option. (by github.com/nashby)
### bug fix
* Make show_for works with namespaced models. (by github.com/fabiokr)
* Add `blank_content_class` to the attributes. (by github.com/blakehilscher). Closes #24.
* Don't call `association.map` if association method is nil (by github.com/nashby). Closes #40.
## 0.2.5
### enhancements
* Add a `:value` option for attribute (by github.com/ml-gt)
* Add `label_class`, `content_class`, `wrapper_class` and `collection_class` configuration options (by github.com/wojtekmach)
### bug fix
* Fix problem with `label => false` and `html_safe` (label => false) (by github.com/nashby)
## 0.2.4
### enhancements
* Do not add separator if label is not present (by github.com/eugenebolshakov)
* Add method for output value only (by github.com/jenkek)
### bug fix
* Fix empty labels to be `html_safe` (label => false) (by github.com/eugenebolshakov)
## 0.2.3
### enhancements
* added :attributes method to generate all attributes given
* update generator to use the new syntax show_for:install
### bug fix
* fix numeric types
## 0.2.2
### bug fix
* allow show_for to work with AR association proxies
### enhancements
* improvements on html safe and output buffers
## 0.2.1
### enhancements
* added label_proc
* compatibility with latest Rails
## 0.2.0
### enhancements
* Rails 3 compatibility
## 0.1.4
### bug fix
* allow show_for to work with AR association proxies
## 0.1.3
### enhancements
* allow builder to be given to show_for
### bug fix
* Fix typo in yaml
## 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
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
gemspec
gem 'railties', '~> 8.1.0'
gem 'activemodel', '~> 8.1.0'
gem 'actionpack', '~> 8.1.0'
================================================
FILE: MIT-LICENSE
================================================
Copyright (c) 2020-CURRENT Rafael França, Carlos Antonio da Silva
Copyright (c) 2012-2019 Plataformatec
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# ShowFor
[](https://badge.fury.io/rb/show_for)
ShowFor allows you to quickly show a model information with I18n features.
```erb
<%= 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",
wrapper_html: { id: "sign_in_timestamp" } %>
<%= u.attribute :photo do %>
<%= image_tag(@user.photo_url) %>
<% end %>
<%= u.association :company %>
<%= u.association :tags, to_sentence: true %>
<% end %>
```
## Installation
Install the gem:
gem install show_for
Or add ShowFor to your Gemfile and bundle it up:
gem 'show_for'
Run the generator:
rails generate show_for:install
And you are ready to go.
Note: This branch aims Rails 7 and 8 support, so if you want to use it with
older versions of Rails, check out the available branches.
## Usage
ShowFor allows you to quickly show a model information with I18n features.
```erb
<%= show_for @admin do |a| %>
<%= a.attribute :name %>
<%= a.attribute :login, value: :upcase %>
<%= a.attribute :confirmed? %>
<%= a.attribute :created_at, format: :short %>
<%= a.attribute :last_sign_in_at, if_blank: "Administrator did not access yet"
wrapper_html: { id: "sign_in_timestamp" } %>
<%= a.attribute :photo do %>
<%= image_tag(@admin.photo_url) %>
<% end %>
<% a.value :biography %>
<% end %>
```
Will generate something like:
```html
Name
José Valim
Login
JVALIM
Confirmed?
Yes
Created at
13/12/2009 - 19h17
Last sign in at
Administrator did not access yet
Photo
Etiam porttitor eros ut diam vestibulum et blandit lectus tempor. Donec
venenatis fermentum nunc ac dignissim. Pellentesque volutpat eros quis enim
mollis bibendum. Ut cursus sem ac sem accumsan nec porttitor felis luctus.
Sed purus nunc, auctor vitae consectetur pharetra, tristique non nisi.
```
You can also show a list of attributes, useful if you don't need to change any configuration:
```erb
<%= show_for @admin do |a| %>
<%= a.attributes :name, :confirmed?, :created_at %>
<% end %>
```
## Value lookup
ShowFor uses the following sequence to get the attribute value:
* use the output of a block argument if given
* use the output of the `:value` argument if given
* check if a `:"human_#{attribute}"` method is defined
* retrieve the attribute directly.
## Options
ShowFor handles a series of options. Those are:
* __:format__ - Sent to `I18n.localize` when the attribute is a date/time object.
* __:value__ - Can be used instead of block. If a `Symbol` is called as instance method.
* __:if_blank__ - An object to be used if the value is blank. Not escaped as well.
* __:separator__ - The piece of html that separates label and content, overriding the global configuration.
In addition, all containers (`:label`, `:content` and `:wrapper`) can have their html
options configured through the `:label_html`, `:content_html` and `:wrapper_html`
options. Containers can have their tags configured on demand as well through
`:label_tag,` `:content_tag` and `:wrapper_tag` options.
## Label
ShowFor also exposes the label method. In case you want to use the default
`human_attribute_name` lookup and the default wrapping:
```ruby
a.label :name #=> Name
a.label "Name", id: "my_name" #=> Name
```
Optionally, if you want to wrap the inner part of the label with some text
(e.g. adding a semicolon), you can do so by specifying a proc for `ShowFor.label_proc`
that will be called with any label text. E.g.:
```ruby
ShowFor.label_proc = lambda { |l| l + ":" }
```
When taking this route, you can also skip on a per label basis by passing the
`:wrap_label` option with a value of false.
## Associations
ShowFor also supports associations.
```erb
<%= show_for @artwork do |a| %>
<%= a.association :artist %>
<%= a.association :artist, using: :name_with_title %>
<%= a.attribute :name_with_title, in: :artist %>
<%= a.association :tags %>
<%= a.association :tags, to_sentence: true %>
<%= a.association :tags do
@artwork.tags.map(&:name).to_sentence
end %>
<%= a.association :fans, collection_tag: :ol do |fan| %>
<%= link_to fan.name, fan %>
<% end %>
<% end %>
```
The first is a `has_one` or `belongs_to` association, which works like an attribute
to ShowFor, 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 :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.
ShowFor can handle collections by default by wrapping them in list (`` with
each item wrapped by an `- `). However, it also allows you to give `:to_sentence`
or `:join` it you want to render them inline.
You can also pass a block which expects an argument to association. In such cases,
a wrapper for the collection is still created and the block just iterates over the
collection objects.
Here are some other examples of the many possibilites to custom the output content:
```erb
<%= u.association :relationships, label: 'test' do %>
<% @user.relationships.each do |relation| %>
<%= relation.related_user.name if relation.related_user_role == 'supervisor' %>
<% end %>
<% end %>
<%= u.attribute :gender do %>
<%= content_tag :span, t("helpers.enum_select.user.gender.#{@user.gender}") %>
<% end %>
```
## Supported Ruby / Rails versions
We intend to maintain support for all Ruby / Rails versions that haven't reached end-of-life.
For more information about specific versions please check [Ruby](https://www.ruby-lang.org/en/downloads/branches/)
and [Rails](https://guides.rubyonrails.org/maintenance_policy.html) maintenance policies, and our test matrix.
## Bugs and Feedback
If you discover any bugs or want to drop a line, feel free to create an issue on GitHub.
http://github.com/heartcombo/show_for/issues
## License
MIT License.
Copyright 2020-CURRENT Rafael França, Carlos Antonio da Silva.
Copyright 2012-2019 Plataformatec.
================================================
FILE: Rakefile
================================================
# encoding: UTF-8
require 'bundler'
Bundler::GemHelper.install_tasks
require 'rake/testtask'
require 'rdoc/task'
desc 'Default: run unit tests.'
task default: :test
desc 'Test the show_form plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the show_for plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'ShowFor'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
================================================
FILE: gemfiles/Gemfile-rails-7-0
================================================
source 'https://rubygems.org'
gemspec path: '..'
gem 'railties', '~> 7.0.0'
gem 'activemodel', '~> 7.0.0'
gem 'actionpack', '~> 7.0.0'
================================================
FILE: gemfiles/Gemfile-rails-7-1
================================================
source 'https://rubygems.org'
gemspec path: '..'
gem 'railties', '~> 7.1.0'
gem 'activemodel', '~> 7.1.0'
gem 'actionpack', '~> 7.1.0'
================================================
FILE: gemfiles/Gemfile-rails-7-2
================================================
source 'https://rubygems.org'
gemspec path: '..'
gem 'railties', '~> 7.2.0'
gem 'activemodel', '~> 7.2.0'
gem 'actionpack', '~> 7.2.0'
================================================
FILE: gemfiles/Gemfile-rails-8-0
================================================
source 'https://rubygems.org'
gemspec path: '..'
gem 'railties', '~> 8.0.0'
gem 'activemodel', '~> 8.0.0'
gem 'actionpack', '~> 8.0.0'
================================================
FILE: gemfiles/Gemfile-rails-main
================================================
source 'https://rubygems.org'
gemspec path: '..'
gem 'railties', github: 'rails/rails', branch: 'main'
gem 'activemodel', github: 'rails/rails', branch: 'main'
gem 'actionpack', github: 'rails/rails', branch: 'main'
================================================
FILE: lib/generators/show_for/USAGE
================================================
To copy a ShowFor initializer to your Rails App, with some configuration values, just do:
rails generate show_for:install
================================================
FILE: lib/generators/show_for/install_generator.rb
================================================
module ShowFor
module Generators
class InstallGenerator < Rails::Generators::Base
desc "Copy ShowFor installation files"
class_option :template_engine, desc: 'Template engine to be invoked (erb or haml or slim).'
source_root File.expand_path('../templates', __FILE__)
def copy_initializers
copy_file 'show_for.rb', 'config/initializers/show_for.rb'
end
def copy_locale_file
copy_file 'en.yml', 'config/locales/show_for.en.yml'
end
def copy_generator_template
engine = options[:template_engine]
copy_file "show.html.#{engine}", "lib/templates/#{engine}/scaffold/show.html.#{engine}"
end
end
end
end
================================================
FILE: lib/generators/show_for/templates/en.yml
================================================
en:
show_for:
blank: "Not specified"
# If you want to use html tags with blank value use blank html translation
# blank_html: "Not specified"
"yes": "Yes"
"no": "No"
================================================
FILE: lib/generators/show_for/templates/show.html.erb
================================================
<%%= show_for @<%= singular_name %> do |s| %>
<% attributes.each do |attribute| -%>
<%%= s.<%= attribute.reference? ? :association : :attribute %> :<%= attribute.name %> %>
<% end -%>
<%% end %>
<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
<%%= link_to 'Back', <%= plural_name %>_path %>
================================================
FILE: lib/generators/show_for/templates/show.html.haml
================================================
= show_for(@<%= singular_name %>) do |s|
<%- attributes.each do |attribute| -%>
= s.<%= attribute.reference? ? :association : :attribute %> :<%= attribute.name %>
<% end -%>
= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>)
|
= link_to 'Back', <%= plural_name %>_path
================================================
FILE: lib/generators/show_for/templates/show.html.slim
================================================
= show_for(@<%= singular_name %>) do |s|
<%- attributes.each do |attribute| -%>
= s.<%= attribute.reference? ? :association : :attribute %> :<%= attribute.name %>
<% end -%>
= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>)
|
= link_to 'Back', <%= plural_name %>_path
================================================
FILE: lib/generators/show_for/templates/show_for.rb
================================================
# Use this setup block to configure all options available in ShowFor.
ShowFor.setup do |config|
# The tag which wraps show_for calls.
# config.show_for_tag = :div
# The DOM class set for show_for tag. Default is nil
# config.show_for_class = :custom
# The tag which wraps each attribute/association call. Default is :p.
# config.wrapper_tag = :dl
# The DOM class set for the wrapper tag. Default is :wrapper.
# config.wrapper_class = :custom
# The tag used to wrap each label. Default is :strong.
# config.label_tag = :dt
# The DOM class of each label tag. Default is :label.
# config.label_class = :custom
# The tag used to wrap each content (value). Default is nil.
# config.content_tag = :dd
# The DOM class of each content tag. Default is :content.
# config.content_class = :custom
# The DOM class set for blank content tags. Default is "blank".
# config.blank_content_class = 'no_content'
# Skip blank attributes instead of generating with a default message. Default is false.
# config.skip_blanks = true
# The separator between label and content. Default is "
".
# config.separator = "
"
# The tag used to wrap collections. Default is :ul.
# config.collection_tag = :ul
# The DOM class set for the collection tag. Default is :collection.
# config.collection_class = :custom
# The default iterator to be used when invoking a collection/association.
# config.default_collection_proc = lambda { |value| " - #{ERB::Util.h(value)}
".html_safe }
# The default format to be used in I18n when localizing a Date/Time.
# config.i18n_format = :default
# Whenever a association is given, the first method in association_methods
# in which the association responds to is used to retrieve the association labels.
# config.association_methods = [ :name, :title, :to_s ]
# If you want to wrap the text inside a label (e.g. to append a semicolon),
# specify label_proc - it will be automatically called, passing in the label text.
# config.label_proc = lambda { |l| l + ":" }
end
================================================
FILE: lib/show_for/association.rb
================================================
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 = 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 values_from_association(association, options) #:nodoc:
sample = association.respond_to?(:to_ary) ? association.first : association
method = options.delete(:using) || ShowFor.association_methods.find { |m| sample.respond_to?(m) }
if method
association.respond_to?(:to_ary) ? association.map(&method) : association.try(method)
end
end
end
end
================================================
FILE: lib/show_for/attribute.rb
================================================
module ShowFor
module Attribute
def attribute(attribute_name, options = {}, &block)
apply_default_options!(attribute_name, options)
block = block_from_value_option(attribute_name, options) unless block
collection_block, block = block, nil if collection_block?(block)
value = attribute_value(attribute_name, &block)
wrap_label_and_content(attribute_name, value, options, &collection_block)
end
def value(attribute_name, options = {}, &block)
apply_default_options!(attribute_name, options)
collection_block, block = block, nil if collection_block?(block)
value = attribute_value(attribute_name, &block)
wrap_content(attribute_name, value, options, &collection_block)
end
def attributes(*attribute_names)
attribute_names.map do |attribute_name|
attribute(attribute_name)
end.join.html_safe
end
private
def attribute_value(attribute_name, &block)
if block
block
elsif @object.respond_to?(:"human_#{attribute_name}")
@object.send :"human_#{attribute_name}"
else
@object.send(attribute_name)
end
end
def block_from_value_option(attribute_name, options)
if !options.has_key?(:value)
nil
elsif options[:value].is_a?(Symbol)
block_from_symbol(attribute_name, options)
else
lambda { options[:value].to_s }
end
end
def block_from_symbol(attribute_name, options)
attribute = @object.send(attribute_name)
case attribute
when Array, Hash
lambda { |element| element.send(options[:value]) }
else
lambda { attribute.send(options[:value]) }
end
end
end
end
================================================
FILE: lib/show_for/builder.rb
================================================
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
attr_reader :object, :template
def initialize(object, template)
@object, @template = object, template
end
protected
def object_name #:nodoc:
@object_name ||= begin
model_name = @object.class.model_name
# TODO Remove this check when we drop support to Rails 3.0
if model_name.respond_to?(:param_key)
model_name.param_key
else
model_name.singular
end
end
end
def wrap_label_and_content(name, value, options, &block) #:nodoc:
return if skip_blanks?(value)
label = label(name, options, false)
if label.present? && separator = options.fetch(:separator) { ShowFor.separator }
label += separator.html_safe
end
wrap_with(:wrapper, label + content(value, options, false, &block), apply_wrapper_options!(:wrapper, options, value))
end
def wrap_content(name, value, options, &block) #:nodoc:
wrap_with(:wrapper, content(value, options, false, &block), apply_wrapper_options!(:wrapper, options, value))
end
# Set "#{object_name}_#{attribute_name}" as in the wrapper tag.
def apply_default_options!(name, options) #:nodoc:
html_class = "#{object_name}_#{name}".gsub(/\W/, '')
wrapper_html = options[:wrapper_html] ||= {}
wrapper_html[:class] = "#{html_class} #{wrapper_html[:class]}".rstrip
end
def apply_wrapper_options!(type, options, value)
options[:"#{type}_html"] ||= {}
options[:"#{type}_html"][:class] = [options[:"#{type}_html"][:class], ShowFor.blank_content_class].join(' ') if is_empty?(value)
options
end
# Gets the default tag set in ShowFor module and apply (if defined)
# around the given content. It also check for html_options in @options
# hash related to the current type.
def wrap_with(type, content, options) #:nodoc:
return if skip_blanks?(content)
tag = options.delete(:"#{type}_tag") || ShowFor.send(:"#{type}_tag")
if tag
type_class = ShowFor.send :"#{type}_class"
html_options = options.delete(:"#{type}_html") || {}
html_options[:class] = [type_class, html_options[:class]].compact.presence
@template.content_tag(tag, content, html_options)
else
content
end
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
# Verifies whether the value is blank and its configured to skip blank values.
def skip_blanks?(value) #:nodoc:
ShowFor.skip_blanks && value.blank? && value != false
end
def is_empty?(value) #:nodoc:
value = @template.capture(&value) if value.is_a?(Proc)
value.blank? && value != false
end
end
end
================================================
FILE: lib/show_for/content.rb
================================================
module ShowFor
module Content
def content(value, options = {}, apply_options = true, &block)
# cache value for apply_wrapper_options!
sample_value = value
# We need to convert value to_a because when dealing with ActiveRecord
# Array proxies, the follow statement Array# === value return false
value = value.to_a if value.respond_to?(:to_ary)
content = case value
when Date, Time, DateTime
I18n.l value, format: options.delete(:format) || ShowFor.i18n_format
when TrueClass
I18n.t :"show_for.yes", default: "Yes"
when FalseClass
I18n.t :"show_for.no", default: "No"
when Array, Hash
collection_handler(value, options, &block) unless value.empty?
when Proc
@template.capture(&value)
when Numeric
value.to_s
else
unless value.blank?
block ? template.capture(value, &block) : value
end
end
if content.blank? && !ShowFor.skip_blanks
content = blank_value(options)
end
options[:content_html] = options.except(:content_tag) if apply_options
wrap_with(:content, content, apply_wrapper_options!(:content, options, sample_value))
end
protected
def collection_handler(value, options, &block) #:nodoc:
iterator = collection_block?(block) ? block : ShowFor.default_collection_proc
response = value.map do |item|
template.capture(item, &iterator)
end.join.html_safe
wrap_with(:collection, response, options)
end
def translate_blank_html
template.t(:'show_for.blank_html', default: translate_blank_text)
end
def translate_blank_text
I18n.t(:'show_for.blank', default: "Not specified")
end
def blank_value(options)
options.delete(:if_blank) || translate_blank_html
end
end
end
================================================
FILE: lib/show_for/helper.rb
================================================
module ShowFor
module Helper
# Creates a div around the object and yields a builder.
#
# Example:
#
# show_for @user do |f|
# f.attribute :name
# f.attribute :email
# end
#
def show_for(object, html_options = {}, &block)
html_options = html_options.dup
tag = html_options.delete(:show_for_tag) || ShowFor.show_for_tag
html_options[:id] ||= dom_id(object)
html_options[:class] = show_for_html_class(object, html_options)
builder = html_options.delete(:builder) || ShowFor::Builder
content = capture(builder.new(object, self), &block)
content_tag(tag, content, html_options)
end
private
def show_for_html_class(object, html_options)
"show_for #{dom_class(object)} #{html_options[:class]} #{ShowFor.show_for_class}".squeeze(" ").rstrip
end
end
end
ActionView::Base.send :include, ShowFor::Helper
================================================
FILE: lib/show_for/label.rb
================================================
module ShowFor
module Label
def label(text_or_attribute, options = {}, apply_options = true)
label = if text_or_attribute.is_a?(String)
text_or_attribute
elsif options.key?(:label)
options.delete(:label)
else
human_attribute_name(text_or_attribute)
end
return ''.html_safe if label == false
options[:label_html] = options.dup if apply_options
label = ShowFor.label_proc.call(label) if options.fetch(:wrap_label, true) && ShowFor.label_proc
wrap_with :label, label, options
end
protected
def human_attribute_name(attribute) #:nodoc:
@object.class.human_attribute_name(attribute.to_s)
end
end
end
================================================
FILE: lib/show_for/version.rb
================================================
module ShowFor
VERSION = "0.9.0".freeze
end
================================================
FILE: lib/show_for.rb
================================================
require 'action_view'
require 'show_for/helper'
module ShowFor
autoload :Builder, 'show_for/builder'
mattr_accessor :show_for_tag
@@show_for_tag = :div
mattr_accessor :show_for_class
@@show_for_class = nil
mattr_accessor :label_tag
@@label_tag = :strong
mattr_accessor :label_class
@@label_class = :label
mattr_accessor :separator
@@separator = "
"
mattr_accessor :content_tag
@@content_tag = nil
mattr_accessor :content_class
@@content_class = :content
mattr_accessor :blank_content_class
@@blank_content_class = "blank"
mattr_accessor :skip_blanks
@@skip_blanks = false
mattr_accessor :wrapper_tag
@@wrapper_tag = :div
mattr_accessor :wrapper_class
@@wrapper_class = :wrapper
mattr_accessor :collection_tag
@@collection_tag = :ul
mattr_accessor :collection_class
@@collection_class = :collection
mattr_accessor :default_collection_proc
@@default_collection_proc = lambda { |value| "- #{ERB::Util.html_escape(value)}
".html_safe }
mattr_accessor :i18n_format
@@i18n_format = :default
mattr_accessor :association_methods
@@association_methods = [ :name, :title, :to_s ]
mattr_accessor :label_proc
@@label_proc = nil
# Yield self for configuration block:
#
# ShowFor.setup do |config|
# config.i18n_format = :long
# end
#
def self.setup
yield self
end
end
================================================
FILE: show_for.gemspec
================================================
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "show_for/version"
Gem::Specification.new do |s|
s.name = "show_for"
s.version = ShowFor::VERSION.dup
s.platform = Gem::Platform::RUBY
s.summary = "Wrap your objects with a helper to easily show them"
s.email = "heartcombo.oss@gmail.com"
s.homepage = "https://github.com/heartcombo/show_for"
s.description = "Wrap your objects with a helper to easily show them"
s.authors = ["José Valim"]
s.licenses = ["MIT"]
s.metadata = {
"homepage_uri" => "https://github.com/heartcombo/show_for",
"changelog_uri" => "https://github.com/heartcombo/show_for/blob/main/CHANGELOG.md",
"source_code_uri" => "https://github.com/heartcombo/show_for",
"bug_tracker_uri" => "https://github.com/heartcombo/show_for/issues",
}
s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.md", "lib/**/*"]
s.require_paths = ["lib"]
s.required_ruby_version = '>= 2.7.0'
s.add_dependency('activemodel', '>= 7.0')
s.add_dependency('actionpack', '>= 7.0')
s.add_development_dependency('rake')
s.add_development_dependency('rdoc')
s.add_development_dependency('ostruct')
end
================================================
FILE: test/association_test.rb
================================================
require 'test_helper'
class AssociationTest < ActionView::TestCase
test "show_for works with belongs_to/has_one associations" do
with_association_for @user, :company
assert_select "div.show_for div.wrapper", /Plataformatec/
end
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 div.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 div.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 div.wrapper ul.collection"
assert_select "div.show_for div.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 div.wrapper ul.collection"
assert_select "div.show_for div.wrapper ul.collection li", "Tag 1"
assert_select "div.show_for div.wrapper ul.collection li", "Tag 2"
assert_select "div.show_for div.wrapper ul.collection li", "Tag 3"
end
test "show_for works with has_many/has_and_belongs_to_many blank associations" do
def @user.tags
[]
end
swap ShowFor, association_methods: [:name] do
with_association_for @user, :tags
assert_no_select "div.show_for div.wrapper ul.collection"
assert_no_select "div.show_for div.wrapper", /Enumerator/
end
end
test "show_for accepts a block with has_many/has_and_belongs_to_many blank associations" do
def @user.tags
[]
end
swap ShowFor, association_methods: [:name] do
with_association_for @user, :tags do |tag|
tag.name
end
assert_no_select "div.show_for div.wrapper ul.collection"
assert_no_select "div.show_for div.wrapper", /Enumerator/
end
end
test "show_for uses :if_blank when has_many/has_and_belongs_to_many association is blank" do
def @user.tags
[]
end
with_association_for @user, :tags, if_blank: 'No tags' do |tag|
tag.name
end
assert_select "div.show_for div.wrapper.blank", /No tags/
assert_no_select "div.show_for div.wrapper ul.collection"
assert_no_select "div.show_for div.wrapper", /Enumerator/
end
test "show_for uses :if_blank if given a block when has_many/has_and_belongs_to_many association is blank" do
def @user.tags
[]
end
with_association_for @user, :tags, if_blank: 'No tags'
assert_select "div.show_for div.wrapper.blank", /No tags/
assert_no_select "div.show_for div.wrapper ul.collection"
assert_no_select "div.show_for div.wrapper", /Enumerator/
end
test "show_for accepts a block with an argument in belongs_to associations" do
with_association_for @user, :company do |company|
company.name.upcase
end
assert_select "div.show_for div.wrapper", /PLATAFORMATEC/
end
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 div.wrapper ul.collection"
assert_select "div.show_for div.wrapper ul.collection li", "Alternate Tag 1"
assert_select "div.show_for div.wrapper ul.collection li", "Alternate Tag 2"
assert_select "div.show_for div.wrapper ul.collection li", "Alternate Tag 3"
end
test "show_for accepts :to_sentence as option in collection associations" do
with_association_for @user, :tags, to_sentence: true
assert_no_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper", /Tag 1, Tag 2, and Tag 3/
end
test "show_for accepts :join as option in collection associations" do
with_association_for @user, :tags, join: ", "
assert_no_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper", /Tag 1, Tag 2, Tag 3/
end
test "show_for accepts a block without argument in collection associations" do
with_association_for @user, :tags do
@user.tags.map(&:name).to_sentence
end
assert_no_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper", /Tag 1, Tag 2, and Tag 3/
end
test "show_for accepts a block with argument in collection associations" do
with_association_for @user, :tags, collection_tag: :p do |tag|
assert_kind_of Tag, tag
content_tag(:span, tag.name)
end
assert_no_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper p.collection"
assert_select "div.show_for div.wrapper p.collection span", "Tag 1"
assert_select "div.show_for div.wrapper p.collection span", "Tag 2"
assert_select "div.show_for div.wrapper p.collection span", "Tag 3"
end
test "show_for does not display empty has_many/has_and_belongs_to_many association if skip_blanks option is passed" do
def @user.tags
[]
end
swap ShowFor, skip_blanks: true do
with_association_for @user, :tags
assert_no_select "div.show_for div.wrapper"
end
end
test "show_for does not display empty belongs_to/has_one association if skip_blanks option is passed" do
def @user.company
nil
end
swap ShowFor, skip_blanks: true do
with_association_for @user, :company
assert_no_select "div.show_for div.wrapper"
end
end
end
================================================
FILE: test/attribute_test.rb
================================================
require 'test_helper'
class AttributeTest < ActionView::TestCase
# COLLECTIONS
test "show_for accepts an attribute as a collection" do
with_attribute_for @user, :scopes
assert_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper ul.collection li", count: 3
end
test "show_for accepts an attribute as a collection with a block to iterate the collection" do
with_attribute_for @user, :scopes do |scope|
content_tag :span, scope
end
assert_select "div.show_for div.wrapper ul.collection"
assert_select "div.show_for div.wrapper ul.collection span", count: 3
end
test "show_for treats symbol for :value as method on each element of collection" do
with_attribute_for @user, :scopes, value: :upcase
@user.scopes.each do |scope|
assert_select "div.show_for div.wrapper ul.collection", /#{scope.upcase}/
end
end
test "show_for allows collection tag to be configured globally" do
swap ShowFor, collection_tag: :ol, collection_class: "my_collection" do
with_attribute_for @user, :scopes
assert_select "div.show_for div.wrapper ol.my_collection"
end
end
test "show_for allows collection class to be disabled globally" do
swap ShowFor, collection_tag: :ol, collection_class: nil do
with_attribute_for @user, :scopes
assert_select "div.show_for div.wrapper ol"
assert_no_select "ol[class]"
end
end
test "show_for allows collection tag to be changed by attribute" do
with_attribute_for @user, :scopes, collection_tag: :ol
assert_select "div.show_for div.wrapper ol.collection"
end
test "show_for allows collection tag html to be configured by attribute" do
with_attribute_for @user, :scopes, collection_html: { id: "thecollection", class: "special" }
assert_select "div.show_for div.wrapper ul#thecollection.special.collection"
end
# CONTENT
test "show_for allows content tag to be configured globally" do
swap ShowFor, content_tag: :span, content_class: :my_content do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper span.my_content"
end
end
test "show_for allows content class to be disabled globally" do
swap ShowFor, content_tag: :span, content_class: nil do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper span"
assert_no_select "span[class]"
end
end
test "show_for allows content tag to be changed by attribute" do
with_attribute_for @user, :name, content_tag: :span
assert_select "div.show_for div.wrapper span.content"
end
test "show_for allows content tag html to be configured by attribute" do
with_attribute_for @user, :name, content_tag: :span, content_html: { id: "thecontent", class: "special" }
assert_select "div.show_for div.wrapper span#thecontent.special.content"
end
test "show_for accepts an attribute as string" do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper", /ShowFor/
end
test "show_for accepts an attribute as time" do
with_attribute_for @user, :created_at
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.created_at))}/
end
test "show_for accepts an attribute as date" do
with_attribute_for @user, :updated_at
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.updated_at))}/
end
test "show_for accepts an attribute as time with format options" do
with_attribute_for @user, :created_at, format: :long
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.created_at, format: :long))}/
end
test "show_for accepts an attribute as true" do
with_attribute_for @user, :active
assert_select "div.show_for div.wrapper", /Yes/
end
test "show_for accepts an attribute as true which can be localized" do
store_translations(:en, show_for: { yes: "Hell yeah!" }) do
with_attribute_for @user, :active
assert_select "div.show_for div.wrapper", /Hell yeah!/
end
end
test "show_for accepts an attribute as false" do
with_attribute_for @user, :invalid
assert_select "div.show_for div.wrapper", /No/
end
test "show_for accepts an attribute as false which can be localized" do
store_translations(:en, show_for: { no: "Hell no!" }) do
with_attribute_for @user, :invalid
assert_select "div.show_for div.wrapper", /Hell no!/
end
end
test "show_for accepts nil and or blank attributes" do
with_attribute_for @user, :description
assert_select "div.show_for div.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 div.wrapper", /OMG! It's blank!/
end
end
test "show_for accepts not spcified message can be localized with html" do
store_translations(:en, show_for: { blank_html: "OMG! It's blank!" }) do
with_attribute_for @user, :description
assert_select "div.show_for div.wrapper span", "OMG! It's blank!"
end
end
test "show_for uses :if_blank if attribute is blank" do
with_attribute_for @user, :description, if_blank: "No description provided"
assert_select "div.show_for div.wrapper", /No description provided/
end
test "show_for accepts a block to supply the content" do
with_attribute_for @user, :description do
"This description is not blank"
end
assert_select "div.show_for div.wrapper", /This description/
end
test "show_for uses :if_blank if the block content is blank" do
with_attribute_for @user, :description, if_blank: "No description provided" do
""
end
assert_select "div.show_for div.wrapper", /No description provided/
end
test "show_for#content given a block should be wrapped in the result" do
with_attribute_for @user, :name do |name|
"#{name}
".html_safe
end
assert_select "div.wrapper.user_name div.block", /ShowFor/
end
test "show_for escapes content by default" do
@user.name = "hack you!"
with_attribute_for @user, :name
assert_no_select "div.show_for div.wrapper b"
assert_select "div.show_for div.wrapper", "Super User Name!hack you!"
end
test "show_for works with html_safe marked strings" do
@user.name = "hack you!".html_safe
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper b", "hack you!"
end
test "show_for uses :value if supplied" do
with_attribute_for @user, :name, value: "Calculated Value"
assert_select "div.show_for div.wrapper", /Calculated Value/
end
test "show_for uses :value and casts to string if supplied" do
with_attribute_for @user, :name, value: 123
assert_select "div.show_for div.wrapper", /123/
end
test "show_for ignores attribute if :value supplied but with nil value" do
with_attribute_for @user, :name, value: nil
assert_select "div.show_for div.wrapper", /Not specified/
end
test "show_for ignores :value if a block is supplied" do
with_attribute_for @user, :name, value: "Calculated Value" do
@user.name.upcase
end
assert_select "div.show_for div.wrapper", /#{@user.name.upcase}/
end
test "show_for treats symbol for :value as method on attribute" do
with_attribute_for @user, :name, value: :upcase
assert_select "div.show_for div.wrapper", /#{@user.name.upcase}/
end
test "show_for does not display blank attribute if skip_blanks option is passed" do
swap ShowFor, skip_blanks: true do
with_attribute_for @user, :description
assert_no_select "div.show_for div.wrapper"
end
end
test "show_for display false attribute if skip_blanks option is passed" do
swap ShowFor, skip_blanks: true do
with_attribute_for @user, :invalid
assert_select "div.show_for div.wrapper", /No/
end
end
# ATTRIBUTES
test "show_for attributes wraps each attribute with a label and content" do
with_attributes_for @user, :name, :email
assert_select "div.show_for div.user_name.wrapper", /ShowFor/
assert_select "div.user_name strong.label", "Super User Name!"
assert_select "div.show_for div.user_email.wrapper", /Not specified/
assert_select "div.user_email strong.label", "Email"
end
test "show_for should wrap blank attributes with no_attribute" do
swap ShowFor, blank_content_class: 'no_attribute' do
with_attributes_for @user, :name, :birthday, :karma
assert_select ".wrapper.user_birthday.no_attribute"
assert_select ".wrapper.user_karma.no_attribute"
assert_select ".wrapper.user_name.no_attribute", false
end
end
end
================================================
FILE: test/builder_test.rb
================================================
require 'test_helper'
class BuilderTest < ActionView::TestCase
# WRAPPER
test "show_for allows wrapper to be configured globally" do
swap ShowFor, wrapper_tag: "li", wrapper_class: "my_wrapper" do
with_attribute_for @user, :name
assert_select "div.show_for li.user_name.my_wrapper"
assert_select "div.show_for li.my_wrapper strong.label"
assert_select "div.show_for li.my_wrapper"
end
end
test "show_for allows wrapper class to be disabled globally" do
swap ShowFor, wrapper_tag: "li", wrapper_class: nil do
with_attribute_for @user, :name
assert_select "div.show_for li[class='user_name']"
end
end
test "show_for attribute wraps each attribute with a label and content" do
with_attribute_for @user, :name
assert_select "div.show_for div.user_name.wrapper"
assert_select "div.show_for div.wrapper strong.label"
assert_select "div.show_for div.wrapper"
end
test "show_for properly deals with namespaced models" do
@user = Namespaced::User.new(id: 1, name: "ShowFor")
with_attribute_for @user, :name
assert_select "div.show_for div.namespaced_user_name.wrapper"
assert_select "div.show_for div.wrapper strong.label"
assert_select "div.show_for div.wrapper"
end
test "show_for allows wrapper tag to be changed by attribute" do
with_attribute_for @user, :name, wrapper_tag: :span
assert_select "div.show_for span.user_name.wrapper"
end
test "show_for allows wrapper html to be configured by attribute" do
with_attribute_for @user, :name, wrapper_html: { id: "thewrapper", class: "special" }
assert_select "div.show_for div#thewrapper.user_name.wrapper.special"
end
# SEPARATOR
test "show_for allows separator to be configured globally" do
swap ShowFor, separator: '' do
with_attribute_for @user, :name
assert_select "div.show_for div.user_name span.separator"
assert_select "div.show_for div.wrapper span.separator"
assert_no_select "div.show_for br"
end
end
test "show_for allows separator to be changed by attribute"do
with_attribute_for @user, :name, separator: ''
assert_select "div.show_for div.wrapper span.separator"
assert_no_select "div.show_for br"
end
test "show_for allows disabling separator by attribute" do
with_attribute_for @user, :name, separator: false
assert_no_select "div.show_for div.wrapper span.separator"
assert_no_select "div.show_for div.wrapper br"
assert_no_select "div.show_for div.wrapper", /false/
end
test "show_for uses a separator if requested" do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper br"
end
test "show_for does not blow if a separator is not set" do
swap ShowFor, separator: nil do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper"
end
end
end
================================================
FILE: test/content_test.rb
================================================
require 'test_helper'
class ContentTest < ActionView::TestCase
test "show_for#content accepts any object" do
with_content_for @user, "Special content"
assert_select "div.show_for", "Special content"
end
test "show_for#content accepts :if_blank as option" do
with_content_for @user, "", if_blank: "Got blank"
assert_select "div.show_for", "Got blank"
end
test "show_for#content accepts html options" do
with_content_for @user, "Special content", content_tag: :b, id: "thecontent", class: "special"
assert_select "div.show_for b#thecontent.special.content", "Special content"
assert_no_select "div.show_for b[content_tag]"
end
test "show_for#content with blank value has a 'no value'-class" do
swap ShowFor, blank_content_class: "nothing" do
with_content_for @user, nil, content_tag: :b
assert_select "div.show_for b.nothing"
end
end
test "show_for#content with blank value does not display content if skip_blanks option is passed" do
swap ShowFor, skip_blanks: true do
with_content_for @user, nil, content_tag: :b
assert_no_select "div.show_for b"
end
end
end
================================================
FILE: test/generators/show_for_generator_test.rb
================================================
require 'test_helper'
class ShowForGeneratorTest < Rails::Generators::TestCase
tests ShowFor::Generators::InstallGenerator
destination File.expand_path('../../tmp', __FILE__)
setup :prepare_destination
teardown { rm_rf(destination_root) }
test 'generates example locale file' do
run_generator
assert_file 'config/locales/show_for.en.yml'
end
test 'generates the show_for initializer' do
run_generator
assert_file 'config/initializers/show_for.rb',
/config.show_for_tag = :div/
end
%W(erb haml slim).each do |engine|
test "generates the scaffold template when using #{engine}" do
run_generator ['-e', engine]
assert_file "lib/templates/#{engine}/scaffold/show.html.#{engine}"
end
end
end
================================================
FILE: test/helper_test.rb
================================================
require "test_helper"
class CustomBuilder < ShowFor::Builder
end
class HelperTest < ActionView::TestCase
test "show for yields an instance of ShowFor::Builder" do
show_for(@user) do |f|
assert f.instance_of?(ShowFor::Builder)
end
end
test "show for yields an instance of builder class specified by builder option" do
show_for(@user, builder: CustomBuilder) do |f|
assert f.instance_of?(CustomBuilder)
end
end
test "show for should add default class to form" do
concat(show_for(@user) do |f| end)
assert_select "div.show_for"
end
test "show for should add object class name as css class to form" do
concat(show_for(@user) do |f| end)
assert_select "div.show_for.user"
end
test "show for should pass options" do
concat(show_for(@user, id: "my_div", class: "common") do |f| end)
assert_select "div#my_div.show_for.user.common"
end
test "show for tag should be configurable" do
swap ShowFor, show_for_tag: :p do
concat(show_for(@user) do |f| end)
assert_select "p.show_for"
end
end
test "show for class should be configurable" do
swap ShowFor, show_for_class: :awesome do
concat(show_for(@user) do |f| end)
assert_select "div.show_for.user.awesome"
end
end
test "show for options hash should not be modified" do
html_options = { show_for_tag: :li }
concat(show_for(@user, html_options) do |f| end)
assert_equal({ show_for_tag: :li }, html_options)
end
end
================================================
FILE: test/label_test.rb
================================================
require 'test_helper'
class LabelTest < ActionView::TestCase
test "show_for shows a label using the humanized attribute name from model" do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper strong.label", "Super User Name!"
end
test "show_for skips label if requested" do
with_attribute_for @user, :name, label: false
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
end
test "show_for uses custom content_tag and skips label if requested" do
with_attribute_for @user, :name, label: false, content_tag: :h2
assert_select "div.show_for div.wrapper h2.content", "ShowFor"
end
test "show_for allows label to be configured globally" do
swap ShowFor, label_tag: :span, label_class: "my_label" do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper span.my_label"
end
end
test "show_for allows label class to be disabled globally" do
swap ShowFor, label_tag: :span, label_class: nil do
with_attribute_for @user, :name
assert_select "div.show_for div.wrapper span"
assert_no_select "span[class]"
end
end
test "show_for allows label to be changed by attribute" do
with_attribute_for @user, :name, label_tag: :span
assert_select "div.show_for div.wrapper span.label"
end
test "show_for allows label html to be configured by attribute" do
with_attribute_for @user, :name, label_html: { id: "thelabel", class: "special" }
assert_select "div.show_for div.wrapper strong#thelabel.special.label"
end
test "show_for allows label to be set without lookup" do
with_attribute_for @user, :name, label: "Special Label"
assert_select "div.show_for div.wrapper strong.label", "Special Label"
end
test "show_for#label accepts the text" do
with_label_for @user, "Special Label"
assert_select "div.show_for strong.label", "Special Label"
end
test "show_for#label accepts an attribute name" do
with_label_for @user, :name
assert_select "div.show_for strong.label", "Super User Name!"
end
test "show_for#label accepts html options" do
with_label_for @user, :name, id: "thelabel", class: "special"
assert_select "div.show_for strong#thelabel.special.label"
end
test "should let you override the label wrapper" do
swap ShowFor, label_proc: proc { |l| l + ":" } do
with_label_for @user, "Special Label"
assert_select "div.show_for strong.label", "Special Label:"
end
end
test "should you skip wrapping the label on a per item basis" do
swap ShowFor, label_proc: proc { |l| l + ":" } do
with_label_for @user, "Special Label", wrap_label: false
assert_select "div.show_for strong.label", "Special Label"
end
end
end
================================================
FILE: test/support/misc_helpers.rb
================================================
module MiscHelpers
def store_translations(locale, translations, &block)
begin
I18n.backend.store_translations locale, translations
yield
ensure
I18n.reload!
end
end
def assert_no_select(selector, value = nil)
assert_select(selector, text: value, count: 0)
end
def swap(object, new_values)
old_values = {}
new_values.each do |key, value|
old_values[key] = object.send key
object.send :"#{key}=", value
end
yield
ensure
old_values.each do |key, value|
object.send :"#{key}=", value
end
end
def with_attribute_for(object, attribute, options = {}, &block)
concat(show_for(object) do |o|
concat o.attribute(attribute, options, &block)
end)
end
def with_value_for(object, attribute, options = {}, &block)
concat(show_for(object) do |o|
concat o.value(attribute, options, &block)
end)
end
def with_association_for(object, association, options = {}, &block)
concat(show_for(object) do |o|
concat o.association(association, options, &block)
end)
end
def with_label_for(object, attribute, options = {})
concat(show_for(object) do |o|
concat o.label(attribute, options)
end)
end
def with_content_for(object, value, options = {})
concat(show_for(object) do |o|
concat o.content(value, options)
end)
end
def with_attributes_for(object, *attributes)
concat(show_for(object) do |o|
concat o.attributes(*attributes)
end)
end
end
================================================
FILE: test/support/models.rb
================================================
require 'ostruct'
Company = Struct.new(:id, :name) do
extend ActiveModel::Naming
def alternate_name
"Alternate #{self.name}"
end
end
Tag = Struct.new(:id, :name) do
extend ActiveModel::Naming
def self.all(options = {})
(1..3).map{ |i| Tag.new(i, "Tag #{i}") }
end
def alternate_name
"Alternate #{self.name}"
end
end
class User < OpenStruct
extend ActiveModel::Naming
# Get rid of deprecation warnings
undef_method :id if respond_to?(:id)
def tags
Tag.all
end
def company
Company.new(1, "Plataformatec")
end
def self.human_attribute_name(attribute)
case attribute
when 'name'
'Super User Name!'
when 'company'
'Company Human Name!'
else
attribute.humanize
end
end
def self.human_name
"User"
end
end
module Namespaced
class User < ::User
end
end
================================================
FILE: test/test_helper.rb
================================================
require 'bundler/setup'
require 'minitest/autorun'
require 'active_model'
require 'action_controller'
require 'action_view'
require 'action_view/template'
require 'action_view/test_case'
require "rails/generators/test_case"
require 'generators/show_for/install_generator'
$:.unshift File.expand_path("../../lib", __FILE__)
require 'show_for'
Dir["#{File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
I18n.enforce_available_locales = true
I18n.default_locale = :en
ActiveSupport::TestCase.test_order = :random if ActiveSupport::TestCase.respond_to?(:test_order=)
class ActionView::TestCase
include MiscHelpers
include ShowFor::Helper
setup :setup_new_user
def setup_new_user(options = {})
@user = User.new({
id: 1,
name: 'ShowFor',
description: '',
active: true,
invalid: false,
scopes: ["admin", "manager", "visitor"],
birthday: nil,
karma: Proc.new { nil },
created_at: Time.now,
updated_at: Date.today
}.merge(options))
end
end
================================================
FILE: test/value_test.rb
================================================
require 'test_helper'
class ValueTest < ActionView::TestCase
test "show_for allows content tag to be configured globally, without label and separator" do
swap ShowFor, content_tag: :span do
with_value_for @user, :name
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper span.content"
end
end
test "show_for allows content with tag to be changed by attribute, without label and separator" do
with_value_for @user, :name, content_tag: :span
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper span.content"
end
test "show_for allows content tag html to be configured by attribute, without label and separator" do
with_value_for @user, :name, content_tag: :span, content_html: { id: "thecontent", class: "special" }
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper span#thecontent.special.content"
end
test "show_for accepts an attribute as string, without label and separator" do
with_value_for @user, :name
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /ShowFor/
end
test "show_for accepts an attribute as time, without label and separator" do
with_value_for @user, :created_at
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.created_at))}/
end
test "show_for accepts an attribute as date, without label and separator" do
with_value_for @user, :updated_at
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.updated_at))}/
end
test "show_for accepts an attribute as time with format options, without label and separator" do
with_value_for @user, :created_at, format: :long
assert_select "div.show_for div.wrapper", /#{Regexp.escape(I18n.l(@user.created_at, format: :long))}/
end
test "show_for accepts an attribute as nil, without label and separator" do
with_value_for @user, :birthday
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /Not specified/
end
test "show_for accepts blank attributes, without label and separator" do
with_value_for @user, :description
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /Not specified/
end
test "show_for uses :if_blank if attribute is nil, without label and separator" do
with_value_for @user, :birthday, if_blank: "No description provided"
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /No description provided/
end
test "show_for uses :if_blank if attribute is blank, without label and separator" do
with_value_for @user, :description, if_blank: "No description provided"
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_select "div.show_for div.wrapper", /No description provided/
end
test "show_for escapes content by default, without label and separator" do
@user.name = "hack you!"
with_value_for @user, :name
assert_no_select "div.show_for div.wrapper strong.label"
assert_no_select "div.show_for div.wrapper br"
assert_no_select "div.show_for div.wrapper b"
assert_select "div.show_for div.wrapper", "hack you!"
end
end