Class: CafeCar::Presenter

Inherits:
Object
  • Object
show all
Includes:
Caching, OptionHelpers
Defined in:
app/presenters/cafe_car/presenter.rb

Overview

Acts 1:3

Direct Known Subclasses

DateTimePresenter

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OptionHelpers

#assign_option!, #assign_options!, #get_options

Methods included from Caching

#cache

Constructor Details

#initialize(template, object, **options, &block) ⇒ Presenter

Returns a new instance of Presenter.



42
43
44
45
46
47
48
49
# File 'app/presenters/cafe_car/presenter.rb', line 42

def initialize(template, object, **options, &block)
  @template         = template
  @object           = object
  @options          = options
  @block            = options.delete(:block) { block }
  @shown_attributes = {}
  assign_options!
end

Instance Attribute Details

#blockObject (readonly)

Returns the value of attribute block.



11
12
13
# File 'app/presenters/cafe_car/presenter.rb', line 11

def block
  @block
end

#objectObject (readonly)

Returns the value of attribute object.



11
12
13
# File 'app/presenters/cafe_car/presenter.rb', line 11

def object
  @object
end

#optionsObject (readonly)

Returns the value of attribute options.



11
12
13
# File 'app/presenters/cafe_car/presenter.rb', line 11

def options
  @options
end

Class Method Details

.candidates(klass) ⇒ Object



29
30
31
# File 'app/presenters/cafe_car/presenter.rb', line 29

def self.candidates(klass)
  names(klass).map { "#{_1}Presenter" }
end

.find(klass) ⇒ Object



25
26
27
# File 'app/presenters/cafe_car/presenter.rb', line 25

def self.find(klass)
  candidates(klass).filter_map { CafeCar[_1] }.first or raise "Could not find presenter"
end

.inherited(subclass) ⇒ Object



15
16
17
18
# File 'app/presenters/cafe_car/presenter.rb', line 15

def self.inherited(subclass)
  super
  subclass.show_defaults = show_defaults.deep_dup
end

.names(klass) ⇒ Object



33
34
35
36
# File 'app/presenters/cafe_car/presenter.rb', line 33

def self.names(klass)
  return [ klass.to_s.classify ] if klass.is_a?(Symbol)
  klass.ancestors.lazy.map(&:name).compact
end

.present(template, object, **options) ⇒ Object



20
21
22
23
# File 'app/presenters/cafe_car/presenter.rb', line 20

def self.present(template, object, **options, &)
  object = object.object if object.is_a?(Presenter)
  find(options.fetch(:as) { object.class }).new(template, object, **options, &)
end

.show(method, block = nil) ⇒ Object



38
39
40
# File 'app/presenters/cafe_car/presenter.rb', line 38

def self.show(method, block = nil, **)
  show_defaults[method].merge!({ block: }.compact, **)
end

Instance Method Details

#associations(*names, **options, &block) ⇒ Object



132
133
134
135
# File 'app/presenters/cafe_car/presenter.rb', line 132

def associations(*names, **options, &block)
  names = policy.displayable_associations if names.blank?
  attributes(*names, **options, &block)
end

#attribute(method) ⇒ Object



103
104
105
106
107
108
109
110
111
# File 'app/presenters/cafe_car/presenter.rb', line 103

def attribute(method, **, &)
  content = show(method, &)
  return "" if content.blank?

  ui.Field do |f|
    concat f.Label(safe_join([ human(method), *info_circle(method) ], " "), tag: :strong)
    concat f.Content(content)
  end
end

#attributes(*methods, except: nil, **options, &block) ⇒ Object



75
76
77
78
79
80
81
82
83
84
# File 'app/presenters/cafe_car/presenter.rb', line 75

def attributes(*methods, except: nil, **options, &block)
  methods  = policy.displayable_attributes if methods.empty?
  methods  = methods.flatten.compact
  methods -= [ *except ]
  capture do
    methods.map do |method|
      attribute(method, **options, &block)
    end.each { concat(_1) }
  end
end

#controls(**options, &block) ⇒ Object



143
144
145
# File 'app/presenters/cafe_car/presenter.rb', line 143

def controls(**options, &block)
  render("controls", object:, options:, &block)
end

#has_partial?Boolean

Returns:

  • (Boolean)


57
# File 'app/presenters/cafe_car/presenter.rb', line 57

def has_partial? = partial&.then { partial? _1 }

#hrefObject

The object’s canonical path, or nil when it isn’t independently routable (e.g. a nested resource like a line item).



90
91
92
93
94
# File 'app/presenters/cafe_car/presenter.rb', line 90

def href
  href_for(object)
rescue NoMethodError, ActionController::UrlGenerationError
  nil
end

#html_safe?Boolean

Returns:

  • (Boolean)


53
# File 'app/presenters/cafe_car/presenter.rb', line 53

def html_safe? = true

#human(method) ⇒ Object



114
# File 'app/presenters/cafe_car/presenter.rb', line 114

def human(method, **) = model.human_attribute_name(method, **)

#i18n(action, scope: nil) ⇒ Object



149
150
151
152
153
154
155
# File 'app/presenters/cafe_car/presenter.rb', line 149

def i18n(action, scope: nil, **)
  vars = i18n_vars Action: t(action, default: action.to_s.humanize),
                   Model:  model_name.human,
                   Models: model_name.human(count: 2),
                   Object: link(@object).to_s.html_safe
  @template.translate(action, scope:, default: :default, deep_interpolation: true, **vars, **)
end

#i18n_vars(names) ⇒ Object



147
# File 'app/presenters/cafe_car/presenter.rb', line 147

def i18n_vars(names) = names.merge(*names.map { { _1.to_s.downcase.to_sym => _2.downcase } })

#info(method) ⇒ Object



113
# File 'app/presenters/cafe_car/presenter.rb', line 113

def info(method) = model.info.field(method)

#info_circle(method, *args, **opts, &block) ⇒ Object



137
138
139
140
141
# File 'app/presenters/cafe_car/presenter.rb', line 137

def info_circle(method, *args, **opts, &block)
  tip = info(method).hint
  return unless tip
  ui.InfoCircle(*args, tip:, **opts, &block)
end


86
# File 'app/presenters/cafe_car/presenter.rb', line 86

def links = link(object)

#logoObject



69
# File 'app/presenters/cafe_car/presenter.rb', line 69

def (*, **, &) = show(policy.logo_attribute, *, **, &)

#modelObject



52
# File 'app/presenters/cafe_car/presenter.rb', line 52

def model      = @object.is_a?(Class) ? @object : @object.class

#partialObject



56
# File 'app/presenters/cafe_car/presenter.rb', line 56

def partial      = @object.try(:to_partial_path)

#presentObject



55
# File 'app/presenters/cafe_car/presenter.rb', line 55

def present(...) = @template.present(...)

#previewObject



96
97
98
99
100
101
# File 'app/presenters/cafe_car/presenter.rb', line 96

def preview(**, &)
  ui.Row :space, href: do
    concat (size: :icon)
    concat title
  end
end

#remaining_attributes(count = nil, **options, &block) ⇒ Object



126
127
128
129
130
# File 'app/presenters/cafe_car/presenter.rb', line 126

def remaining_attributes(count = nil, **options, &block)
  attrs = policy.displayable_attributes - @shown_attributes.keys
  attrs = attrs.take(count) if count
  attributes(*attrs, **options, &block)
end

#show(method, **options) ⇒ Object



120
121
122
123
124
# File 'app/presenters/cafe_car/presenter.rb', line 120

def show(method, **options, &)
  return if method.nil?
  @shown_attributes[method] = true
  present(value(method), **show_defaults[method], **options, &)
end

#timestampsObject



71
72
73
# File 'app/presenters/cafe_car/presenter.rb', line 71

def timestamps(**, &)
  attributes(*model.info.fields.timestamps.names, **, &)
end

#titleObject



68
# File 'app/presenters/cafe_car/presenter.rb', line 68

def title(*, **, &) = show(policy.title_attribute, *, blank: show(:id), **, &)

#to_htmlObject



62
63
64
65
66
# File 'app/presenters/cafe_car/presenter.rb', line 62

def to_html
  return render(object:, partial:) if has_partial?
  return blank if captured.blank? && blank
  preview
end

#to_modelObject



51
# File 'app/presenters/cafe_car/presenter.rb', line 51

def to_model   = @object

#to_sObject



54
# File 'app/presenters/cafe_car/presenter.rb', line 54

def to_s       = to_html.to_s

#value(method) ⇒ Object



116
117
118
# File 'app/presenters/cafe_car/presenter.rb', line 116

def value(method)
  model.inspection_filter.filter_param(method, object.try(method))
end