lib/status_tag/presenter.rb
# SRP: Provides a method signature that can be splatted to content_tag_for to create labels
#
# This base class can be used to instantiate a label for anything.
# Subclasses will address specific needs, like a label for user status, order status, job state, etc.
# Flexible: not explicitly dependent on bootstrap or any other style framework.
#
# Example:
#
# text, signature = StatusTag::Presenter.status_tag_signature_for(:span, mtm_profile, "fit_status")
# content_tag_for(*signature) do
# text
# end
module StatusTag
class Presenter
# Override constants in subclasses
ORDERED_CHOICES = [StatusTag::Choice.new]
CSS_CLASS = [] # A CSS class or classes to assign to all tags generated with the presenter
# RECEIVER CONFIGURATION
# :object sends the messages to the object passed into the initializer
# :self sends the messages to the to the presenter class instance
# (which has an internal reference to object) and would allow more complicated logic that
# pertains to the view, not the model.
CHOICE_NAME_MESSAGE_RECEIVER = :object
CHOICE_TEXT_MESSAGE_RECEIVER = :object
attr_accessor :object, # e.g. an instance of the User class
:aspect # e.g. "state", "status" or some other descriptive name for this particular status tag
# Defaults to nil, so by default there is only one StatusTag presenter allowed per object class,
# as the aspect provides a namespace for additional presenters.
attr_reader :decider, :choice, :options
def initialize(object:, aspect: nil, options: {})
@object = object
@aspect = aspect
@decider = StatusTag::Decider.new(ordered_choices: self.class.ordered_choices(object, aspect))
@options = options || {}
end
def decide
@choice = if (self.class)::CHOICE_NAME_MESSAGE_RECEIVER == :object
decider.decide(object)
else
decider.decide(self)
end
end
def text
return "" unless choice
if choice.text.is_a?(Symbol)
receiver = (self.class)::CHOICE_TEXT_MESSAGE_RECEIVER == :object ? object : self
receiver.send(choice.text)
else
choice.text
end
end
def noop?
return true unless choice
choice.noop?
end
def css_class
return nil unless choice
choice.css_class
end
# An alternative to overriding the constant in subclasses is to override this method.
# If you override, do not change the signature.
# The params enable the ordered choices to be derived dynamically for your needs, but are not used by default.
def self.ordered_choices(object, aspect)
self::ORDERED_CHOICES
end
# An alternative to overriding the CSS_CLASS constant in subclasses is to override this method.
# If you override, do not change the signature.
# The params enable the ordered choices to be derived dynamically for your needs, but are not used by default.
def self.css_class(object, aspect)
self::CSS_CLASS
end
end
end