/
builder.rb
133 lines (110 loc) · 2.82 KB
/
builder.rb
1
2
3
4
5
6
7
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
102
103
104
105
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
module Virtus
# Class to build a Virtus module with it's own config
#
# This allows for individual Virtus modules to be included in
# classes and not impacted by the global Virtus config,
# which is implemented using Virtus::config.
#
# @private
class Builder
# Return module
#
# @return [Module]
#
# @api private
attr_reader :mod
# Return config
#
# @return [config]
#
# @api private
attr_reader :config
# @api private
def self.call(options, &block)
new(Configuration.new(options, &block)).mod
end
# @api private
def self.pending
@pending ||= []
end
# Initializes a new Builder
#
# @param [Configuration] config
# @param [Module] mod
#
# @return [undefined]
#
# @api private
def initialize(conf, mod = Module.new)
@config, @mod = conf, mod
add_included_hook
add_extended_hook
end
# @api private
def extensions
[Model::Core]
end
# @api private
def options
config.to_h
end
private
# Adds the .included hook to the anonymous module which then defines the
# .attribute method to override the default.
#
# @return [Module]
#
# @api private
def add_included_hook
with_hook_context do |context|
mod.define_singleton_method :included do |object|
Builder.pending << object unless context.finalize?
context.modules.each { |mod| object.send(:include, mod) }
object.define_singleton_method(:attribute, context.attribute_method)
end
end
end
# @api private
def add_extended_hook
with_hook_context do |context|
mod.define_singleton_method :extended do |object|
context.modules.each { |mod| object.extend(mod) }
object.define_singleton_method(:attribute, context.attribute_method)
end
end
end
# @api private
def with_hook_context
yield(HookContext.new(self, config))
end
end # class Builder
# @private
class ModelBuilder < Builder
end # ModelBuilder
# @private
class ModuleBuilder < Builder
private
# @api private
def add_included_hook
with_hook_context do |context|
mod.define_singleton_method :included do |object|
super(object)
object.extend(ModuleExtensions)
ModuleExtensions.setup(object, context.modules)
object.define_singleton_method(:attribute, context.attribute_method)
end
end
end
end # ModuleBuilder
# @private
class ValueObjectBuilder < Builder
# @api private
def extensions
super << ValueObject::AllowedWriterMethods << ValueObject::InstanceMethods
end
# @api private
def options
super.merge(:writer => :private)
end
end # ValueObjectBuilder
end # module Virtus