forked from Empact/roxml
-
Notifications
You must be signed in to change notification settings - Fork 108
/
representable.rb
118 lines (94 loc) · 3.38 KB
/
representable.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
require "uber/delegates"
require "uber/callable"
require "declarative/schema"
require "representable/option"
require "representable/config"
require "representable/definition"
require "representable/declarative"
require "representable/deserializer"
require "representable/serializer"
require "representable/binding"
require "representable/pipeline"
require "representable/insert" # Pipeline::Insert
require "representable/cached"
require "representable/for_collection"
require "representable/represent"
module Representable
autoload :Binding, 'representable/binding'
autoload :HashMethods, 'representable/hash_methods'
autoload :Decorator, 'representable/decorator'
autoload :Hash, 'representable/hash'
autoload :JSON, 'representable/json'
autoload :Object, 'representable/object'
autoload :YAML, 'representable/yaml'
autoload :XML, 'representable/xml'
attr_writer :representable_attrs
def self.included(base)
base.class_eval do
extend Declarative
# make Representable horizontally and vertically inheritable.
extend ModuleExtensions, ::Declarative::Heritage::Inherited, ::Declarative::Heritage::Included
extend ClassMethods
extend ForCollection
extend Represent
end
end
private
# Reads values from +doc+ and sets properties accordingly.
def update_properties_from(doc, options, format)
propagated_options = normalize_options(**options)
representable_map!(doc, propagated_options, format, :uncompile_fragment)
represented
end
# Compiles the document going through all properties.
def create_representation_with(doc, options, format)
propagated_options = normalize_options(**options)
representable_map!(doc, propagated_options, format, :compile_fragment)
doc
end
def representable_map(options, format)
Binding::Map.new(representable_bindings_for(format, options))
end
def representable_map!(doc, options, format, method)
options = {doc: doc, options: options, represented: represented, decorator: self}
representable_map(options, format).(method, options) # .(:uncompile_fragment, options)
end
def representable_bindings_for(format, options)
representable_attrs.collect {|definition| format.build(definition) }
end
def normalize_options(user_options: {}, **options)
{ user_options: user_options }.merge(options)
end
# Prepares options for a particular nested representer.
# This is used in Serializer and Deserializer.
OptionsForNested = ->(options, binding) do
child_options = {user_options: options[:user_options], }
# wrap:
child_options[:wrap] = binding[:wrap] unless binding[:wrap].nil?
# nested params:
child_options.merge!(options[binding.name.to_sym]) if options[binding.name.to_sym]
child_options
end
def representable_attrs
@representable_attrs ||= self.class.definitions
end
def representation_wrap(options = {})
representable_attrs.wrap_for(represented, options)
end
def represented
self
end
module ModuleExtensions
# Copies the representable_attrs reference to the extended object.
# Note that changing attrs in the instance will affect the class configuration.
def extended(object)
super
object.representable_attrs=(representable_attrs) # yes, we want a hard overwrite here and no inheritance.
end
end
module ClassMethods
def prepare(represented)
represented.extend(self)
end
end
end