Module: GraphQL::Define::InstanceDefinable

Included in:
Argument, BaseType, GraphQL::Directive, EnumType::EnumValue, Field, Relay::Mutation, Schema
Defined in:
lib/graphql/define/instance_definable.rb

Overview

This module provides the .define { ... } API for BaseType, Field and others.

Calling .accepts_definitions(...) creates:

  • a keyword to the .define method
  • a helper method in the .define { ... } block

The .define { ... } block will be called lazily. To be sure it has been called, use the private method #ensure_defined. That will call the definition block if it hasn't been called already.

The goals are:

  • Minimal overhead in consuming classes
  • Independence between consuming classes
  • Extendable by third-party libraries without monkey-patching or other nastiness

Examples:

Make a class definable

class Car
  include GraphQL::Define::InstanceDefinable
  attr_accessor :make, :model, :doors
  accepts_definitions(
    # These attrs will be defined with plain setters, `{attr}=`
    :make, :model,
    # This attr has a custom definition which applies the config to the target
    doors: ->(car, doors_count) { doors_count.times { car.doors << Door.new } }
  )
  ensure_defined(:make, :model, :doors)

  def initialize
    @doors = []
  end
end

class Door; end;

# Create an instance with `.define`:
subaru_baja = Car.define do
  make "Subaru"
  model "Baja"
  doors 4
end

# The custom proc was applied:
subaru_baja.doors #=> [<Door>, <Door>, <Door>, <Door>]

Extending the definition of a class

# Add some definitions:
Car.accepts_definitions(all_wheel_drive: GraphQL::Define.(:all_wheel_drive))

# Use it in a definition
subaru_baja = Car.define do
  # ...
  all_wheel_drive true
end

# Access it from metadata
subaru_baja.[:all_wheel_drive] # => true

Extending the definition of a class via a plugin

# A plugin is any object that responds to `.use(definition)`
module SubaruCar
  extend self

  def use(defn)
    # `defn` has the same methods as within `.define { ... }` block
    defn.make "Subaru"
    defn.doors 4
  end
end

# Use the plugin within a `.define { ... }` block
subaru_baja = Car.define do
  use SubaruCar
  model 'Baja'
end

subaru_baja.make # => "Subaru"
subaru_baja.doors # => [<Door>, <Door>, <Door>, <Door>]

Making a copy with an extended definition

# Create an instance with `.define`:
subaru_baja = Car.define do
  make "Subaru"
  model "Baja"
  doors 4
end

# Then extend it with `#redefine`
two_door_baja = subaru_baja.redefine do
  doors 2
end

Defined Under Namespace

Modules: ClassMethods Classes: AssignAttribute, AssignMetadataKey, Definition

Instance Method Summary collapse

Instance Method Details

#define(**kwargs, &block) ⇒ void

This method returns an undefined value.

Mutate this instance using functions from its definitions. Keywords or helpers in the block correspond to keys given to accepts_definitions.

Note that the block is not called right away -- instead, it's deferred until one of the defined fields is needed.



116
117
118
119
120
121
122
# File 'lib/graphql/define/instance_definable.rb', line 116

def define(**kwargs, &block)
  # make sure the previous definition_proc was executed:
  ensure_defined
  stash_dependent_methods
  @pending_definition = Definition.new(kwargs, block)
  nil
end

#initialize_copy(other) ⇒ Object



134
135
136
137
# File 'lib/graphql/define/instance_definable.rb', line 134

def initialize_copy(other)
  super
  @metadata = other..dup
end

#metadataHash<Object, Object>

metadata can store arbitrary key-values with an object.

Returns:

  • (Hash<Object, Object>)

    Hash for user-defined storage



106
107
108
# File 'lib/graphql/define/instance_definable.rb', line 106

def 
  @metadata ||= {}
end

#redefine(**kwargs, &block) ⇒ InstanceDefinable

Shallow-copy this object, then apply new definitions to the copy.

Returns:

See Also:

  • for arguments


127
128
129
130
131
132
# File 'lib/graphql/define/instance_definable.rb', line 127

def redefine(**kwargs, &block)
  ensure_defined
  new_inst = self.dup
  new_inst.define(**kwargs, &block)
  new_inst
end