Module: Compony

Defined in:
lib/compony.rb,
lib/compony/engine.rb,
lib/compony/intent.rb,
lib/compony/version.rb,
lib/compony/component.rb,
lib/compony/model_mixin.rb,
lib/compony/view_helpers.rb,
lib/compony/virtual_model.rb,
lib/compony/components/new.rb,
lib/compony/components/edit.rb,
lib/compony/components/form.rb,
lib/compony/components/list.rb,
lib/compony/components/show.rb,
lib/compony/request_context.rb,
lib/compony/components/index.rb,
lib/compony/controller_mixin.rb,
lib/compony/model_fields/url.rb,
lib/compony/natural_ordering.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/manage_intents_dsl.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/components/buttons/link.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/components/buttons/css_button.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, Intent, ManageIntentsDsl, MethodAccessibleHash, NaturalOrdering, RequestContext, VirtualModel

Class Method Summary collapse

Class Method Details

.authentication_before_actionObject

Getter for the name of the Rails before_action that enforces authentication.



104
105
106
# File 'lib/compony.rb', line 104

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.

Parameters:

  • authentication_before_action (Symbol)

    Name of the method you want to call for authentication



47
48
49
# File 'lib/compony.rb', line 47

def self.authentication_before_action=(authentication_before_action)
  @authentication_before_action = authentication_before_action.to_sym
end

.button_component_class(style = default_button_style) ⇒ Object

Getter for the button component class for a given style.

Parameters:

  • style (Symbol) (defaults to: default_button_style)

    Style for which the matching button component class should be returned. Defaults to default_button_style.

See Also:

  • {Compony{Compony#register_button_style}
  • {Compony{Compony#default_button_style}


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/compony.rb', line 73

def self.button_component_class(style = default_button_style)
  # Lazy initialize
  if @button_component_classes.nil?
    @button_component_classes = {
      css_button: Compony::Components::Buttons::CssButton,
      link:       Compony::Components::Buttons::Link
    }.merge(@button_component_class_names&.transform_values(&:constantize) || {})
    @button_component_classes.each_value do |button_component_class|
      unless button_component_class.is_a?(Class) && button_component_class < Compony::Component
        fail("Expected a button component class, got #{button_component_class.inspect}")
      end
    end
  end
  # Retrieval
  return @button_component_classes[style&.to_sym] || fail("Unknown button style #{style.inspect}. Use one of: #{@button_component_classes.keys.inspect}")
end

.comp_class_forObject

Given a component and a family/model, this returns the matching component class if any, or nil if the component does not exist.



141
142
143
144
145
# File 'lib/compony.rb', line 141

def self.comp_class_for(...)
  return intent(...).comp_class
rescue NameError
  return nil
end

.comp_class_for!(*args, **kwargs) ⇒ Object

Same as Compony#comp_class_for but fails if none found



150
151
152
153
154
# File 'lib/compony.rb', line 150

def self.comp_class_for!(*args, **kwargs)
  comp_class_for(*args, **kwargs) || fail(
    "No component found for #{args.inspect}, #{kwargs.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.



60
61
62
63
# File 'lib/compony.rb', line 60

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_blockObject

Getter for content_after_root_comp_block

See Also:

  • #content_after_root_comp=


116
117
118
# File 'lib/compony.rb', line 116

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.



53
54
55
56
# File 'lib/compony.rb', line 53

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_blockObject

Getter for content_before_root_comp_block

See Also:

  • #content_before_root_comp=


110
111
112
# File 'lib/compony.rb', line 110

def self.content_before_root_comp_block
  @content_before_root_comp_block
end

.default_button_styleObject

Getter for the default button style, defaults to :css_button.

See Also:

  • {Compony{Compony#default_button_style=}


92
93
94
# File 'lib/compony.rb', line 92

def self.default_button_style
  return @default_button_style || :css_button
end

.default_button_style=(default_button_style) ⇒ Object

Setter for the default button style. Defaults to :css_button.

Parameters:

  • default_button_style (Symbol)

    Name of the style that should be used as default.

See Also:

  • {Compony{Compony#default_button_style}


23
24
25
# File 'lib/compony.rb', line 23

def self.default_button_style=(default_button_style)
  @default_button_style = default_button_style
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.

Parameters:

  • model_or_family_name_or_cst (String, Symbol, ApplicationRecord)

    Either the family that contains the requested component, or an instance implementing model_name from which the family name is auto-generated. Examples: Users, 'Users', :users, User.first



165
166
167
168
169
170
171
# File 'lib/compony.rb', line 165

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

.intent(intent_or_comp_args) ⇒ Object

Pure helper to create a Compony Intent. If given an intent, will return it unchanged. Otherwise, will give all params to the intent initializer.



125
126
127
128
129
130
131
# File 'lib/compony.rb', line 125

def self.intent(intent_or_comp_args, ...)
  if intent_or_comp_args.is_a?(Intent)
    return intent_or_comp_args
  else
    return Intent.new(intent_or_comp_args, ...)
  end
end

.model_field_class_for(constant) ⇒ Object

Goes through model_field_namespaces and returns the first hit for the given constant

Parameters:

  • constant (Constant)

    The constant that is searched, e.g. RichText -> would return e.g. Compony::ModelFields::RichText



175
176
177
178
179
180
181
182
183
# File 'lib/compony.rb', line 175

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_namespacesObject

Getter for the global field namespaces.



98
99
100
# File 'lib/compony.rb', line 98

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

Parameters:

  • model_field_namespaces (Array)

    Array of strings, the names of the namespaces in the order they should be searched



34
35
36
# File 'lib/compony.rb', line 34

def self.model_field_namespaces=(model_field_namespaces)
  @model_field_namespaces = model_field_namespaces
end

.path(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil) ⇒ Object

Generates a Rails path to a component. Examples: Compony.path(:index, :users), Compony.path(:show, User.first) The first two arguments are given to create an Intent and all subsequend args and all kwargs are given to Compony::Intent#path



135
136
137
# File 'lib/compony.rb', line 135

def self.path(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil, *, **)
  intent(comp_name_or_cst_or_class, model_or_family_name_or_cst).path(*, **)
end

.register_button_style(name, button_component_class_name) ⇒ Object

Adds a button style that can be referred to when rendering an intent.

Parameters:

  • name (Symbol)

    Name of the style. If it exists already, will override the style.

  • button_component_class (String)

    String with the class name of the button component that will be instanciated to render the intent.



15
16
17
18
# File 'lib/compony.rb', line 15

def self.register_button_style(name, button_component_class_name)
  @button_component_class_names ||= {}
  @button_component_class_names[name.to_sym] = button_component_class_name
end

.root_compObject

Returns the current root component, if any



157
158
159
# File 'lib/compony.rb', line 157

def self.root_comp
  RequestStore.store[:compony_root_comp]
end