Class: DeclareSchema::Model::DeferredFieldSpec

Inherits:
Object
  • Object
show all
Defined in:
lib/declare_schema/model/deferred_field_spec.rb

Overview

A placeholder for a FieldSpec whose final shape can’t be computed at field- declaration time. The only producer today is ‘belongs_to` between two declare_schema models: we cannot touch `reflection.klass` while declaring the FK without risking a model-load cycle, so we stash an eager default-typed FieldSpec along with a block that knows how to mirror the parent’s PK once all models have been eager-loaded.

The migrator calls #resolve on every value in ‘field_specs` at the start of migration generation (see `Migrator#generate`); for plain FieldSpecs `#resolve` is a no-op returning self, while for instances of this class it invokes the resolver block with the default spec and returns the produced FieldSpec.

Instance Method Summary collapse

Constructor Details

#initialize(default_spec) {|default_spec| ... } ⇒ DeferredFieldSpec

Returns a new instance of DeferredFieldSpec.

Parameters:

  • default_spec (FieldSpec)

    the eager placeholder spec

Yield Parameters:

Yield Returns:



21
22
23
24
25
# File 'lib/declare_schema/model/deferred_field_spec.rb', line 21

def initialize(default_spec, &resolver)
  resolver or raise ArgumentError, "DeferredFieldSpec requires a resolver block"
  @default_spec = default_spec
  @resolver = resolver
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **kwargs) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/declare_schema/model/deferred_field_spec.rb', line 41

def method_missing(name, *args, **kwargs, &)
  if resolve.respond_to?(name)
    resolve.public_send(name, *args, **kwargs, &)
  else
    super
  end
end

Instance Method Details

#resolveFieldSpec

Resolve and memoize the produced FieldSpec. Memoization matters because application code can hit several FieldSpec accessors per request (e.g. ModelReport reads ‘.options`, ApplicationModel reads `.limit`); without it each one would re-run the resolver and re-touch `reflection.klass`.

Returns:



33
34
35
# File 'lib/declare_schema/model/deferred_field_spec.rb', line 33

def resolve
  @resolved ||= @resolver.call(@default_spec)
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Returns:



37
38
39
# File 'lib/declare_schema/model/deferred_field_spec.rb', line 37

def respond_to_missing?(name, include_private = false)
  resolve.respond_to?(name, include_private) || super
end