Module: Jsapi::Meta::Attributes::ClassMethods

Included in:
Base
Defined in:
lib/jsapi/meta/attributes/class_methods.rb

Instance Method Summary collapse

Instance Method Details

#attribute(name, type = Object, keys: nil, values: nil, default: nil, default_key: nil, writer: true) ⇒ Object

Defines an attribute.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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/jsapi/meta/attributes/class_methods.rb', line 8

def attribute(name, type = Object,
              keys: nil,
              values: nil,
              default: nil,
              default_key: nil,
              writer: true)

  (@attribute_names ||= []) << name.to_sym

  instance_variable_name = "@#{name}"

  # Attribute reader
  define_method(name) do
    value = instance_variable_get(instance_variable_name)
    value.nil? ? default : value
  end

  case type
  when Array
    if writer
      singular_name = name.to_s.singularize
      type_caster = TypeCaster.new(type.first, values: values, name: singular_name)

      # Attribute writer
      define_method("#{name}=") do |argument|
        instance_variable_set(
          instance_variable_name,
          Array.wrap(argument).map { |element| type_caster.cast(element) }
        )
      end

      # add_{singular_name} method
      define_method("add_#{singular_name}") do |argument = nil|
        type_caster.cast(argument).tap do |casted_argument|
          if instance_variable_defined?(instance_variable_name)
            instance_variable_get(instance_variable_name)
          else
            instance_variable_set(instance_variable_name, [])
          end << casted_argument
        end
      end
    end
  when Hash
    singular_name = name.to_s.singularize
    key_type, value_type = type.first
    key_type_caster = TypeCaster.new(key_type, values: keys, name: 'key')

    # hash value reader
    define_method(singular_name) do |key = nil|
      send(name)&.[](key_type_caster.cast(key) || default_key)
    end

    if writer
      value_type_caster = TypeCaster.new(value_type, values: values)

      # add_{singular_name} method
      define_method("add_#{singular_name}") do |key_or_value, value = nil|
        if value.nil? && default_key
          key = default_key
          value = key_or_value
        else
          key = key_or_value || default_key
        end
        raise ArgumentError, "key can't be blank" if key.blank?

        casted_key = key_type_caster.cast(key)
        casted_value = value_type_caster.cast(value)

        if instance_variable_defined?(instance_variable_name)
          instance_variable_get(instance_variable_name)
        else
          instance_variable_set(instance_variable_name, {})
        end[casted_key] = casted_value
      end
    end
  else
    # Predicate method
    define_method("#{name}?") do
      value = instance_variable_get(instance_variable_name)
      value.nil? ? default || false : value
    end if values == [true, false]

    if writer
      type_caster = TypeCaster.new(type, values: values, name: name)

      # Attribute writer
      define_method("#{name}=") do |argument = nil|
        instance_variable_set(
          instance_variable_name, type_caster.cast(argument)
        )
      end
    end
  end
end

#attribute_namesObject



103
104
105
106
107
108
# File 'lib/jsapi/meta/attributes/class_methods.rb', line 103

def attribute_names
  names = @attribute_names || []
  return names unless superclass.respond_to?(:attribute_names)

  superclass.attribute_names + names
end