Class: Attributor::DSLCompiler

Inherits:
Object
  • Object
show all
Defined in:
lib/attributor/dsl_compiler.rb

Overview

The reference option for an attribute is passed if a block is given

Direct Known Subclasses

HashDSLCompiler

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, **options) ⇒ DSLCompiler

Returns a new instance of DSLCompiler.



15
16
17
18
# File 'lib/attributor/dsl_compiler.rb', line 15

def initialize(target, **options)
  @target = target
  @options = options
end

Instance Attribute Details

#optionsObject

Returns the value of attribute options.



13
14
15
# File 'lib/attributor/dsl_compiler.rb', line 13

def options
  @options
end

#targetObject

Returns the value of attribute target.



13
14
15
# File 'lib/attributor/dsl_compiler.rb', line 13

def target
  @target
end

Instance Method Details

#attribute(name, attr_type = nil, **opts, &block) ⇒ Object



34
35
36
37
# File 'lib/attributor/dsl_compiler.rb', line 34

def attribute(name, attr_type = nil, **opts, &block)
  raise AttributorException, "Attribute names must be symbols, got: #{name.inspect}" unless name.is_a? ::Symbol
  target.attributes[name] = define(name, attr_type, **opts, &block)
end

#attributesObject



26
27
28
29
30
31
32
# File 'lib/attributor/dsl_compiler.rb', line 26

def attributes
  if target.respond_to?(:attributes)
    target.attributes
  else
    target.keys
  end
end

#define(name, type, opts, &block) ⇒ Object #define(name, opts, &block) ⇒ Object

Creates an Attributor:Attribute with given definition.

Overloads:

  • #define(name, type, opts, &block) ⇒ Object

    With an explicit type.

    Examples:

    attribute :email, String, example: Randgen.email

    Parameters:

    • name (symbol)

      describe name param

    • type (Attributor::Type)

      describe type param

    • opts (Hash)

      describe opts param

    • block (Block)

      describe block param

  • #define(name, opts, &block) ⇒ Object

    Assume a type of Attributor::Struct

    Examples:

    attribute :address do
      attribute :number, String
      attribute :street, String
      attribute :city, String
      attribute :state, String
    end

    Parameters:

    • name (symbol)

      describe name param

    • opts (Hash)

      describe opts param

    • block (Block)

      describe block param



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/attributor/dsl_compiler.rb', line 80

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

  # determine inherited type (giving preference to the direct attribute options)
  inherited_type = opts[:reference]
  unless inherited_type
    reference = options[:reference]
    if reference && reference.respond_to?(:attributes) && reference.attributes.key?(name)
      inherited_attribute = reference.attributes[name]
      opts = inherited_attribute.options.merge(opts) unless attr_type
      inherited_type = inherited_attribute.type
      opts[:reference] = inherited_type if block_given?
    end
  end

  # determine attribute type to use
  if attr_type.nil?
    if block_given?
      # Don't inherit explicit examples if we've redefined the structure 
      # (but preserve the direct example if given here)
      opts.delete :example unless  example_given
      attr_type = if inherited_type && inherited_type < Attributor::Collection
                    # override the reference to be the member_attribute's type for collections
                    opts[:reference] = inherited_type.member_attribute.type
                    Attributor::Collection.of(Struct)
                  else
                    Attributor::Struct
                  end
    elsif inherited_type
      attr_type = inherited_type
    else
      raise AttributorException, "type for attribute with name: #{name} could not be determined"
    end
  end

  Attributor::Attribute.new(attr_type, opts, &block)
end

#extra(name, attr_type = nil, **opts, &block) ⇒ Object



46
47
48
49
50
51
52
53
54
55
# File 'lib/attributor/dsl_compiler.rb', line 46

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) ⇒ Object



39
40
41
42
43
44
# File 'lib/attributor/dsl_compiler.rb', line 39

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) ⇒ Object



20
21
22
23
24
# File 'lib/attributor/dsl_compiler.rb', line 20

def parse(*blocks)
  blocks.push(Proc.new) if block_given?
  blocks.each { |block| instance_eval(&block) }
  self
end