class Paradocs::Schema

Attributes

default_field_policies[R]
definitions[R]
environment[RW]
expansions[R]
ignored_field_keys[R]
options[R]
structure_builder[R]
subschemes[R]

Public Class Methods

new(options={}, &block) click to toggle source
# File lib/paradocs/schema.rb, line 11
def initialize(options={}, &block)
  @options = options
  @fields = {}
  @subschemes = {}
  @definitions = []
  @definitions << block if block_given?
  @default_field_policies = []
  @ignored_field_keys = []
  @expansions = {}
  @structure_builder = Paradocs::Extensions::Structure.new(self)
end

Public Instance Methods

clone() click to toggle source
# File lib/paradocs/schema.rb, line 90
def clone
  instance = self.class.new(options)
  copy_into instance
end
coerce(val, _, context) click to toggle source
# File lib/paradocs/schema.rb, line 153
def coerce(val, _, context)
  flush!
  if val.is_a?(Array)
    val.map.with_index do |v, idx|
      subcontext = context.sub(idx)
      out = coerce_one(v, subcontext)
      resolve_expansions(v, out, subcontext)
    end
  else
    out = coerce_one(val, context)
    resolve_expansions(val, out, context)
  end
end
copy_into(instance) click to toggle source
# File lib/paradocs/schema.rb, line 102
def copy_into(instance)
  instance.policy(*default_field_policies) if default_field_policies.any?

  definitions.each do |d|
    instance.definitions << d
  end

  subschemes.each { |name, subsc| instance.subschema(name, subsc) }

  instance.ignore *ignored_field_keys
  instance
end
eligible?(value, key, payload) click to toggle source
# File lib/paradocs/schema.rb, line 141
def eligible?(value, key, payload)
  payload.key? key
end
example_payloads(&block) click to toggle source
# File lib/paradocs/schema.rb, line 38
def example_payloads(&block)
  @example_payloads ||= Paradocs::Extensions::PayloadBuilder.new(self).build!(&block)
end
expand(exp, &block) click to toggle source
# File lib/paradocs/schema.rb, line 129
def expand(exp, &block)
  expansions[exp] = block
  self
end
field(field_or_key) click to toggle source
# File lib/paradocs/schema.rb, line 115
def field(field_or_key)
  f, key = if field_or_key.kind_of?(Field)
    [field_or_key, field_or_key.key]
  else
    [Field.new(field_or_key), field_or_key.to_sym]
  end

  if ignored_field_keys.include?(f.key)
    f
  else
    @fields[key] = apply_default_field_policies_to(f)
  end
end
fields() click to toggle source
# File lib/paradocs/schema.rb, line 69
def fields
  apply!
  @fields
end
flush!() click to toggle source
# File lib/paradocs/schema.rb, line 167
def flush!
  @fields = {}
  @applied = false
end
ignore(*field_keys, &block) click to toggle source
# File lib/paradocs/schema.rb, line 81
def ignore(*field_keys, &block)
  @ignored_field_keys += field_keys
  @ignored_field_keys.uniq!

  definitions << block if block_given?

  self
end
merge(other_schema) click to toggle source
# File lib/paradocs/schema.rb, line 95
def merge(other_schema)
  instance = self.class.new(options.merge(other_schema.options))

  copy_into(instance)
  other_schema.copy_into(instance)
end
meta_data() click to toggle source
# File lib/paradocs/schema.rb, line 149
def meta_data
  {}
end
mutation_by!(key, &block) click to toggle source
# File lib/paradocs/schema.rb, line 27
def mutation_by!(key, &block)
  f = @fields.keys.include?(key) ? @fields[key] : field(key).transparent
  f.mutates_schema!(&block)
end
policy(*names, &block) click to toggle source
# File lib/paradocs/schema.rb, line 74
def policy(*names, &block)
  @default_field_policies = names
  definitions << block if block_given?

  self
end
resolve(payload, environment={}) click to toggle source
# File lib/paradocs/schema.rb, line 134
def resolve(payload, environment={})
  @environment = environment
  context = Context.new(nil, Top.new, @environment, subschemes)
  output = coerce(payload, nil, context)
  Results.new(output, context.errors, @environment)
end
schema() click to toggle source
# File lib/paradocs/schema.rb, line 23
def schema
  self
end
structure(ignore_transparent: true) click to toggle source
# File lib/paradocs/schema.rb, line 32
def structure(ignore_transparent: true)
  flush!
  structure_builder.ignore_transparent = ignore_transparent
  structure_builder
end
subschema(*args, &block) click to toggle source
# File lib/paradocs/schema.rb, line 53
def subschema(*args, &block)
  options = args.last.is_a?(Hash) ? args.last : {}
  name = args.first.is_a?(Symbol) ? args.shift : Paradocs.config.default_schema_name
  current_schema = subschemes.fetch(name) { self.class.new }
  new_schema = if block_given?
    sc = self.class.new(options)
    sc.definitions << block
    sc
  elsif args.first.is_a?(self.class)
    args.first
  else
    self.class.new(options)
  end
  subschemes[name] = current_schema.merge(new_schema)
end
valid?(*_) click to toggle source
# File lib/paradocs/schema.rb, line 145
def valid?(*_)
  true
end
visit(meta_key = nil, &visitor) click to toggle source
# File lib/paradocs/schema.rb, line 47
def visit(meta_key = nil, &visitor)
  fields.each_with_object({}) do |(_, field), m|
    m[field.key] = field.visit(meta_key, &visitor)
  end
end
walk(meta_key = nil, &visitor) click to toggle source
# File lib/paradocs/schema.rb, line 42
def walk(meta_key = nil, &visitor)
  r = visit(meta_key, &visitor)
  Results.new(r, {}, {})
end

Private Instance Methods

apply!() click to toggle source
# File lib/paradocs/schema.rb, line 228
def apply!
  return if @applied
  definitions.each do |d|
    self.instance_exec(options, &d)
  end
  @applied = true
end
apply_default_field_policies_to(field) click to toggle source
# File lib/paradocs/schema.rb, line 224
def apply_default_field_policies_to(field)
  default_field_policies.reduce(field) {|f, policy_name| f.policy(policy_name) }
end
coerce_one(val, context, flds: fields) click to toggle source
# File lib/paradocs/schema.rb, line 180
def coerce_one(val, context, flds: fields)
  invoke_subschemes!(val, context, flds: flds)
  flds.each_with_object({}) do |(_, field), m|
    r = field.resolve(val, context.sub(field.key))
    key = field.meta_data[:alias] || field.key
    m[key] = r.value if r.eligible?
  end
end
invoke_subschemes!(payload, context, flds: fields) click to toggle source
# File lib/paradocs/schema.rb, line 189
def invoke_subschemes!(payload, context, flds: fields)
  invoked_any = false
  # recoursive definitions call depending on payload
  flds.clone.each_pair do |_, field|
    next unless field.expects_mutation?
    subschema_name = field.subschema_for_mutation(payload, context.environment)
    subschema = subschemes[subschema_name] || context.subschema(subschema_name)
    next unless subschema # or may be raise error?
    subschema.definitions.each { |block| self.instance_exec(&block) }
    invoked_any = true
  end
  # if definitions are applied new subschemes may appear, apply them until they end
  invoke_subschemes!(payload, context, flds: fields) if invoked_any
end
resolve_expansions(payload, into, context) click to toggle source
# File lib/paradocs/schema.rb, line 210
def resolve_expansions(payload, into, context)
  expansions.each do |exp, block|
    payload.each do |key, value|
      match = exp.match(key.to_s)
      next unless match
      fld = MatchContext.new.instance_exec(match, &block)
      next unless fld
      into.update(coerce_one({fld.key => value}, context, flds: {fld.key => apply_default_field_policies_to(fld)}))
    end
  end

  into
end