carnesmedia/olson

View on GitHub
lib/olson/class_methods.rb

Summary

Maintainability
A
0 mins
Test Coverage
module ClassMethods

  # By default, humanize the attributes listed.
  #
  # Contrived Example:
  #
  #   class UserDecorator < ApplicationDecorator
  #     decorates :user
  #
  #     humanizes :activation_status, :plan_status
  #
  #     # Is a shortcut for:
  #
  #     def activation_status
  #       humanize :activation_status
  #     end
  #
  #     def plan_status
  #       humanize :plan_status
  #     end
  #   end
  #
  # See +ApplicationDecorator.humanize+ for a more detailed example.
  def humanizes(*attrs)
    attrs.each do |attr|
      define_method attr do         # def status
        humanize attr               #   humanize :status
      end                           # end

      attr_options = :"#{ attr }_options"
      define_singleton_method attr_options do   # def status_options
        options_for_select_with_i18n attr,      #   options_for_select_with_i18n 'status',
          source_class.send(attr_options)       #     User.status_options
      end                                       # end
    end
  end

  # Humanize an attribute using I18n, falling back to the humanized attributes value.
  #
  # The `.default_humanize` method can be overridden to configure how values are humanized
  # when they are not found in I18n.
  #
  # I tend to store attributes like `status` or `role` as underscored strings (a string that
  # would be suitable for a method/variable name) sometimes a simple .humanize will do the
  # trick when it comes to displaying that value in the UI user but other times you need to
  # customize them a bit which is one reason I18n is great. This helps automate the usage of
  # I18n for such a purpose.
  #
  # Contrived Example:
  #
  #   # user_decorator.rb
  #   class UserDecorator < ApplicationDecorator
  #     decorates :user
  #
  #     def activation_status
  #       humanize :activation_status
  #     end
  #
  #     def plan_status
  #       humanize :plan_status
  #     end
  #   end
  #
  #   # en.yml
  #   en:
  #     active: Current
  #     user:
  #       activation_status:
  #         active: 'Activated'
  #
  #   # Examples:
  #   @user.activation_status = 'active';
  #   @user.decorator.activation_status # => 'Activated'
  #
  #   @user.plan_status = 'active'
  #   @user.decorator.plan_status # => 'Current'
  #
  #   @user.activation_status = 'inactive'
  #   @user.decorator.activation_status # => 'Inactive'
  def humanize(attribute, value, default = default_humanize(value))
    i18n_with_scoped_defaults value, [model_name.i18n_key, attribute], default if value.present?
  end

  # The default way to humanize a value when not found in I18n.
  #
  # To configure the default humanization, you can override `.default_humanize` in your
  # decorator. For example, to use `String#titleize` instead of `String#humanize`:
  #
  #   # user_decorator.rb
  #   class UserDecorator < ApplicationDecorator
  #     decorates :user
  #
  #     def self.default_humanize(value)
  #       value.to_s.titleize
  #     end
  #   end
  #
  def default_humanize(value)
    value.to_s.humanize
  end

  # Try to translate a key with I18n and a scope but fallback to less-and-less scope.
  # An example will explain more clearly:
  #
  #   i18n_with_scoped_defaults(:some_key, [:foo, :bar, :baz])
  #
  # Will try the following I18n translations in order:
  # * foo.bar.baz.some_key
  # * foo.bar.some_key
  # * foo.some_key
  # * some_key
  #
  # And if none of the I18n keys translate, it will use the default param (which defaults to
  # humanizing the provided key).
  #
  # The final call to I18n will be:
  #
  #   I18n.t :'foo.bar.baz.some_key', defaults: [
  #     :'foo.bar.some_key', :'foo.some_key', :some_key, 'Some key'
  #   ]
  #
  # REVIEW: Should the root :some_key be used? or should i18n_with_scoped_defaults skip it?
  #
  def i18n_with_scoped_defaults(key, scope = [], default = key.to_s.humanize)
    scope << key
    key = scope.join('.').to_sym

    defaults = []
    defaults << scope.join('.').to_sym while scope.delete_at(-2)
    defaults << default

    I18n.t key, default: defaults
  end


  # Use humanize to generate select options for an attribute and given options.
  #
  # Example usage:
  #
  #   # user.rb
  #   class User < AR::Base
  #     ROLE_OPTIONS = %w(admin user)
  #     ...
  #   end
  #
  #   # user_decorator.rb
  #   class UserDecorator < ApplicationDecorator
  #     humanizes :role
  #
  #     def self.role_options
  #       options_for_select_with_i18n :role, User::ROLE_OPTIONS
  #     end
  #   end
  #
  #   # admin/users/edit.html.erb
  #   <%= simple_form_for @user do |f| %>
  #     <%= f.input :role, collection: UserDecorator.role_options %>
  #   ...
  def options_for_select_with_i18n(attribute, options)
    options.map do |option|
      [ humanize(attribute, option), option ]
    end
  end
end