simple_ams 0.1.0
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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/README.md +224 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/simple_ams/adapters/ams.rb +85 -0
- data/lib/simple_ams/adapters.rb +2 -0
- data/lib/simple_ams/document/fields.rb +66 -0
- data/lib/simple_ams/document/links.rb +61 -0
- data/lib/simple_ams/document/metas.rb +15 -0
- data/lib/simple_ams/document/relations.rb +95 -0
- data/lib/simple_ams/document.rb +93 -0
- data/lib/simple_ams/dsl.rb +216 -0
- data/lib/simple_ams/methy.rb +10 -0
- data/lib/simple_ams/options/adapter.rb +9 -0
- data/lib/simple_ams/options/concerns/filterable.rb +45 -0
- data/lib/simple_ams/options/concerns/name_value_hash.rb +32 -0
- data/lib/simple_ams/options/concerns/value_hash.rb +23 -0
- data/lib/simple_ams/options/fields.rb +7 -0
- data/lib/simple_ams/options/includes.rb +7 -0
- data/lib/simple_ams/options/links.rb +11 -0
- data/lib/simple_ams/options/metas.rb +12 -0
- data/lib/simple_ams/options/primary_id.rb +7 -0
- data/lib/simple_ams/options/relation.rb +31 -0
- data/lib/simple_ams/options/type.rb +8 -0
- data/lib/simple_ams/options.rb +299 -0
- data/lib/simple_ams/renderer.rb +59 -0
- data/lib/simple_ams/version.rb +3 -0
- data/lib/simple_ams.rb +29 -0
- data/simple_ams.gemspec +29 -0
- metadata +160 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Document
|
4
|
+
attr_reader :options, :serializer, :resource
|
5
|
+
|
6
|
+
def initialize(options = SimpleAMS::Options.new)
|
7
|
+
@options = options
|
8
|
+
@serializer = options.serializer
|
9
|
+
@resource = options.resource
|
10
|
+
end
|
11
|
+
|
12
|
+
def primary_id
|
13
|
+
options.primary_id
|
14
|
+
end
|
15
|
+
|
16
|
+
def fields
|
17
|
+
return @fields ||= self.class::Fields.new(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def relations
|
21
|
+
return @relations ||= self.class::Relations.new(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def name
|
25
|
+
options.name
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
options.type
|
30
|
+
end
|
31
|
+
|
32
|
+
def adapter
|
33
|
+
options.adapter
|
34
|
+
end
|
35
|
+
|
36
|
+
def links
|
37
|
+
return @links ||= self.class::Links.new(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def metas
|
41
|
+
return @metas ||= self.class::Metas.new(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def folder?
|
45
|
+
self.is_a?(self.class::Folder)
|
46
|
+
end
|
47
|
+
|
48
|
+
def document?
|
49
|
+
!folder?
|
50
|
+
end
|
51
|
+
|
52
|
+
class Folder < self
|
53
|
+
attr_reader :collection
|
54
|
+
|
55
|
+
def initialize(options)
|
56
|
+
@_options = options
|
57
|
+
@options = @_options.collection_options
|
58
|
+
|
59
|
+
@collection = options.collection
|
60
|
+
end
|
61
|
+
|
62
|
+
def documents
|
63
|
+
@documents = collection.map do |resource|
|
64
|
+
SimpleAMS::Document.new(options_for(resource))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def resource_options
|
69
|
+
_options
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
attr_reader :_options
|
74
|
+
|
75
|
+
#TODO: OBS! here we have extra cost for nothing
|
76
|
+
#can't we just pass the resource_option with different resource?
|
77
|
+
def options_for(resource)
|
78
|
+
SimpleAMS::Options.new(resource, {
|
79
|
+
injected_options: resource_options.injected_options.merge({
|
80
|
+
serializer: serializer_for(resource)
|
81
|
+
}),
|
82
|
+
allowed_options: resource_options.allowed_options
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
def serializer_for(resource)
|
87
|
+
_serializer = resource_options.serializer_class
|
88
|
+
_serializer = _serializer.call(resource) if _serializer.respond_to?(:call)
|
89
|
+
|
90
|
+
return _serializer
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
module SimpleAMS::DSL
|
4
|
+
def self.included(host_class)
|
5
|
+
host_class.extend ClassMethods
|
6
|
+
|
7
|
+
_klass = Class.new(Object).extend(ClassMethods)
|
8
|
+
_klass.instance_eval do
|
9
|
+
def options
|
10
|
+
{
|
11
|
+
adapter: adapter,
|
12
|
+
primary_id: primary_id,
|
13
|
+
type: type,
|
14
|
+
fields: fields,
|
15
|
+
relations: relations,
|
16
|
+
includes: includes,
|
17
|
+
links: links,
|
18
|
+
metas: metas,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
host_class.const_set('Collection', _klass)
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
#TODO: Shouldn't we call here super to presever user's behavior ?
|
28
|
+
def inherited(subclass)
|
29
|
+
_klass = Class.new(Object).extend(ClassMethods)
|
30
|
+
_klass.instance_eval do
|
31
|
+
def options
|
32
|
+
{
|
33
|
+
adapter: adapter,
|
34
|
+
primary_id: primary_id,
|
35
|
+
type: type,
|
36
|
+
fields: fields,
|
37
|
+
relations: relations,
|
38
|
+
includes: includes,
|
39
|
+
links: links,
|
40
|
+
metas: metas,
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
subclass.const_set('Collection', _klass)
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_options
|
49
|
+
@_default_options ||= {
|
50
|
+
adapter: [SimpleAMS::Adapters::AMS, {}],
|
51
|
+
primary_id: [:id, {}],
|
52
|
+
type: [_default_type_name, {}]
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
#TODO: Add tests !!
|
57
|
+
def _default_type_name
|
58
|
+
if self.to_s.end_with?('::Collection')
|
59
|
+
_name = self.to_s.gsub(
|
60
|
+
'Serializer',''
|
61
|
+
).gsub(
|
62
|
+
'::Collection', ''
|
63
|
+
).downcase.split('::').last
|
64
|
+
|
65
|
+
return "#{_name}_collection".to_sym
|
66
|
+
else
|
67
|
+
return self.to_s.gsub('Serializer','').downcase.split('::').last.to_sym
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def with_options(options = {})
|
71
|
+
@_options = options
|
72
|
+
meths = SimpleAMS::DSL::ClassMethods.instance_methods(false)
|
73
|
+
@_options.each do |key, value|
|
74
|
+
if key.to_sym == :collection
|
75
|
+
self.send(:collection){}.with_options(value)
|
76
|
+
elsif meths.include?(key)
|
77
|
+
self.send(key, value) if value.is_a?(Array)
|
78
|
+
self.send(key, value)
|
79
|
+
else
|
80
|
+
#TODO: Add a proper logger
|
81
|
+
puts "SimpeAMS: #{key} is not recognized, ignoring (from #{self.to_s})"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return @_options
|
86
|
+
end
|
87
|
+
|
88
|
+
#same for other ValueHashes
|
89
|
+
def adapter(name = nil, options = {})
|
90
|
+
@_adapter ||= default_options[:adapter]
|
91
|
+
return @_adapter if name.nil?
|
92
|
+
|
93
|
+
@_adapter = [name, options]
|
94
|
+
end
|
95
|
+
|
96
|
+
def primary_id(value = nil, options = {})
|
97
|
+
@_primary_id ||= default_options[:primary_id]
|
98
|
+
return @_primary_id if value.nil?
|
99
|
+
|
100
|
+
@_primary_id = [value, options]
|
101
|
+
end
|
102
|
+
|
103
|
+
def type(value = nil, options = {})
|
104
|
+
@_type ||= default_options[:type]
|
105
|
+
return @_type if value.nil?
|
106
|
+
|
107
|
+
@_type = [value, options]
|
108
|
+
end
|
109
|
+
|
110
|
+
def attributes(*args)
|
111
|
+
@_attributes ||= []
|
112
|
+
return @_attributes.uniq if (args&.empty? || args.nil?)
|
113
|
+
|
114
|
+
append_attributes(args)
|
115
|
+
end
|
116
|
+
alias attribute attributes
|
117
|
+
alias fields attributes
|
118
|
+
|
119
|
+
def has_many(name, options = {})
|
120
|
+
append_relationship([__method__, name, options])
|
121
|
+
end
|
122
|
+
|
123
|
+
def has_one(name, options = {})
|
124
|
+
append_relationship([__method__, name, options])
|
125
|
+
end
|
126
|
+
|
127
|
+
def belongs_to(name, options = {})
|
128
|
+
append_relationship([__method__, name, options])
|
129
|
+
end
|
130
|
+
|
131
|
+
def relations
|
132
|
+
@_relations || []
|
133
|
+
end
|
134
|
+
|
135
|
+
#TODO: there is no memoization here, hence we ignore includes manually set !!
|
136
|
+
#Consider fixing it by employing an observer that will clean the instance var
|
137
|
+
#each time @_relations is updated
|
138
|
+
def includes(_ = [])
|
139
|
+
relations.map{|rel| rel[1] }
|
140
|
+
end
|
141
|
+
|
142
|
+
def link(name, value, options = {})
|
143
|
+
append_link([name, value, options])
|
144
|
+
end
|
145
|
+
|
146
|
+
def meta(name = nil, value = nil, options = {})
|
147
|
+
append_meta([name, value, options])
|
148
|
+
end
|
149
|
+
|
150
|
+
def links(links = [])
|
151
|
+
links.map{|key, value| append_link([key, value].flatten(1))} if links.is_a?(Hash)
|
152
|
+
|
153
|
+
@_links ||= links
|
154
|
+
end
|
155
|
+
|
156
|
+
def metas(metas = [])
|
157
|
+
metas.map{|key, value| append_meta([key, value].flatten(1))} if metas.is_a?(Hash)
|
158
|
+
|
159
|
+
@_metas || []
|
160
|
+
end
|
161
|
+
|
162
|
+
def collection(name = nil, &block)
|
163
|
+
if block
|
164
|
+
self::Collection.class_eval do
|
165
|
+
instance_exec(&block)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
self::Collection.type(name) if name
|
170
|
+
|
171
|
+
return self::Collection
|
172
|
+
end
|
173
|
+
|
174
|
+
def options
|
175
|
+
{
|
176
|
+
adapter: adapter,
|
177
|
+
primary_id: primary_id,
|
178
|
+
type: type,
|
179
|
+
fields: fields,
|
180
|
+
relations: relations,
|
181
|
+
includes: includes,
|
182
|
+
links: links,
|
183
|
+
metas: metas,
|
184
|
+
collection: collection
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
def append_relationship(rel)
|
190
|
+
@_relations ||= []
|
191
|
+
|
192
|
+
@_relations << rel
|
193
|
+
end
|
194
|
+
|
195
|
+
def append_attributes(*attrs)
|
196
|
+
@_attributes ||= []
|
197
|
+
|
198
|
+
@_attributes = (@_attributes << attrs).flatten.compact.uniq
|
199
|
+
end
|
200
|
+
|
201
|
+
def append_link(link)
|
202
|
+
@_links ||= []
|
203
|
+
|
204
|
+
@_links << link
|
205
|
+
end
|
206
|
+
|
207
|
+
def append_meta(meta)
|
208
|
+
@_metas ||= []
|
209
|
+
|
210
|
+
@_metas << meta
|
211
|
+
end
|
212
|
+
|
213
|
+
def empty_options
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Options
|
4
|
+
module Concerns
|
5
|
+
#works for arrays that can hold either elements or object that respond_to? :name
|
6
|
+
module Filterable
|
7
|
+
#for optimizing performance, ask only the first element
|
8
|
+
#other idea is to create another module just for (Name)ValueHash objects
|
9
|
+
def &(other_filterables)
|
10
|
+
other_is_object = other_filterables.first.respond_to?(:name)
|
11
|
+
|
12
|
+
return self.class.new(
|
13
|
+
self.select{|m|
|
14
|
+
if other_is_object
|
15
|
+
other_filterables.include?(m.name)
|
16
|
+
else
|
17
|
+
other_filterables.include?(m)
|
18
|
+
end
|
19
|
+
}
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
#for optimizing performance, ask only the first element of self and save it as state
|
24
|
+
def include?(member)
|
25
|
+
unless defined?(@self_is_object)
|
26
|
+
@self_is_object = self.first.respond_to?(:name)
|
27
|
+
end
|
28
|
+
|
29
|
+
if @self_is_object
|
30
|
+
self.map(&:name).include?(member)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def raw
|
37
|
+
if self.first.respond_to?(:raw)
|
38
|
+
self.map(&:raw)
|
39
|
+
else
|
40
|
+
self.map{|i| i}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Options
|
4
|
+
module Concerns
|
5
|
+
module NameValueHash
|
6
|
+
attr_reader :name, :value, :options
|
7
|
+
|
8
|
+
def initialize(name, value, options = {}, resource:)
|
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
|
13
|
+
if _value.is_a?(Array) && _value.length > 1
|
14
|
+
@options = (_value.last || {}).merge(options || {})
|
15
|
+
else
|
16
|
+
@options = options || {}
|
17
|
+
end
|
18
|
+
else
|
19
|
+
@value = value
|
20
|
+
@options = options || {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def raw
|
25
|
+
[name, value, options]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_writer :name, :value, :options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Options
|
4
|
+
module Concerns
|
5
|
+
module ValueHash
|
6
|
+
attr_reader :value, :options
|
7
|
+
|
8
|
+
def initialize(value, options = {})
|
9
|
+
@value = value.is_a?(String) ? value.to_sym : value
|
10
|
+
@options = options.kind_of?(Hash) ? options || {} : options
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :name, :value
|
14
|
+
|
15
|
+
def raw
|
16
|
+
[value, options]
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
attr_writer :value, :options
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "simple_ams"
|
2
|
+
|
3
|
+
class SimpleAMS::Options
|
4
|
+
class Relation
|
5
|
+
attr_reader :type, :name, :options
|
6
|
+
def initialize(type, name, options = {})
|
7
|
+
@type = type.to_sym
|
8
|
+
@name = name.is_a?(String) ? name.to_sym : name
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
@many = type == :has_many ? true : false
|
12
|
+
end
|
13
|
+
|
14
|
+
alias relation name
|
15
|
+
|
16
|
+
def raw
|
17
|
+
[type, name, options]
|
18
|
+
end
|
19
|
+
|
20
|
+
def collection?
|
21
|
+
@many
|
22
|
+
end
|
23
|
+
|
24
|
+
def single?
|
25
|
+
!array
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_writer :type, :name, :options
|
30
|
+
end
|
31
|
+
end
|