Module: Compony
- Defined in:
- lib/compony.rb,
lib/compony/engine.rb,
lib/compony/version.rb,
lib/compony/component.rb,
lib/compony/model_mixin.rb,
lib/compony/view_helpers.rb,
lib/compony/components/new.rb,
lib/compony/components/edit.rb,
lib/compony/components/form.rb,
lib/compony/request_context.rb,
lib/compony/controller_mixin.rb,
lib/compony/model_fields/url.rb,
lib/compony/natural_ordering.rb,
lib/compony/components/button.rb,
lib/compony/model_fields/base.rb,
lib/compony/model_fields/date.rb,
lib/compony/model_fields/text.rb,
lib/compony/model_fields/time.rb,
lib/compony/components/destroy.rb,
lib/compony/model_fields/color.rb,
lib/compony/model_fields/email.rb,
lib/compony/model_fields/float.rb,
lib/compony/model_fields/phone.rb,
lib/compony/model_fields/string.rb,
lib/compony/components/with_form.rb,
lib/compony/model_fields/boolean.rb,
lib/compony/model_fields/decimal.rb,
lib/compony/model_fields/integer.rb,
lib/compony/model_fields/currency.rb,
lib/compony/model_fields/datetime.rb,
lib/compony/method_accessible_hash.rb,
lib/compony/model_fields/rich_text.rb,
lib/compony/model_fields/attachment.rb,
lib/compony/model_fields/percentage.rb,
lib/compony/model_fields/anchormodel.rb,
lib/compony/model_fields/association.rb,
lib/compony/component_mixins/resourceful.rb,
lib/compony/component_mixins/default/labelling.rb,
lib/compony/component_mixins/default/standalone.rb,
lib/compony/component_mixins/default/standalone/verb_dsl.rb,
lib/compony/component_mixins/default/standalone/standalone_dsl.rb,
lib/compony/component_mixins/default/standalone/resourceful_verb_dsl.rb
Overview
Root module, containing confguration and pure helpers. For the setters, create an initializer config/initializers/compony.rb
and call them from there.
Defined Under Namespace
Modules: ComponentMixins, Components, ControllerMixin, ModelFields, ModelMixin, Version, ViewHelpers Classes: Component, Engine, MethodAccessibleHash, NaturalOrdering, RequestContext
Class Method Summary collapse
-
.authentication_before_action ⇒ Object
Getter for the name of the Rails
before_action
that enforces authentication. -
.authentication_before_action=(authentication_before_action) ⇒ Object
Setter for the name of the Rails
before_action
that should be called to ensure that users are authenticated before accessing the component. -
.button(comp_name_or_cst, model_or_family_name_or_cst, label_opts: nil, params: nil, feasibility_action: nil, feasibility_target: nil, method: nil, **override_kwargs) ⇒ Object
Given a component and a family/model, this instanciates and returns a button component.
-
.button_component_class ⇒ Object
Getter for the global button component class.
-
.button_component_class=(button_component_class) ⇒ Object
Setter for the global button component class.
-
.button_defaults ⇒ Object
Getter for current button defaults.
-
.comp_class_for(comp_name_or_cst, model_or_family_name_or_cst) ⇒ Object
Given a component and a family/model, this returns the matching component class if any, or nil if the component does not exist.
-
.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst) ⇒ Object
Same as Compony#comp_class_for but fails if none found.
-
.content_after_root_comp(&block) ⇒ Object
Setter for a content block that runs after the root component gets rendered (standalone only).
-
.content_after_root_comp_block ⇒ Object
Getter for content_after_root_comp_block.
-
.content_before_root_comp(&block) ⇒ Object
Setter for a content block that runs before the root component gets rendered (standalone only).
-
.content_before_root_comp_block ⇒ Object
Getter for content_before_root_comp_block.
-
.family_name_for(model_or_family_name_or_cst) ⇒ Object
Given a family name or a model-like class, this returns the suitable family name as String.
-
.model_field_class_for(constant) ⇒ Object
Goes through model_field_namespaces and returns the first hit for the given constant.
-
.model_field_namespaces ⇒ Object
Getter for the global field namespaces.
-
.model_field_namespaces=(model_field_namespaces) ⇒ Object
Setter for the global field namespaces.
-
.path(comp_name_or_cst, model_or_family_name_or_cst, *args_for_path_helper, **kwargs_for_path_helper) ⇒ Object
Generates a Rails path to a component.
-
.path_helper_name ⇒ Object
Given a component and a family, this returns the name of the Rails URL helper returning the path to this component.
The parameters are the same as for Compony.rails_action_name.
Example usage:send("#{path_helper_name(:index, :users)}_url)
. -
.rails_action_name(comp_name_or_cst, model_or_family_name_or_cst, name = nil) ⇒ Object
Given a component and a family, this returns the name of the ComponyController action for this component.
Optionally can pass a name for extra standalone configs. -
.root_comp ⇒ Object
Returns the current root component, if any.
-
.with_button_defaults(**keys_to_overwrite, &block) ⇒ Object
Overwrites the keys of the current button defaults by the ones provided during the execution of a given block and restores them afterwords.
Class Method Details
.authentication_before_action ⇒ Object
Getter for the name of the Rails before_action
that enforces authentication.
77 78 79 |
# File 'lib/compony.rb', line 77 def self.authentication_before_action @authentication_before_action end |
.authentication_before_action=(authentication_before_action) ⇒ Object
Setter for the name of the Rails before_action
that should be called to ensure that users are authenticated before accessing the component. For instance, implement a method def enforce_authentication
in your ApplicationController
. In the method, make sure the user has a session and redirect to the login page if they don’t.
The action must be accessible by ComponyController and the easiest way to achieve this is to implement the action in your ApplicationController
. If this is never called, authentication is disabled.
39 40 41 |
# File 'lib/compony.rb', line 39 def self.authentication_before_action=(authentication_before_action) @authentication_before_action = authentication_before_action.to_sym end |
.button(comp_name_or_cst, model_or_family_name_or_cst, label_opts: nil, params: nil, feasibility_action: nil, feasibility_target: nil, method: nil, **override_kwargs) ⇒ Object
Given a component and a family/model, this instanciates and returns a button component.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/compony.rb', line 168 def self.(comp_name_or_cst, model_or_family_name_or_cst, label_opts: nil, params: nil, feasibility_action: nil, feasibility_target: nil, method: nil, **override_kwargs) label_opts ||= [:label_opts] || {} params ||= [:params] || {} model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil target_comp_instance = Compony.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst).new(data: model) feasibility_action ||= [:feasibility_action] || comp_name_or_cst.to_s.underscore.to_sym feasibility_target ||= [:feasibility_target] || model = { label: target_comp_instance.label(model, **label_opts), icon: target_comp_instance.icon, color: target_comp_instance.color, path: Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, **params), method:, visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, verb: method) } } if feasibility_target .merge!({ enabled: feasibility_target.feasible?(feasibility_action), title: feasibility_target.(feasibility_action).presence }) end .merge!(override_kwargs.symbolize_keys) return Compony..new(**.symbolize_keys) end |
.button_component_class ⇒ Object
Getter for the global button component class.
63 64 65 66 67 |
# File 'lib/compony.rb', line 63 def self. @button_component_class ||= Components::Button @button_component_class = const_get(@button_component_class) if @button_component_class.is_a?(String) return @button_component_class end |
.button_component_class=(button_component_class) ⇒ Object
Setter for the global button component class. This allows you to implement a custom button component and have all Compony button helpers use your custom button component instead of Compony::Components::Button.
15 16 17 |
# File 'lib/compony.rb', line 15 def self.() @button_component_class = end |
.button_defaults ⇒ Object
document params
Getter for current button defaults
219 220 221 |
# File 'lib/compony.rb', line 219 def self. RequestStore.store[:button_defaults] || {} end |
.comp_class_for(comp_name_or_cst, model_or_family_name_or_cst) ⇒ Object
Given a component and a family/model, this returns the matching component class if any, or nil if the component does not exist.
120 121 122 123 124 125 126 127 |
# File 'lib/compony.rb', line 120 def self.comp_class_for(comp_name_or_cst, model_or_family_name_or_cst) family_cst_str = family_name_for(model_or_family_name_or_cst).camelize comp_cst_str = comp_name_or_cst.to_s.camelize return nil unless ::Components.const_defined?(family_cst_str) family_constant = ::Components.const_get(family_cst_str) return nil unless family_constant.const_defined?(comp_cst_str) return family_constant.const_get(comp_cst_str) end |
.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst) ⇒ Object
Same as Compony#comp_class_for but fails if none found
131 132 133 134 135 |
# File 'lib/compony.rb', line 131 def self.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst) comp_class_for(comp_name_or_cst, model_or_family_name_or_cst) || fail( "No component found for [#{comp_name_or_cst.inspect}, #{model_or_family_name_or_cst.inspect}]" ) end |
.content_after_root_comp(&block) ⇒ Object
Setter for a content block that runs after the root component gets rendered (standalone only). Usage is the same as content
. The block runs after render
, i.e. after the last content
block.
52 53 54 55 |
# File 'lib/compony.rb', line 52 def self.content_after_root_comp(&block) fail('`Compony.content_after` requires a block.') unless block_given? @content_after_root_comp_block = block end |
.content_after_root_comp_block ⇒ Object
Getter for content_after_root_comp_block
89 90 91 |
# File 'lib/compony.rb', line 89 def self.content_after_root_comp_block @content_after_root_comp_block end |
.content_before_root_comp(&block) ⇒ Object
Setter for a content block that runs before the root component gets rendered (standalone only). Usage is the same as content
. The block runs between before_render
and render
, i.e. before the first content
block.
45 46 47 48 |
# File 'lib/compony.rb', line 45 def self.content_before_root_comp(&block) fail('`Compony.content_before` requires a block.') unless block_given? @content_before_root_comp_block = block end |
.content_before_root_comp_block ⇒ Object
Getter for content_before_root_comp_block
83 84 85 |
# File 'lib/compony.rb', line 83 def self.content_before_root_comp_block @content_before_root_comp_block end |
.family_name_for(model_or_family_name_or_cst) ⇒ Object
Given a family name or a model-like class, this returns the suitable family name as String.
209 210 211 212 213 214 215 |
# File 'lib/compony.rb', line 209 def self.family_name_for(model_or_family_name_or_cst) if model_or_family_name_or_cst.respond_to?(:model_name) return model_or_family_name_or_cst.model_name.plural else return model_or_family_name_or_cst.to_s.underscore end end |
.model_field_class_for(constant) ⇒ Object
Goes through model_field_namespaces and returns the first hit for the given constant
250 251 252 253 254 255 256 257 258 |
# File 'lib/compony.rb', line 250 def self.model_field_class_for(constant) model_field_namespaces.each do |model_field_namespace| model_field_namespace = model_field_namespace.constantize if model_field_namespace.is_a?(::String) if model_field_namespace.const_defined?(constant, false) return model_field_namespace.const_get(constant, false) end end fail("No `model_field_namespace` implements ...::#{constant}. Configured namespaces: #{Compony.model_field_namespaces.inspect}") end |
.model_field_namespaces ⇒ Object
Getter for the global field namespaces.
71 72 73 |
# File 'lib/compony.rb', line 71 def self.model_field_namespaces return @model_field_namespaces ||= ['Compony::ModelFields'] end |
.model_field_namespaces=(model_field_namespaces) ⇒ Object
Setter for the global field namespaces. This allows you to implement custom Fields, be it new ones or overrides for existing Compony model fields. Must give an array of strings of namespaces that contain field classes named after the field type. The array is queried in order, if the first namespace does not contain the class we’re looking for, the next is considered and so on. The classes defined in the namespace must inherit from Compony::ModelFields::Base
26 27 28 |
# File 'lib/compony.rb', line 26 def self.model_field_namespaces=(model_field_namespaces) @model_field_namespaces = model_field_namespaces end |
.path(comp_name_or_cst, model_or_family_name_or_cst, *args_for_path_helper, **kwargs_for_path_helper) ⇒ Object
Generates a Rails path to a component. Examples: Compony.path(:index, :users)
, Compony.path(:show, User.first)
105 106 107 108 109 110 111 112 113 |
# File 'lib/compony.rb', line 105 def self.path(comp_name_or_cst, model_or_family_name_or_cst, *args_for_path_helper, **kwargs_for_path_helper) # Extract model if any, to get the ID kwargs_for_path_helper.merge!(id: model_or_family_name_or_cst.id) if model_or_family_name_or_cst.respond_to?(:model_name) return Rails.application.routes.url_helpers.send( "#{path_helper_name(comp_name_or_cst, model_or_family_name_or_cst)}_path", *args_for_path_helper, **kwargs_for_path_helper ) end |
.path_helper_name ⇒ Object
Given a component and a family, this returns the name of the Rails URL helper returning the path to this component.
The parameters are the same as for rails_action_name.
Example usage: send("#{path_helper_name(:index, :users)}_url)
142 143 144 |
# File 'lib/compony.rb', line 142 def self.path_helper_name(...) "#{rails_action_name(...)}_comp" end |
.rails_action_name(comp_name_or_cst, model_or_family_name_or_cst, name = nil) ⇒ Object
Given a component and a family, this returns the name of the ComponyController action for this component.
Optionally can pass a name for extra standalone configs.
152 153 154 |
# File 'lib/compony.rb', line 152 def self.rails_action_name(comp_name_or_cst, model_or_family_name_or_cst, name = nil) [name.presence, comp_name_or_cst.to_s.underscore, family_name_for(model_or_family_name_or_cst)].compact.join('_') end |
.root_comp ⇒ Object
Returns the current root component, if any
201 202 203 |
# File 'lib/compony.rb', line 201 def self.root_comp RequestStore.store[:compony_root_comp] end |
.with_button_defaults(**keys_to_overwrite, &block) ⇒ Object
Overwrites the keys of the current button defaults by the ones provided during the execution of a given block and restores them afterwords. This method is useful when the same set of options is to be given to a multitude of buttons.
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/compony.rb', line 227 def self.(**keys_to_overwrite, &block) # Lazy initialize butto_defaults store if it hasn't been yet RequestStore.store[:button_defaults] ||= {} keys_to_overwrite.transform_keys!(&:to_sym) old_values = {} newly_defined_keys = keys_to_overwrite.keys - RequestStore.store[:button_defaults].keys keys_to_overwrite.each do |key, new_value| # Assign new value old_values[key] = RequestStore.store[:button_defaults][key] RequestStore.store[:button_defaults][key] = new_value end return_value = block.call # Restore previous value keys_to_overwrite.each do |key, _new_value| RequestStore.store[:button_defaults][key] = old_values[key] end # Undefine keys that were not there previously newly_defined_keys.each { |key| RequestStore.store[:button_defaults].delete(key) } return return_value end |