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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, **options) ⇒ DSLCompiler

Returns a new instance of DSLCompiler


17
18
19
20
# File 'lib/attributor/dsl_compiler.rb', line 17

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

Instance Attribute Details

#optionsObject

Returns the value of attribute options


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

def options
  @options
end

#targetObject

Returns the value of attribute target


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

def target
  @target
end

Instance Method Details

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


36
37
38
39
# File 'lib/attributor/dsl_compiler.rb', line 36

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

#attributesObject


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

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: /[: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


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
# File 'lib/attributor/dsl_compiler.rb', line 82

def define(name, attr_type=nil, **opts, &block)
  # 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 attribute
  inherited_attribute = nil      
  if (reference = self.options[:reference])
    if (inherited_attribute = reference.attributes[name])
      opts = inherited_attribute.options.merge(opts) unless attr_type
      opts[:reference] = inherited_attribute.type if block_given?
    end
  end

  # determine attribute type to use
  if attr_type.nil?
    if block_given?
      attr_type = if inherited_attribute && inherited_attribute.type < Attributor::Collection
        # override the reference to be the member_attribute's type for collections
        opts[:reference] = inherited_attribute.type.member_attribute.type
        Attributor::Collection.of(Struct)
      else
        Attributor::Struct
      end
    elsif inherited_attribute
      attr_type = inherited_attribute.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


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

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


41
42
43
44
45
46
# File 'lib/attributor/dsl_compiler.rb', line 41

def key(name, attr_type=nil, **opts, &block)
  unless name.kind_of?(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


22
23
24
25
26
# File 'lib/attributor/dsl_compiler.rb', line 22

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