simple_ams 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|