Class: Compony::Intent
- Inherits:
-
Object
- Object
- Compony::Intent
- Defined in:
- lib/compony/intent.rb
Overview
An Intent is a a gateway to a component, along with relevant context, such as the comp and family, perhaps a resource, standalone name, feasibility etc.
The class provides tooling used by various Compony helpers used to point to other components in some way.
Note: The arguments label and style are not part of the button: hash, because they are processed by the Intent before affecting the button.
Instance Attribute Summary collapse
- #comp_class ⇒ Object readonly
- #data ⇒ Object readonly
Instance Method Summary collapse
-
#button_comp_opts ⇒ Object
Returns the options that are given to the initializer when creating a button from this intent.
-
#comp ⇒ Object
Instanciates the component and returns the instance.
- #feasibility_action ⇒ Object
- #feasibility_target ⇒ Object
-
#feasible? ⇒ Boolean
Returns whether this intent is feasible (no prevention).
-
#initialize(comp_name_or_cst_or_class = nil, model_or_family_name_or_cst = nil, standalone_name: nil, name: nil, label: nil, style: nil, button: {}, path: nil, method: nil, data: nil, data_class: nil, feasibility_target: nil, feasibility_action: nil) ⇒ Intent
constructor
A new instance of Intent.
-
#label(model = nil, **label_opt_overrides) ⇒ Object
Returns the label of buttons produced by this intent.
- #method ⇒ Object
-
#model? ⇒ Boolean
Returns true for things like User.first, but false for things like :users or User.
-
#name ⇒ Object
Returns a name for this intent, consisting of comp and family name.
-
#path(model = nil, standalone_name: nil, **path_opt_overrides) ⇒ Object
Returns the path to the component.
-
#render(controller, parent_comp = nil, style: nil, **button_arg_overrides) ⇒ Object
Renders this intent into a button defined by
style.
Constructor Details
#initialize(comp_name_or_cst_or_class = nil, model_or_family_name_or_cst = nil, standalone_name: nil, name: nil, label: nil, style: nil, button: {}, path: nil, method: nil, data: nil, data_class: nil, feasibility_target: nil, feasibility_action: nil) ⇒ Intent
Returns a new instance of Intent.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/compony/intent.rb', line 26 def initialize(comp_name_or_cst_or_class = nil, model_or_family_name_or_cst = nil, standalone_name: nil, name: nil, label: nil, style: nil, button: {}, path: nil, method: nil, data: nil, data_class: nil, feasibility_target: nil, feasibility_action: nil) # Check for model / data @data = data @data ||= model_or_family_name_or_cst if model_or_family_name_or_cst.respond_to?(:model_name) @data_class = data_class # Figure out comp_class if comp_name_or_cst_or_class.nil? if name.blank? || !label.is_a?(String) fail('An intent created without positional arguments must be given the kwargs `name:`, `label` (String).') end elsif comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component) # A class was given as the first argument @comp_class = comp_name_or_cst_or_class else # Build the constant from the first two arguments family_underscore_str = if !(model_or_family_name_or_cst.is_a?(String) || model_or_family_name_or_cst.is_a?(Symbol)) && @data.respond_to?(:model_name) # Determine the component family from the data @data.model_name.plural else # Determine the component family from the given argument model_or_family_name_or_cst.to_s.underscore end constant_str = "::Components::#{family_underscore_str.camelize}::#{comp_name_or_cst_or_class.to_s.camelize}" @comp_class = constant_str.constantize end # Store further arguments @name = name&.to_sym @standalone_name = standalone_name @label = label.is_a?(String) ? label : nil @label_opts = label.is_a?(Hash) ? label : {} @style = style&.to_sym @button_opts = @path = path.is_a?(String) ? path : nil @path_opts = path.is_a?(Hash) ? path : {} @method = method&.to_sym @feasibility_target = feasibility_target @feasibility_action = feasibility_action end |
Instance Attribute Details
#comp_class ⇒ Object (readonly)
7 8 9 |
# File 'lib/compony/intent.rb', line 7 def comp_class @comp_class end |
#data ⇒ Object (readonly)
8 9 10 |
# File 'lib/compony/intent.rb', line 8 def data @data end |
Instance Method Details
#button_comp_opts ⇒ Object
Returns the options that are given to the initializer when creating a button from this intent.
134 135 136 137 138 139 140 141 142 |
# File 'lib/compony/intent.rb', line 134 def return { label:, href: feasible? ? path : nil, method:, class: feasible? ? nil : 'disabled', title: feasible? ? nil : feasibility_target.(feasibility_action).presence }.deep_merge(@button_opts) end |
#comp ⇒ Object
Instanciates the component and returns the instance. If data and/or data_class were specified when instantiating this intent, they are passed.
All given arguments will be given to the component's initializer, also overriding data and data_class if present.
87 88 89 90 |
# File 'lib/compony/intent.rb', line 87 def comp(*, **) return nil if @comp_class.nil? return @comp ||= @comp_class.new(*, data: @data, data_class: @data_class, **) end |
#feasibility_action ⇒ Object
123 124 125 |
# File 'lib/compony/intent.rb', line 123 def feasibility_action @feasibility_action.presence || comp_class.comp_name.to_sym end |
#feasibility_target ⇒ Object
119 120 121 |
# File 'lib/compony/intent.rb', line 119 def feasibility_target @feasibility_target.presence || model? ? @data : nil end |
#feasible? ⇒ Boolean
Returns whether this intent is feasible (no prevention)
128 129 130 131 |
# File 'lib/compony/intent.rb', line 128 def feasible? return true if feasibility_target.blank? || feasibility_action.blank? return feasibility_target.feasible?(feasibility_action) end |
#label(model = nil, **label_opt_overrides) ⇒ Object
Returns the label of buttons produced by this intent.
110 111 112 113 |
# File 'lib/compony/intent.rb', line 110 def label(model = nil, *, **label_opt_overrides) label_opts = @label_opts.deep_merge(label_opt_overrides) @label.presence || comp.label(model || (model? ? @data : nil), *, **label_opts) end |
#method ⇒ Object
115 116 117 |
# File 'lib/compony/intent.rb', line 115 def method @method || :get end |
#model? ⇒ Boolean
Returns true for things like User.first, but false for things like :users or User
80 81 82 83 |
# File 'lib/compony/intent.rb', line 80 def model? @model = @data.respond_to?(:model_name) && !@data.is_a?(Class) if @model.nil? return @model end |
#name ⇒ Object
Returns a name for this intent, consisting of comp and family name. Can be overriden in the constructor. Example: :show_users, :destroy_sessions
105 106 107 |
# File 'lib/compony/intent.rb', line 105 def name @name.presence || :"#{comp_class.comp_name}_#{comp_class.family_name}" end |
#path(model = nil, standalone_name: nil, **path_opt_overrides) ⇒ Object
Returns the path to the component. Additional arguments are passed to the component's path block, which typically passes them to the Rails path helper.
96 97 98 99 100 101 |
# File 'lib/compony/intent.rb', line 96 def path(model = nil, *, standalone_name: nil, **path_opt_overrides) return @path if @path.present? return nil if @comp_class.nil? path_opts = @path_opts.deep_merge(path_opt_overrides) comp.path(model || (model? ? @data : nil), standalone_name: standalone_name || @standalone_name, **path_opts) end |
#render(controller, parent_comp = nil, style: nil, **button_arg_overrides) ⇒ Object
Renders this intent into a button defined by style.
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/compony/intent.rb', line 149 def render(controller, parent_comp = nil, style: nil, **) # Abort if not authorized return nil if comp && !comp.standalone_access_permitted_for?(controller, standalone_name: @standalone_name, verb: method) # Prepare opts ||= Compony.(*[style || @style].compact) = (comp&. || {}).merge().merge() # overrides go right to left # Perform render if parent_comp return parent_comp.sub_comp(, **).render(controller) else .new(**).render(controller) end end |