Module: Micro::Attributes

Defined in:
lib/micro/attributes.rb,
lib/micro/attributes/diff.rb,
lib/micro/attributes/macros.rb,
lib/micro/attributes/version.rb,
lib/micro/attributes/features.rb,
lib/micro/attributes/composition.rb,
lib/micro/attributes/features/diff.rb,
lib/micro/attributes/features/accept.rb,
lib/micro/attributes/features/initialize.rb,
lib/micro/attributes/features/accept/strict.rb,
lib/micro/attributes/features/keys_as_symbol.rb,
lib/micro/attributes/features/initialize/strict.rb,
lib/micro/attributes/features/activemodel_validations.rb

Defined Under Namespace

Modules: Composition, Diff, Features, Utils, With

Constant Summary collapse

VERSION =
'3.1.0'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/micro/attributes.rb', line 14

def self.included(base)
  base.extend(::Micro::Attributes.const_get(:Macros))
  base.send(:prepend, ::Micro::Attributes::Composition::Coercion)
  base.send(:include, ::Micro::Attributes::Composition::Instance)

  base.class_eval do
    private_class_method :__attributes, :__attribute_reader
    private_class_method :__attribute_assign, :__attributes_groups
    private_class_method :__attributes_required_add, :__attributes_data_to_assign
    private_class_method :__attribute_reapply_visibility
  end

  def base.inherited(subclass)
    subclass.__attributes_set_after_inherit__(self.__attributes_data__)

    subclass.extend ::Micro::Attributes.const_get('Macros::ForSubclasses'.freeze)
  end
end

.new(options = {}, &block) ⇒ Object

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/micro/attributes.rb', line 67

def self.new(options = {}, &block)
  raise ArgumentError, 'options must be a Hash' unless options.is_a?(Hash)

  effective = NEW_DEFAULTS.merge(options)

  # `:initialize` must resolve to one of the allowed "on" values.
  # Catches `false`, `nil`, garbage values like `'wrong'`, etc. —
  # without it the returned class has no hash constructor and the
  # next `klass.new(hash)` raises an opaque `ArgumentError` from
  # `Object#initialize`.
  unless [true, :strict].include?(effective[:initialize])
    raise ArgumentError,
          '`Micro::Attributes.new` requires the :initialize feature ' \
          '(omit the key or pass `true` / `:strict`)'
  end

  klass = Class.new
  klass.send(:include, with(effective))
  klass.class_eval(&block) if block

  # ActiveModel-aware naming for the anonymous factory class. Without
  # this, the first call to `errors.full_messages` raises "Class name
  # cannot be blank" because AM's `model_name` is invoked on a still-
  # anonymous class (the user may never assign the result to a
  # constant). `self.name` resolves lazily — Ruby fills it in if/when
  # the constant is assigned later. Mirrors the inline-child fix in
  # `Macros#__micro_attributes_build_inline_class__`.
  if defined?(::ActiveModel::Validations) && klass.include?(::ActiveModel::Validations)
    klass.define_singleton_method(:model_name) do
      ::ActiveModel::Name.new(self, nil, self.name || self.inspect)
    end
  end

  klass
end

.with(*names) ⇒ Object



37
38
39
# File 'lib/micro/attributes.rb', line 37

def self.with(*names)
  Features.with(names)
end

.with_all_featuresObject



41
42
43
# File 'lib/micro/attributes.rb', line 41

def self.with_all_features
  Features.all
end

.without(*names) ⇒ Object



33
34
35
# File 'lib/micro/attributes.rb', line 33

def self.without(*names)
  Features.without(names)
end

Instance Method Details

#attribute(name) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/micro/attributes.rb', line 107

def attribute(name)
  return unless attribute?(name)

  value = public_send(name)

  block_given? ? yield(value) : value
end

#attribute!(name, &block) ⇒ Object

Raises:

  • (NameError)


115
116
117
118
119
# File 'lib/micro/attributes.rb', line 115

def attribute!(name, &block)
  attribute(name) { |name| return block ? block[name] : name }

  raise NameError, __attribute_access_error_message(name)
end

#attribute?(name, include_all = false) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/micro/attributes.rb', line 103

def attribute?(name, include_all = false)
  self.class.attribute?(name, include_all)
end

#attributes(*names) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/micro/attributes.rb', line 127

def attributes(*names)
  return __attributes if names.empty?

  options = names.last.is_a?(Hash) ? names.pop : Kind::Empty::HASH

  names.flatten!

  without_option = Array(options.fetch(:without, Kind::Empty::ARRAY))

  keys = names.empty? ? defined_attributes - without_option.map { |value| __attribute_key(value) } : names - without_option

  data = keys.each_with_object({}) { |key, memo| memo[key] = attribute(key) if attribute?(key) }

  with_option = Array(options.fetch(:with, Kind::Empty::ARRAY))

  unless with_option.empty?
    extra = with_option.each_with_object({}) { |key, memo| memo[__attribute_key(key)] = public_send(key) }

    data.merge!(extra)
  end

  Utils::Hashes.keys_as(options[:keys_as], data)
end

#defined_attributes(option = nil) ⇒ Object



121
122
123
124
125
# File 'lib/micro/attributes.rb', line 121

def defined_attributes(option = nil)
  return self.class.attributes_by_visibility if option == :by_visibility

  @defined_attributes ||= self.class.attributes
end