class JSON::SchemaDsl::Builder

Builders are used to build entity-structs. They handle building this raw data so it can then be given to the renderers which modify the structure to be valid json-schema.

Each type has an associated Builder that is a dynamically generated class. Since entity-structs are immutable, the builder updates the struct and keeps track of the latest version of the struct.

Entity definitions can mostly be treated as data input while most of the logic of building the entity tree resides in the builders. @todo Refactor class and remove rubocop exception rubocop:disable Metrics/ClassLength

Attributes

inner_class[RW]
inner[R]
scope[R]

Public Class Methods

[](klass) click to toggle source

@param [Class] klass A class that is a subclass of {JSON::SchemaDsl::Entity}. @return A new builder class that subclasses {JSON::SchemaDsl::Builder}

# File lib/json/schema_dsl/builder.rb, line 22
def [](klass)
  raise ArgumentError, "#{klass} is not a struct." unless klass < AstNode

  registered_builders[klass] ||= klass.builder
end
add_defaults_for(type, defaults) click to toggle source

Adds new defaults for the given type. @param [Symbol] type The type symbol for the type. Usually the name underscored and

symbolized. I.e. {JSON::SchemaDsl::Object} => `:object`.

@param [Hash<Symbol, Object>] defaults New defaults that will be merged to

the existing ones.

@return [Hash<Symbol, Hash>] @see type_defaults

# File lib/json/schema_dsl/builder.rb, line 56
def add_defaults_for(type, defaults)
  if type_defaults[type].empty?
    type_defaults[type] = type_defaults[type].merge(defaults)
  else
    type_defaults[type].merge!(defaults)
  end
end
build(name = nil, scope: nil, **attributes, &block) click to toggle source

Instantiates a new builder instance with a corresponding entity and applies the attributes and block to construct a complete entity. @param [#to_s] name The name of the new entity. This is important for the entity

to be added to properties later. Usually is the name of a property or the pattern
for a pattern property.

@param [Object] scope The scope will be used as a fallback to evaluate the block.

If there are any methods that the block does not understand, the scope will
be called instead.

@param [Hash] attributes The initial attributes that the entity will start with

before the block is applied.

@param [Proc] block Will be evaluated in the context of the builder. Should contain

setter methods.
# File lib/json/schema_dsl/builder.rb, line 77
def build(name = nil, scope: nil, **attributes, &block)
  type     = (attributes[:type] || inner_class.infer_type)&.to_sym
  defaults = ::JSON::SchemaDsl::Builder
             .type_defaults[type].merge(name: name, type: type)
  builder  = new(inner_class.new(defaults), scope: scope)
  Docile.dsl_eval(builder, &config_block(attributes, &block))
end
class_name() click to toggle source

nodoc

# File lib/json/schema_dsl/builder.rb, line 91
def class_name
  name || inner_class.name + 'Builder'
end
define_builder(klass) click to toggle source

@param [Class] klass A class that is a subclass of {JSON::SchemaDsl::Entity}. @return A new builder class that subclasses {JSON::SchemaDsl::Builder} @see []

# File lib/json/schema_dsl/builder.rb, line 109
def define_builder(klass)
  Class.new(self) do
    self.inner_class = klass
    klass.schema.keys.map(&:name).each do |name|
      define_method(name) do |*args, **opts, &block|
        set(name, *args, **opts, &block)
      end
    end
  end
end
define_builder_method(type) click to toggle source

Defines a new method for the builder instance that mirrors the dsl method

for the given type.

@param [Class] type A class that is a subclass of {JSON::SchemaDsl::Entity}.

# File lib/json/schema_dsl/builder.rb, line 98
def define_builder_method(type)
  type_param = type.type_method_name || 'entity'
  define_method(type_param) do |name = nil, **attributes, &block|
    new_child = build_struct(type, name, **attributes, &block)
    add_child(new_child)
  end
end
inspect() click to toggle source

nodoc

# File lib/json/schema_dsl/builder.rb, line 86
def inspect
  "#<#{class_name} inner_class=#{inner_class}>"
end
new(inner, scope: nil) click to toggle source

@param [JSON::SchemaDsl::Entity] inner The struct that the builder is supposed

to update and build up.

@param [Object] scope The scope is used for as a fallback for helper methods. @see JSON::SchemaDsl::Builder.build

# File lib/json/schema_dsl/builder.rb, line 139
def initialize(inner, scope: nil)
  @inner = inner
  @scope = scope
end
registered_builders() click to toggle source

@return [Array<JSON::SchemaDsl::Builder>] All builders that have been

registered so far. Usually builders get automatically registered when
the associated type is registered.
# File lib/json/schema_dsl/builder.rb, line 31
def registered_builders
  @registered_builders ||= {}
end
reset_type_defaults!() click to toggle source

Clears the registered type defaults and returns an empty hash. @return [Hash<Symbol, Hash>] @see type_defaults

# File lib/json/schema_dsl/builder.rb, line 45
def reset_type_defaults!
  type_defaults.clear
end
type_defaults() click to toggle source

@return [Hash<Symbol, Hash>] Defaults that are applied when a new struct of a

given type is contsructed. The type symbol is the key and the defaults the value
of this hash.
# File lib/json/schema_dsl/builder.rb, line 38
def type_defaults
  @type_defaults ||= Hash.new { {} }
end

Private Class Methods

config_block(attributes, &block) click to toggle source

Combines a set of attributes and a block into a single proc.

# File lib/json/schema_dsl/builder.rb, line 123
def config_block(attributes, &block)
  proc do
    attributes.each { |k, v| send(k, v) }
    instance_exec(&block) if block_given?
  end
end

Public Instance Methods

render() click to toggle source

Renders the given tree structure into a hash. Note that this hash still has symbol keys.

The scope used for the render is the same as the builder.

@see JSON::SchemaDsl::Renderer#render

# File lib/json/schema_dsl/builder.rb, line 147
def render
  ::JSON::SchemaDsl::Renderer.new(inner, scope).render
end

Private Instance Methods

add_child(child) click to toggle source
# File lib/json/schema_dsl/builder.rb, line 201
def add_child(child)
  children(children | [child])
  child
end
build_struct(type, name = nil, **attributes, &block) click to toggle source
# File lib/json/schema_dsl/builder.rb, line 162
def build_struct(type, name = nil, **attributes, &block)
  builder = self.class[type || attributes[:type].constantize]
  builder.build(name, **attributes, scope: scope, &block)
end
extract_args(name, args, opts, &block) click to toggle source
# File lib/json/schema_dsl/builder.rb, line 193
def extract_args(name, args, opts, &block)
  if block.present? || !inner.class.has_attribute?(name) || opts[:type].present?
    return build_struct(Object, **opts, &block)
  end

  args.presence || opts.presence
end
inspect() click to toggle source
# File lib/json/schema_dsl/builder.rb, line 182
def inspect
  "#<#{self.class.class_name} \n  scope = #{scope}\n  inner = #{inner}> "
end
method_missing(meth, *args, &block) click to toggle source
Calls superclass method
# File lib/json/schema_dsl/builder.rb, line 167
def method_missing(meth, *args, &block)
  return super unless scope&.respond_to?(meth, true)

  maybe_child = scope.send(meth, *args, &block)
  maybe_child.respond_to?(:render) &&
    add_child(maybe_child)
  maybe_child
end
respond_to_missing?(meth, priv) click to toggle source
Calls superclass method
# File lib/json/schema_dsl/builder.rb, line 176
def respond_to_missing?(meth, priv)
  return super unless scope

  scope.respond_to?(meth, priv)
end
set(name, *args, **opts, &block) click to toggle source
# File lib/json/schema_dsl/builder.rb, line 186
def set(name, *args, **opts, &block)
  args = extract_args(name, args, opts, &block)
  return inner.send(name) unless args

  @inner = update(name, args)
end
update(type, *args) click to toggle source
# File lib/json/schema_dsl/builder.rb, line 153
def update(type, *args)
  args = args.first if args.count == 1 && args.is_a?(::Array)
  @inner = if args.is_a?(::Array)
             inner.update(type, *args)
           else
             inner.update(type, args)
           end
end