Completed
Push — master ( 001e31...14458d )
by Marcelo
01:22
created

ClassMethods.coerce_adapter()   A

Complexity

Conditions 3

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
1
require 'koine/attributes/version'
2
require 'koine/attributes/builder'
3
require 'koine/attributes/adapter/base'
4
5
# provides the following API
6
#
7
# @example using attributes
8
#   class Person
9
#     attributes do
10
#       attribute :name, :string
11
#       attribute :birthday, :date
12
#
13
#       # or
14
#       attribute :birthday, Koine::Attributes::Adapter::Date.new
15
#     end
16
#   end
17
#
18
#   peson = Person.new
19
#   person.name = 'John Doe'
20
#   person.birtday = '2001-02-31' # Date Object can also be given
21
#
22
#   person.name # => 'John Doe'
23
#   person.birtday # => #<Date 2001-02-31>
24
#
25
# @example custom attribute options
26
#
27
#     attributes do
28
#       attribute :name, Koine::Attributes::Adapters::Date.new.with_default('guest')
29
#
30
#       # or
31
#       attribute :name, :string, ->(adapter) { adapter.with_default('guest') }
32
#     end
33
#
34
# @example Constructor for attributes
35
#
36
#   class Person
37
#     attributes initializer: true do
38
#       attribute :name, :string
39
#       attribute :birthday, :date
40
#     end
41
#   end
42
#
43
#   person = Person.new(name: 'John Doe', birthday: '2001-01-31')
44
#
45
#   # foo: attribute will raise error with strict mode
46
#   person = Person.new(name: 'John Doe', birthday: '2001-01-31', foo: :bar)
47
#
48
# @example Constructor for attributes withouth strict mode
49
#
50
#   class Person
51
#     attributes initializer: { strict: false } do
52
#       attribute :name, :string
53
#       attribute :birthday, :date
54
#     end
55
#   end
56
#
57
#   # foo will be ignored
58
#   person = Person.new(name: 'John Doe', birthday: '2001-01-31', foo: :bar)
59
#
60
# @example Override constructor
61
#
62
#   class Person
63
#     attr_reader :foo
64
#
65
#     attributes initializer: true do
66
#       attribute :name, :string
67
#       attribute :birthday, :date
68
#     end
69
#
70
#     def initializ(attributes = {})
71
#       @foo = attributes.delete(:foo)
72
#
73
#       initialize_attributes(attributes) # protected
74
#     end
75
#   end
76
#
77
#   person = Person.new(name: 'John Doe', birthday: '2001-01-31', foo: :bar)
78
#   person.foo # => :bar
79
#
80
module Koine
81
  module Attributes
82
    module Adapter
83
      autoload :Date, 'koine/attributes/adapter/date'
84
    end
85
86
    Error = Class.new(StandardError)
87
88
    def self.included(base)
89
      base.extend(ClassMethods)
90
    end
91
92
    module ClassMethods
93
      def attributes(options = {}, &block)
94
        @builder = Builder.new(target: self)
95
        class_eval(&block)
96
97
        if options[:initializer]
98
          initializer_options = options[:initializer]
99
100
          initializer_options = {} unless initializer_options.is_a?(Hash)
101
102
          @builder.build_constructor(initializer_options)
103
        end
104
105
        @builder = nil
106
      end
107
108
      def attribute(name, adapter, &block)
109
        unless @builder
110
          raise Error, 'You must call .attribute inside the .attributes block'
111
        end
112
113
        adapter = coerce_adapter(adapter, &block)
114
        @builder.build(name, adapter)
115
      end
116
117
      private def coerce_adapter(adapter, &block)
118
        return adapter unless adapter.instance_of?(::Symbol)
119
        adapter = const_get("Koine::Attributes::Adapter::#{adapter.to_s.capitalize}").new
120
        yield(adapter) if block
121
        adapter
122
      end
123
    end
124
  end
125
end
126