Module: Axn::Mountable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/axn/mountable.rb,
lib/axn/exceptions.rb,
lib/axn/mountable/descriptor.rb,
lib/axn/mountable/helpers/mounter.rb,
lib/axn/mountable/inherit_profiles.rb,
lib/axn/mountable/helpers/validator.rb,
lib/axn/mountable/mounting_strategies.rb,
lib/axn/mountable/helpers/class_builder.rb,
lib/axn/mountable/mounting_strategies/axn.rb,
lib/axn/mountable/mounting_strategies/step.rb,
lib/axn/mountable/helpers/namespace_manager.rb,
lib/axn/mountable/mounting_strategies/_base.rb,
lib/axn/mountable/mounting_strategies/method.rb
Overview
Mountable provides functionality for mounting actions to classes
## Inheritance Behavior
Mounted actions inherit features from their target class in different ways depending on the mounting strategy. Each strategy has sensible defaults, but you can customize inheritance behavior using the ‘inherit` parameter.
### Default Inheritance Modes
-
‘mount_axn` and `mount_axn_method`: `:lifecycle` - Inherits hooks, callbacks, messages, and async config (but not fields)
-
‘step`: `:none` - Completely independent to avoid conflicts
### Inheritance Profiles
-
‘:lifecycle` - Inherits everything except fields (hooks, callbacks, messages, async config)
-
‘:async_only` - Only inherits async configuration
-
‘:none` - Completely standalone with no inheritance
You can also use a hash for granular control:
`inherit: { fields: false, hooks: true, callbacks: false, messages: true, async: true }`
Available hash keys: ‘:fields`, `:hooks`, `:callbacks`, `:messages`, `:async`
Defined Under Namespace
Modules: Helpers, InheritProfiles Classes: Descriptor, DuplicateMountingTypeError, MountingError, MountingStrategies, MountingTypeNotFound
Class Method Summary collapse
Class Method Details
.included(base) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/axn/mountable.rb', line 68 def self.included(base) unless base.is_a?(Class) # Module host: plain accessor — no class_attribute (Class-only) or inherited hook needed. base.instance_variable_set(:@_mounted_axn_descriptors, []) base.define_singleton_method(:_mounted_axn_descriptors) { @_mounted_axn_descriptors ||= [] } base.define_singleton_method(:_mounted_axn_descriptors=) { |val| @_mounted_axn_descriptors = val } end if base.is_a?(Class) base.class_eval do class_attribute :_mounted_axn_descriptors, default: [] # Eagerly create action class constants for inherited descriptors # (e.g. allow TeamsharesAPI::Company::Axns::Get.call to work *without* having to # call TeamsharesAPI::Company.get! first) def self.inherited(subclass) super # Only process if we have inherited descriptors from parent return unless _mounted_axn_descriptors.any? # Skip if subclass doesn't respond to _mounted_axn_descriptors # This prevents recursion when creating action classes that inherit from target return unless subclass.respond_to?(:_mounted_axn_descriptors) # Skip if we're currently creating an action class (prevent infinite recursion) # This is necessary because Axn::Factory.build creates classes that inherit from # Axn (which includes Axn::Mountable), triggering inherited callbacks during # action class creation. superclass = subclass.superclass creating_for = superclass&.instance_variable_get(:@_axn_creating_action_class_for) return if creating_for # Skip if this is an action class being created (they're in the Axns namespace) # Action classes have names like "ParentClass::Axns::ActionName" subclass_name = subclass.name return if subclass_name&.include?("::Axns::") # Eagerly create constants for all inherited descriptors # mounted_axn_for will ensure namespace exists and create the constant # If a child overrides, the new descriptor will replace the constant _mounted_axn_descriptors.each do |descriptor| # This will create the constant if it doesn't exist descriptor.mounted_axn_for(target: subclass) # Also define namespace methods on the child's namespace # This ensures TeamsharesAPI::Company::Axns.get works even though # the descriptor was originally mounted on TeamsharesAPI::Base # We use define_namespace_methods instead of mount_to_namespace to # avoid re-registering the constant (which is already created above) descriptor.mount_strategy.define_namespace_methods(descriptor:, target: subclass) end end end end MountingStrategies.all.each do |(_name, klass)| base.extend klass::DSL if klass.const_defined?(:DSL) end end |