Module: Acfs::Resource::Attributes

Extended by:
ActiveSupport::Concern
Includes:
ActiveModel::AttributeMethods
Included in:
Acfs::Resource
Defined in:
lib/acfs/resource/attributes.rb,
lib/acfs/resource/attributes/base.rb,
lib/acfs/resource/attributes/dict.rb,
lib/acfs/resource/attributes/list.rb,
lib/acfs/resource/attributes/uuid.rb,
lib/acfs/resource/attributes/float.rb,
lib/acfs/resource/attributes/string.rb,
lib/acfs/resource/attributes/boolean.rb,
lib/acfs/resource/attributes/integer.rb,
lib/acfs/resource/attributes/date_time.rb

Overview

Acfs Attributes

Allows to specify attributes of a class with default values and type safety.

For each attribute a setter and getter will be created and values will be type casted when set.

Examples:

class User < Acfs::Resource
  attribute :name, :string, default: 'Anon'
  attribute :age, :integer
  attribute :special, My::Special::Type
end

Defined Under Namespace

Modules: ClassMethods Classes: Base, Boolean, DateTime, Dict, Float, Integer, List, String, UUID

Constant Summary collapse

Uuid =

Lower-case alias for automatic type lookup

UUID

Instance Method Summary collapse

Instance Method Details

#attributesHashWithIndifferentAccess{Symbol => Object}

Returns ActiveModel compatible list of attributes and values.

rubocop:disable Naming/MemoizedInstanceVariableName

Examples:

class User < Acfs::Resource
  attribute :name, type: String, default: 'Anon'
end
user = User.new(name: 'John')
user.attributes # => { "name" => "John" }

Returns:

  • (HashWithIndifferentAccess{Symbol => Object})

    Attributes and their values.



52
53
54
# File 'lib/acfs/resource/attributes.rb', line 52

def attributes
  @_attrs ||= HashWithIndifferentAccess.new
end

#attributes=(attributes) ⇒ Object

Update all attributes with given hash. Attribute values will be casted to defined attribute type.

Examples:

user.attributes = { :name => 'Adam' }
user.name # => 'Adam'

Parameters:

  • Attributes (Hash{String, Symbol => Object}, #each{|key, value|})

    to set in resource.

See Also:



70
71
72
# File 'lib/acfs/resource/attributes.rb', line 70

def attributes=(attributes)
  write_attributes(attributes)
end

#initialize(*attrs) ⇒ Object

Write default attributes defined in resource class.



31
32
33
34
35
# File 'lib/acfs/resource/attributes.rb', line 31

def initialize(*attrs)
  write_attributes self.class.attributes
  reset_changes
  super
end

#read_attribute(name) ⇒ Object

Read an attribute from instance variable.

Parameters:

  • name (Symbol, String)

    Attribute name.

Returns:

  • (Object)

    Attribute value.



81
82
83
# File 'lib/acfs/resource/attributes.rb', line 81

def read_attribute(name)
  attributes[name.to_s]
end

#write_attribute(name, value, opts = {}) ⇒ Object

Write single attribute with given value. Value will be casted to defined attribute type.

Parameters:

  • name (String, Symbol)

    Attribute name.

  • value (Object)

    Value to write.

Raises:

  • (ArgumentError)

    If no attribute with given name is defined.



160
161
162
163
164
165
166
167
# File 'lib/acfs/resource/attributes.rb', line 160

def write_attribute(name, value, opts = {})
  attr_type = self.class.defined_attributes[name.to_s]
  if attr_type
    write_raw_attribute name, attr_type.cast(value), opts
  else
    write_raw_attribute name, value, opts
  end
end

#write_attributes(attributes, **opts) ⇒ Object

Write a hash of attributes and values.

If attribute value is a `Proc` it will be evaluated in the context of the resource after all non-proc attribute values are set. Values will be casted to defined attribute type.

The behavior is used to apply default attributes from resource class definition.

Examples:

user.write_attributes name: 'john', email: ->{ "#{name}@example.org" }
user.name  # => 'john'
user.email # => 'john@example.org'

Parameters:

  • Attributes (Hash{String, Symbol => Object, Proc}, #each{|key, value|})

    to write.

See Also:



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/acfs/resource/attributes.rb', line 106

def write_attributes(attributes, **opts)
  unless attributes.respond_to?(:each) && attributes.respond_to?(:keys)
    return false
  end

  if opts.fetch(:unknown, :ignore) == :raise &&
     (attributes.keys.map(&:to_s) - self.class.attributes.keys).any?
    missing = attributes.keys - self.class.attributes.keys
    missing.map!(&:inspect)
    raise ArgumentError.new "Unknown attributes: #{missing.join(', ')}"
  end

  procs = {}

  attributes.each do |key, _|
    if attributes[key].is_a? Proc
      procs[key] = attributes[key]
    else
      write_local_attribute(key, attributes[key], **opts)
    end
  end

  procs.each do |key, proc|
    write_local_attribute(key, instance_exec(&proc), **opts)
  end

  true
end

#write_local_attribute(name, value, opts = {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a public getter for attribute exists that should be called to write it or of #write_attribute should be called directly. This is necessary as #write_attribute should go though setters but can also handle unknown attribute that will not have a generated setter method.



142
143
144
145
146
147
148
149
# File 'lib/acfs/resource/attributes.rb', line 142

def write_local_attribute(name, value, opts = {})
  method = "#{name}="
  if respond_to? method, true
    public_send method, value
  else
    write_attribute name, value, opts
  end
end

#write_raw_attribute(name, value, _ = {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Write an attribute without checking type or existence or casting value to attributes type. Value be stored in an instance variable named after attribute name.

Parameters:

  • name (String, Symbol)

    Attribute name.

  • value (Object)

    Attribute value.



178
179
180
# File 'lib/acfs/resource/attributes.rb', line 178

def write_raw_attribute(name, value, _ = {})
  attributes[name.to_s] = value
end