class Attributor::DSLCompiler
The reference option for an attribute is passed if a block is given
Attributes
options[RW]
target[RW]
Public Class Methods
new(target, **options)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 16 def initialize(target, **options) @target = target @options = options end
Public Instance Methods
add_reference_to_block(name, opts)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 156 def add_reference_to_block(name, opts) base_reference = options[:reference] if opts[:reference] # Direct reference specified in the attribute, just pass it to the block {reference: opts[:reference]} elsif( base_reference && base_reference.respond_to?(:attributes) && base_reference.attributes.key?(name)) selected_type = base_reference.attributes[name].type selected_type = selected_type.member_attribute.type if selected_type < Attributor::Collection {reference: selected_type} else {} end end
attribute(name, attr_type = nil, **opts, &block)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 35 def attribute(name, attr_type = nil, **opts, &block) raise AttributorException, "Attribute names must be symbols, got: #{name.inspect}" unless name.is_a? ::Symbol if opts[:reference] raise AttributorException, ":reference option can only be used when defining blocks" unless block_given? if opts[:reference] < Attributor::Collection err = ":reference option cannot be a collection. It must be a concrete Struct-like type containing the attribute #{name} you are defining.\n" location_file, location_line = block.source_location err += "The place where you are trying to define the attribute is here:\n#{location_file} line #{location_line}\n#{block.source}\n" raise AttributorException, err end end target.attributes[name] = define(name, attr_type, **opts, &block) end
attributes()
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 27 def attributes if target.respond_to?(:attributes) target.attributes else target.keys end end
define(name, attr_type = nil, **opts, &block)
click to toggle source
Creates an Attributor:Attribute with given definition.
@overload define(name, type, opts, &block)
With an explicit type. @param [symbol] name describe name param @param [Attributor::Type] type describe type param @param [Hash] opts describe opts param @param [Block] block describe block param @example attribute :email, String, example: Randgen.email
@overload define(name, opts, &block)
Assume a type of Attributor::Struct @param [symbol] name describe name param @param [Hash] opts describe opts param @param [Block] block describe block param @example attribute :address do attribute :number, String attribute :street, String attribute :city, String attribute :state, String end
@api semiprivate
# File lib/attributor/dsl_compiler.rb, line 90 def define(name, attr_type = nil, **opts, &block) example_given = opts.key? :example # add to existing attribute if present if (existing_attribute = attributes[name]) if existing_attribute.attributes existing_attribute.type.attributes(&block) return existing_attribute end end if attr_type.nil? if block_given? final_type, carried_options = resolve_type_for_block(name, **opts, &block) else final_type, carried_options = resolve_type_for_no_block(name, **opts) end else final_type = attr_type carried_options = {} end final_opts = opts.dup final_opts.delete(:reference) # Possibly add a reference for block definitions (No reference for leaves) final_opts.merge!(add_reference_to_block(name, opts)) if block_given? final_opts = carried_options.merge(final_opts) Attributor::Attribute.new(final_type, final_opts, &block) end
extra(name, attr_type = nil, **opts, &block)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 56 def extra(name, attr_type = nil, **opts, &block) if attr_type.nil? attr_type = Attributor::Hash.of(key: target.key_type, value: target.value_type) end target.extra_keys = name target.options[:allow_extra] = true opts[:default] ||= {} attr_type.options[:allow_extra] = true key(name, attr_type, **opts, &block) end
key(name, attr_type = nil, **opts, &block)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 49 def key(name, attr_type = nil, **opts, &block) unless name.is_a?(options.fetch(:key_type, Attributor::Object).native_type) raise "Invalid key: #{name.inspect}, must be instance of #{options[:key_type].native_type.name}" end target.keys[name] = define(name, attr_type, **opts, &block) end
parse(*blocks)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 21 def parse(*blocks) blocks.push(Proc.new) if block_given? blocks.each { |block| instance_eval(&block) } self end
resolve_type_for_block(name, **opts)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 121 def resolve_type_for_block(name, **opts) resolved_type = nil carried_options = {} ref = options[:reference] if ref && ref.respond_to?(:attributes) && ref.attributes.key?(name) type_from_ref = ref.attributes[name]&.type resolved_type = type_from_ref < Attributor::Collection ? Attributor::Struct[] : Attributor::Struct else # Type for attribute with given name could not be determined from reference...or ther is not refrence: defaulting to Struct" resolved_type = Attributor::Struct end [resolved_type, carried_options] end
resolve_type_for_no_block(name, **opts)
click to toggle source
# File lib/attributor/dsl_compiler.rb, line 135 def resolve_type_for_no_block(name, **opts) resolved_type = nil carried_options = {} ref = options[:reference] if ref && ref.respond_to?(:attributes) && ref.attributes.key?(name) resolved_type = ref.attributes[name].type carried_options = ref.attributes[name].options else message = "Type for attribute with name: #{name} could not be determined.\n" if ref message += "You are defining '#{name}' without a type, and the passed in :reference type (#{ref}) does not have an attribute named '#{name}'.\n" \ else message += "You are defining '#{name}' without a type, and there is no :reference type to infer it from (Did you forget to add the type?).\n" \ end message += "\nIf you are omiting a type thinking that would be inherited from the reference, make sure the right one is passed in," \ ", which has a #{name} defined, otherwise simply specify the type of the attribute you want.\n" raise AttributorException, message end [resolved_type, carried_options] end