module Dry::Core::ClassAttributes

Internal support module for class-level settings

@api public

Public Instance Methods

defines(*args, type: ::Object, coerce: IDENTITY) click to toggle source

Specify what attributes a class will use

@example

class ExtraClass
  extend Dry::Core::ClassAttributes

  defines :hello

  hello 'world'
end

@example with inheritance and type checking

class MyClass
  extend Dry::Core::ClassAttributes

  defines :one, :two, type: Integer

  one 1
  two 2
end

class OtherClass < MyClass
  two 3
end

MyClass.one # => 1
MyClass.two # => 2

OtherClass.one # => 1
OtherClass.two # => 3

@example with dry-types

class Foo
  extend Dry::Core::ClassAttributes

  defines :one, :two, type: Dry::Types['strict.int']
end

@example with coercion using Proc

class Bar
  extend Dry::Core::ClassAttributes

  defines :one, coerce: proc { |value| value.to_s }
end

@example with coercion using dry-types

class Bar
  extend Dry::Core::ClassAttributes

  defines :one, coerce: Dry::Types['coercible.string']
end
Calls superclass method
# File lib/dry/core/class_attributes.rb, line 70
def defines(*args, type: ::Object, coerce: IDENTITY)
  unless coerce.respond_to?(:call)
    raise ::ArgumentError, "Non-callable coerce option: #{coerce.inspect}"
  end

  mod = ::Module.new do
    args.each do |name|
      ivar = :"@#{name}"

      define_method(name) do |value = Undefined|
        if Undefined.equal?(value)
          if instance_variable_defined?(ivar)
            instance_variable_get(ivar)
          else
            nil
          end
        elsif type === value
          instance_variable_set(ivar, coerce.call(value))
        else
          raise InvalidClassAttributeValue.new(name, value)
        end
      end
    end

    define_method(:inherited) do |klass|
      args.each { |name| klass.send(name, send(name)) }

      super(klass)
    end
  end

  extend(mod)
end