Module: Familia::Horreum::RelatedFieldsManagement

Included in:
DefinitionMethods, ManagementMethods
Defined in:
lib/familia/horreum/related_fields.rb

Overview

RelatedFieldsManagement - Class-level methods for defining DataType relationships

This module uses metaprogramming to dynamically create field definition methods that generate both class-level and instance-level accessor methods for DataTypes (e.g., list, set, zset, hashkey, string).

When included in a class via ManagementMethods, it provides class methods like:

  • Customer.list :recent_orders # defines class method for class-level list
  • customer.recent_orders # creates instance method returning list instance

Key metaprogramming features:

  • Dynamically defines DSL methods for each Database type (e.g., set, list, hashkey)
  • Each DSL method creates corresponding instance/class accessor methods
  • Provides query methods for checking relation types

Usage: Include this module in classes that need DataType management Call setup_related_fields_definition_methods to initialize the feature

Defined Under Namespace

Modules: RelatedFieldsAccessors

Instance Method Summary collapse

Instance Method Details

Creates a class-level relation

Raises:

  • (ArgumentError)


208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/familia/horreum/related_fields.rb', line 208

def attach_class_related_field(name, klass, opts)
  Familia.trace :attach_class_related_field, "#{name} #{klass}", opts if Familia.debug?
  raise ArgumentError, 'Name is blank (klass)' if name.to_s.empty?

  name = name.to_s.to_sym
  opts = opts.nil? ? {} : opts.clone
  opts[:parent] = self unless opts.key?(:parent)

  class_related_fields[name] = RelatedFieldDefinition.new(name, klass, opts)

  # An accessor method created in the metaclass will
  # access the instance variables for this class.
  singleton_class.attr_reader name

  define_singleton_method :"#{name}=" do |v|
    send(name).replace v
  end
  define_singleton_method :"#{name}?" do
    !send(name).empty?
  end

  related_field = klass.new name, opts
  related_field.freeze
  instance_variable_set(:"@#{name}", related_field)

  class_related_fields[name]
end

Creates an instance-level relation

Raises:

  • (ArgumentError)


166
167
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
199
200
201
202
203
204
205
# File 'lib/familia/horreum/related_fields.rb', line 166

def attach_instance_related_field(name, klass, opts)
  Familia.trace :attach_instance_related_field, name, klass, opts if Familia.debug?
  raise ArgumentError, "Name is blank (#{klass})" if name.to_s.empty?

  name = name.to_s.to_sym
  opts ||= {}

  related_fields[name] = RelatedFieldDefinition.new(name, klass, opts)

  # Create lazy-initializing accessor that calls initialize_relatives if needed
  define_method name do
    ivar = :"@#{name}"
    value = instance_variable_get(ivar)

    # If nil and we haven't initialized relatives, do it now
    # Check singleton class to avoid polluting instance variables
    if value.nil? && !singleton_class.instance_variable_defined?(:"@relatives_initialized")
      initialize_relatives
      value = instance_variable_get(ivar)
    end

    # If still nil after lazy initialization attempt, raise helpful error
    # Only raise if we tried to initialize but it's still nil
    if value.nil? && singleton_class.instance_variable_defined?(:"@relatives_initialized")
      raise "#{self.class}##{name} is nil. Did you override initialize without calling super? " \
            "(Field is nil after initialization attempt)"
    end

    value
  end

  define_method :"#{name}=" do |val|
    send(name).replace val
  end
  define_method :"#{name}?" do
    !send(name).empty?
  end

  related_fields[name]
end