simple_ams 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +35 -8
- data/lib/simple_ams/adapters/ams.rb +33 -16
- data/lib/simple_ams/adapters/jsonapi.rb +182 -0
- data/lib/simple_ams/document/fields.rb +17 -32
- data/lib/simple_ams/document/forms.rb +13 -0
- data/lib/simple_ams/document/generics.rb +14 -0
- data/lib/simple_ams/document/links.rb +14 -24
- data/lib/simple_ams/document/metas.rb +1 -1
- data/lib/simple_ams/document/primary_id.rb +23 -0
- data/lib/simple_ams/document/relations.rb +43 -13
- data/lib/simple_ams/document.rb +68 -16
- data/lib/simple_ams/dsl.rb +127 -33
- data/lib/simple_ams/options/concerns/name_value_hash.rb +5 -4
- data/lib/simple_ams/options/concerns/value_hash.rb +14 -3
- data/lib/simple_ams/options/forms.rb +12 -0
- data/lib/simple_ams/options/generics.rb +13 -0
- data/lib/simple_ams/options/metas.rb +0 -1
- data/lib/simple_ams/options/relations.rb +52 -0
- data/lib/simple_ams/options.rb +115 -87
- data/lib/simple_ams/version.rb +1 -1
- data/lib/simple_ams.rb +7 -1
- metadata +9 -3
- data/lib/simple_ams/options/relation.rb +0 -31
data/lib/simple_ams/document.rb
CHANGED
@@ -1,24 +1,30 @@
|
|
1
1
|
require "simple_ams"
|
2
2
|
|
3
3
|
class SimpleAMS::Document
|
4
|
-
attr_reader :options, :serializer, :resource
|
4
|
+
attr_reader :options, :embedded_options, :serializer, :resource
|
5
5
|
|
6
|
-
def initialize(options =
|
6
|
+
def initialize(options, embedded_options = nil)
|
7
7
|
@options = options
|
8
|
+
@embedded_options = embedded_options
|
8
9
|
@serializer = options.serializer
|
9
10
|
@resource = options.resource
|
10
11
|
end
|
11
12
|
|
12
13
|
def primary_id
|
13
|
-
options
|
14
|
+
@primary_id ||= self.class::PrimaryId.new(options)
|
14
15
|
end
|
15
16
|
|
16
17
|
def fields
|
18
|
+
return @fields if defined?(@fields)
|
19
|
+
return @fields = [] if options.fields.empty?
|
17
20
|
return @fields ||= self.class::Fields.new(options)
|
18
21
|
end
|
19
22
|
|
20
23
|
def relations
|
21
|
-
return @relations
|
24
|
+
return @relations if defined?(@relations)
|
25
|
+
return @relations ||= self.class::Relations.new(
|
26
|
+
options, options.relations
|
27
|
+
)
|
22
28
|
end
|
23
29
|
|
24
30
|
def name
|
@@ -34,13 +40,29 @@ class SimpleAMS::Document
|
|
34
40
|
end
|
35
41
|
|
36
42
|
def links
|
43
|
+
return @links if defined?(@links)
|
44
|
+
return @links = {} if options.links.empty?
|
37
45
|
return @links ||= self.class::Links.new(options)
|
38
46
|
end
|
39
47
|
|
40
48
|
def metas
|
49
|
+
return @metas if defined?(@metas)
|
50
|
+
return @metas = {} if options.metas.empty?
|
41
51
|
return @metas ||= self.class::Metas.new(options)
|
42
52
|
end
|
43
53
|
|
54
|
+
def forms
|
55
|
+
return @forms if defined?(@forms)
|
56
|
+
return @forms = {} if options.forms.empty?
|
57
|
+
return @forms ||= self.class::Forms.new(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def generics
|
61
|
+
return @generics if defined?(@generics)
|
62
|
+
return @generics = {} if options.generics.empty?
|
63
|
+
return @generics ||= self.class::Generics.new(options)
|
64
|
+
end
|
65
|
+
|
44
66
|
def folder?
|
45
67
|
self.is_a?(self.class::Folder)
|
46
68
|
end
|
@@ -49,18 +71,37 @@ class SimpleAMS::Document
|
|
49
71
|
!folder?
|
50
72
|
end
|
51
73
|
|
74
|
+
def embedded
|
75
|
+
return nil unless embedded_options
|
76
|
+
|
77
|
+
@embedded ||= SimpleAMS::Document.new(embedded_options)
|
78
|
+
end
|
79
|
+
|
52
80
|
class Folder < self
|
53
|
-
|
81
|
+
include Enumerable
|
82
|
+
attr_reader :members
|
54
83
|
|
55
|
-
def initialize(options)
|
84
|
+
def initialize(options, embedded_options = nil)
|
56
85
|
@_options = options
|
86
|
+
@embedded_options = embedded_options
|
57
87
|
@options = @_options.collection_options
|
58
88
|
|
59
|
-
@
|
89
|
+
@members = options.collection
|
90
|
+
end
|
91
|
+
|
92
|
+
def each(&block)
|
93
|
+
return enum_for(:each) unless block_given?
|
94
|
+
|
95
|
+
members.each do |resource|
|
96
|
+
yield SimpleAMS::Document.new(options_for(resource))
|
97
|
+
end
|
98
|
+
|
99
|
+
self
|
60
100
|
end
|
61
101
|
|
102
|
+
#do we really need this method ?
|
62
103
|
def documents
|
63
|
-
@
|
104
|
+
@members.map do |resource|
|
64
105
|
SimpleAMS::Document.new(options_for(resource))
|
65
106
|
end
|
66
107
|
end
|
@@ -72,15 +113,26 @@ class SimpleAMS::Document
|
|
72
113
|
private
|
73
114
|
attr_reader :_options
|
74
115
|
|
75
|
-
#TODO: OBS! here we have extra cost for nothing
|
76
|
-
#can't we just pass the resource_option with different resource?
|
77
116
|
def options_for(resource)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
117
|
+
if resource_options.serializer_class.respond_to?(:call)
|
118
|
+
SimpleAMS::Options.new(resource, {
|
119
|
+
injected_options: resource_options.injected_options.merge({
|
120
|
+
serializer: serializer_for(resource)
|
121
|
+
}),
|
122
|
+
allowed_options: serializer_for(resource).options
|
123
|
+
})
|
124
|
+
else
|
125
|
+
resource_options.with_resource(resource)
|
126
|
+
end
|
127
|
+
=begin
|
128
|
+
SimpleAMS::Options.new(resource, {
|
129
|
+
injected_options: resource_options.injected_options.merge({
|
130
|
+
serializer: serializer_for(resource)
|
131
|
+
}),
|
132
|
+
allowed_options: serializer_for(resource).options
|
133
|
+
})
|
134
|
+
end
|
135
|
+
=end
|
84
136
|
end
|
85
137
|
|
86
138
|
def serializer_for(resource)
|
data/lib/simple_ams/dsl.rb
CHANGED
@@ -16,16 +16,27 @@ module SimpleAMS::DSL
|
|
16
16
|
includes: includes,
|
17
17
|
links: links,
|
18
18
|
metas: metas,
|
19
|
+
forms: forms,
|
20
|
+
generics: generics,
|
19
21
|
}
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
host_class.const_set('
|
25
|
+
host_class.const_set('Collection_', _klass)
|
24
26
|
end
|
25
27
|
|
26
28
|
module ClassMethods
|
27
29
|
#TODO: Shouldn't we call here super to presever user's behavior ?
|
28
30
|
def inherited(subclass)
|
31
|
+
#TODO: why this breaks collection type?
|
32
|
+
subclass.with_options(
|
33
|
+
options.merge(
|
34
|
+
#TODO: maybe add another group of elements under dsl?
|
35
|
+
#this could be DSL::Type.new(type).explicit?
|
36
|
+
type.last[:_explicit] ? {} : {type: nil}
|
37
|
+
)
|
38
|
+
)
|
39
|
+
|
29
40
|
_klass = Class.new(Object).extend(ClassMethods)
|
30
41
|
_klass.instance_eval do
|
31
42
|
def options
|
@@ -38,11 +49,20 @@ module SimpleAMS::DSL
|
|
38
49
|
includes: includes,
|
39
50
|
links: links,
|
40
51
|
metas: metas,
|
52
|
+
forms: forms,
|
53
|
+
generics: generics,
|
41
54
|
}
|
42
55
|
end
|
43
56
|
end
|
44
57
|
|
45
|
-
|
58
|
+
_klass.with_options(
|
59
|
+
self::Collection_.options.merge(
|
60
|
+
#TODO: maybe add another group of elements under dsl?
|
61
|
+
#this could be DSL::Type.new(type).explicit?
|
62
|
+
type.last[:_explicit] ? {} : {type: nil}
|
63
|
+
)
|
64
|
+
)
|
65
|
+
subclass.const_set('Collection_', _klass)
|
46
66
|
end
|
47
67
|
|
48
68
|
def default_options
|
@@ -55,11 +75,11 @@ module SimpleAMS::DSL
|
|
55
75
|
|
56
76
|
#TODO: Add tests !!
|
57
77
|
def _default_type_name
|
58
|
-
if self.to_s.end_with?('::
|
78
|
+
if self.to_s.end_with?('::Collection_')
|
59
79
|
_name = self.to_s.gsub(
|
60
80
|
'Serializer',''
|
61
81
|
).gsub(
|
62
|
-
'::
|
82
|
+
'::Collection_', ''
|
63
83
|
).downcase.split('::').last
|
64
84
|
|
65
85
|
return "#{_name}_collection".to_sym
|
@@ -71,11 +91,21 @@ module SimpleAMS::DSL
|
|
71
91
|
@_options = options
|
72
92
|
meths = SimpleAMS::DSL::ClassMethods.instance_methods(false)
|
73
93
|
@_options.each do |key, value|
|
74
|
-
if key
|
75
|
-
|
94
|
+
if key == :relations
|
95
|
+
(value || []).each{|rel_value|
|
96
|
+
append_relationship(rel_value)
|
97
|
+
}
|
98
|
+
elsif key.to_sym == :collection
|
99
|
+
#TODO: Add proc option maybe?
|
100
|
+
if value.is_a?(Hash)
|
101
|
+
collection{}.with_options(value)
|
102
|
+
end
|
76
103
|
elsif meths.include?(key)
|
77
|
-
|
78
|
-
|
104
|
+
if (value.is_a?(Array) && value.first.is_a?(Array)) || value.is_a?(Hash)
|
105
|
+
self.send(key, value)
|
106
|
+
else
|
107
|
+
self.send(key, *value)
|
108
|
+
end
|
79
109
|
else
|
80
110
|
#TODO: Add a proper logger
|
81
111
|
puts "SimpeAMS: #{key} is not recognized, ignoring (from #{self.to_s})"
|
@@ -85,26 +115,16 @@ module SimpleAMS::DSL
|
|
85
115
|
return @_options
|
86
116
|
end
|
87
117
|
|
88
|
-
|
89
|
-
|
90
|
-
@_adapter ||= default_options[:adapter]
|
91
|
-
return @_adapter if name.nil?
|
92
|
-
|
93
|
-
@_adapter = [name, options]
|
118
|
+
def adapter(value = nil, options = {})
|
119
|
+
@_adapter = _value_hash_for(@_adapter, value, options, :adapter)
|
94
120
|
end
|
95
121
|
|
96
122
|
def primary_id(value = nil, options = {})
|
97
|
-
@_primary_id
|
98
|
-
return @_primary_id if value.nil?
|
99
|
-
|
100
|
-
@_primary_id = [value, options]
|
123
|
+
@_primary_id = _value_hash_for(@_primary_id, value, options, :primary_id)
|
101
124
|
end
|
102
125
|
|
103
126
|
def type(value = nil, options = {})
|
104
|
-
@_type
|
105
|
-
return @_type if value.nil?
|
106
|
-
|
107
|
-
@_type = [value, options]
|
127
|
+
@_type = _value_hash_for(@_type, value, options.merge(_explicit: true), :type)
|
108
128
|
end
|
109
129
|
|
110
130
|
def attributes(*args)
|
@@ -116,26 +136,50 @@ module SimpleAMS::DSL
|
|
116
136
|
alias attribute attributes
|
117
137
|
alias fields attributes
|
118
138
|
|
119
|
-
def
|
120
|
-
|
139
|
+
def attributes=(*args)
|
140
|
+
@_attributes = []
|
141
|
+
|
142
|
+
attributes(args)
|
143
|
+
end
|
144
|
+
|
145
|
+
def has_many(name, options = {}, &block)
|
146
|
+
append_relationship(
|
147
|
+
[__method__, name, options, embedded_class_for(name, options, block)]
|
148
|
+
)
|
121
149
|
end
|
122
150
|
|
123
|
-
def has_one(name, options = {})
|
124
|
-
append_relationship(
|
151
|
+
def has_one(name, options = {}, &block)
|
152
|
+
append_relationship(
|
153
|
+
[__method__, name, options, embedded_class_for(name, options, block)]
|
154
|
+
)
|
125
155
|
end
|
126
156
|
|
127
|
-
def belongs_to(name, options = {})
|
128
|
-
append_relationship(
|
157
|
+
def belongs_to(name, options = {}, &block)
|
158
|
+
append_relationship(
|
159
|
+
[__method__, name, options, embedded_class_for(name, options, block)]
|
160
|
+
)
|
129
161
|
end
|
130
162
|
|
131
163
|
def relations
|
132
164
|
@_relations || []
|
133
165
|
end
|
134
166
|
|
167
|
+
def embedded_class_for(name, options, block)
|
168
|
+
embedded = Class.new(self)
|
169
|
+
klass_name = "Embedded#{name.to_s.capitalize}Options_"
|
170
|
+
self.const_set(klass_name, embedded)
|
171
|
+
embedded.with_options(
|
172
|
+
default_options.merge(options.select{|k| k != :serializer})
|
173
|
+
)
|
174
|
+
embedded.instance_exec(&block) if block
|
175
|
+
|
176
|
+
return embedded
|
177
|
+
end
|
178
|
+
|
135
179
|
#TODO: there is no memoization here, hence we ignore includes manually set !!
|
136
180
|
#Consider fixing it by employing an observer that will clean the instance var
|
137
181
|
#each time @_relations is updated
|
138
|
-
def includes(
|
182
|
+
def includes(*args)
|
139
183
|
relations.map{|rel| rel[1] }
|
140
184
|
end
|
141
185
|
|
@@ -147,28 +191,53 @@ module SimpleAMS::DSL
|
|
147
191
|
append_meta([name, value, options])
|
148
192
|
end
|
149
193
|
|
194
|
+
def form(name, value, options = {})
|
195
|
+
append_form([name, value, options])
|
196
|
+
end
|
197
|
+
|
198
|
+
def generic(name, value, options = {})
|
199
|
+
append_generic([name, value, options])
|
200
|
+
end
|
201
|
+
|
150
202
|
def links(links = [])
|
203
|
+
return @_links ||= [] if links.empty?
|
151
204
|
links.map{|key, value| append_link([key, value].flatten(1))} if links.is_a?(Hash)
|
152
205
|
|
153
206
|
@_links ||= links
|
154
207
|
end
|
155
208
|
|
156
209
|
def metas(metas = [])
|
210
|
+
return @_metas ||= [] if metas.empty?
|
211
|
+
|
157
212
|
metas.map{|key, value| append_meta([key, value].flatten(1))} if metas.is_a?(Hash)
|
158
213
|
|
159
|
-
@_metas
|
214
|
+
@_metas ||= metas
|
215
|
+
end
|
216
|
+
|
217
|
+
def forms(forms = [])
|
218
|
+
return @_forms ||= [] if forms.empty?
|
219
|
+
forms.map{|key, value| append_form([key, value].flatten(1))} if forms.is_a?(Hash)
|
220
|
+
|
221
|
+
@_forms ||= forms
|
222
|
+
end
|
223
|
+
|
224
|
+
def generics(generics = [])
|
225
|
+
return @_generics ||= [] if generics.empty?
|
226
|
+
generics.map{|key, value| append_generic([key, value].flatten(1))} if generics.is_a?(Hash)
|
227
|
+
|
228
|
+
@_generics ||= generics
|
160
229
|
end
|
161
230
|
|
162
231
|
def collection(name = nil, &block)
|
163
232
|
if block
|
164
|
-
self::
|
233
|
+
self::Collection_.class_eval do
|
165
234
|
instance_exec(&block)
|
166
235
|
end
|
167
236
|
end
|
168
237
|
|
169
|
-
self::
|
238
|
+
self::Collection_.type(name) if name
|
170
239
|
|
171
|
-
return self::
|
240
|
+
return self::Collection_
|
172
241
|
end
|
173
242
|
|
174
243
|
def options
|
@@ -181,11 +250,24 @@ module SimpleAMS::DSL
|
|
181
250
|
includes: includes,
|
182
251
|
links: links,
|
183
252
|
metas: metas,
|
253
|
+
forms: forms,
|
254
|
+
generics: generics,
|
184
255
|
collection: collection
|
185
256
|
}
|
186
257
|
end
|
187
258
|
|
259
|
+
def simple_ams?
|
260
|
+
true
|
261
|
+
end
|
262
|
+
|
188
263
|
private
|
264
|
+
def _value_hash_for(current, value, options, name)
|
265
|
+
_type = current || default_options[name]
|
266
|
+
return _type if value.nil?
|
267
|
+
|
268
|
+
return [value, options]
|
269
|
+
end
|
270
|
+
|
189
271
|
def append_relationship(rel)
|
190
272
|
@_relations ||= []
|
191
273
|
|
@@ -210,6 +292,18 @@ module SimpleAMS::DSL
|
|
210
292
|
@_metas << meta
|
211
293
|
end
|
212
294
|
|
295
|
+
def append_form(form)
|
296
|
+
@_forms ||= []
|
297
|
+
|
298
|
+
@_forms << form
|
299
|
+
end
|
300
|
+
|
301
|
+
def append_generic(generic)
|
302
|
+
@_generics ||= []
|
303
|
+
|
304
|
+
@_generics << generic
|
305
|
+
end
|
306
|
+
|
213
307
|
def empty_options
|
214
308
|
end
|
215
309
|
end
|
@@ -5,14 +5,15 @@ class SimpleAMS::Options
|
|
5
5
|
module NameValueHash
|
6
6
|
attr_reader :name, :value, :options
|
7
7
|
|
8
|
-
def initialize(name, value, options = {}, resource:)
|
8
|
+
def initialize(name, value, options = {}, resource:, serializer:)
|
9
9
|
@name = name.is_a?(String) ? name.to_sym : name
|
10
|
-
if value.is_a?(Proc)
|
11
|
-
_value = value.call(resource)
|
12
|
-
@value = _value.first
|
10
|
+
if value.is_a?(Proc) #TODO: maybe we should do duck typing instead?
|
11
|
+
_value = value.call(resource, serializer)
|
13
12
|
if _value.is_a?(Array) && _value.length > 1
|
13
|
+
@value = _value.first
|
14
14
|
@options = (_value.last || {}).merge(options || {})
|
15
15
|
else
|
16
|
+
@value = _value
|
16
17
|
@options = options || {}
|
17
18
|
end
|
18
19
|
else
|
@@ -5,9 +5,20 @@ class SimpleAMS::Options
|
|
5
5
|
module ValueHash
|
6
6
|
attr_reader :value, :options
|
7
7
|
|
8
|
-
def initialize(value, options = {})
|
9
|
-
|
10
|
-
|
8
|
+
def initialize(value, options = {}, resource:, serializer:)
|
9
|
+
if value.is_a?(Proc) #TODO: maybe we should do duck typing instead?
|
10
|
+
_value = value.call(resource, serializer)
|
11
|
+
if _value.is_a?(Array) && _value.length > 1
|
12
|
+
@value = _value.first
|
13
|
+
@options = (_value.last || {}).merge(options || {})
|
14
|
+
else
|
15
|
+
@value = _value
|
16
|
+
@options = options || {}
|
17
|
+
end
|
18
|
+
else
|
19
|
+
@value = value.is_a?(String) ? value.to_sym : value
|
20
|
+
@options = options || {}
|
21
|
+
end
|
11
22
|
end
|
12
23
|
|
13
24
|
alias_method :name, :value
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Options
|
4
|
+
class Relations < Array
|
5
|
+
attr_reader :relations, :includes
|
6
|
+
|
7
|
+
def initialize(relations, includes = nil)
|
8
|
+
@relations = relations
|
9
|
+
@includes = includes
|
10
|
+
|
11
|
+
super(relations.map{|rel| Relations::Relation.new(*rel)})
|
12
|
+
end
|
13
|
+
|
14
|
+
def available
|
15
|
+
return @available ||= self if includes.nil?
|
16
|
+
return @available ||= [] if includes.empty?
|
17
|
+
|
18
|
+
@available ||= self.select{
|
19
|
+
|relation| includes.include?(relation.name)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
class Relation
|
24
|
+
attr_reader :type, :name, :options, :embedded
|
25
|
+
def initialize(type, name, options = {}, embedded)
|
26
|
+
@type = type.to_sym
|
27
|
+
@name = name.is_a?(String) ? name.to_sym : name
|
28
|
+
@options = options
|
29
|
+
@embedded = embedded
|
30
|
+
|
31
|
+
@many = type == :has_many ? true : false
|
32
|
+
end
|
33
|
+
|
34
|
+
alias relation name
|
35
|
+
|
36
|
+
def raw
|
37
|
+
[type, name, options, embedded]
|
38
|
+
end
|
39
|
+
|
40
|
+
def collection?
|
41
|
+
@many
|
42
|
+
end
|
43
|
+
|
44
|
+
def single?
|
45
|
+
!collection?
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
attr_writer :type, :name, :options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|