aepic 0.0.1 → 0.0.2
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/.ruby-version +1 -0
- data/README.md +7 -2
- data/aepic.gemspec +1 -0
- data/app/views/application/api.html.haml +7 -3
- data/app/views/application/index.jsonld.erb +1 -0
- data/lib/aepic.rb +8 -0
- data/lib/aepic/concerns/controller.rb +65 -16
- data/lib/aepic/concerns/decorator.rb +11 -1
- data/lib/aepic/concerns/responder.rb +40 -0
- data/lib/aepic/concerns/serializer.rb +34 -12
- data/lib/aepic/engine.rb +21 -0
- data/lib/aepic/responder.rb +9 -0
- data/lib/aepic/schema.rb +6 -4
- data/lib/aepic/serializer.rb +9 -0
- data/lib/aepic/version.rb +1 -1
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0b84ed455960e7c9b19f9406984a7dc49f14529
|
4
|
+
data.tar.gz: 48ca4c4d21750b579bb7f1498fb6aa1a146bc432
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7bd2a420c029dbb10e07ef2becf4815c20abd010c2d3ca01edcf044f7ed9b14f2c824316ec21f2b8f3b115e8bcfd1b78fedb10b75717ba8df2cdd2d12d21974
|
7
|
+
data.tar.gz: c6fdd4a3987f7772476e693f7def5eff5c081b66dfc5f6656e0b3c9677f0d343c3f4527ffd7959b603d67a9d4521cc76ec1833c39f3f19e4bba8f7fd14da3def
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p247
|
data/README.md
CHANGED
@@ -24,8 +24,12 @@ TODO: Write usage instructions here
|
|
24
24
|
## Roadmap
|
25
25
|
|
26
26
|
* TODO: Provide similar Atom-based XML representation
|
27
|
-
* TODO: Provide [WADL][]
|
28
|
-
|
27
|
+
* TODO: Provide [WADL][]
|
28
|
+
|
29
|
+
## Ideas
|
30
|
+
|
31
|
+
* TODO: Provide [Swagger-compatible][Swagger] API description
|
32
|
+
* TODO: Provide [RSDL][]
|
29
33
|
|
30
34
|
## Contributing
|
31
35
|
|
@@ -41,3 +45,4 @@ TODO: Write usage instructions here
|
|
41
45
|
[API]: http://en.wikipedia.org/wiki/Application_programming_interface
|
42
46
|
[WADL]: http://en.wikipedia.org/wiki/WADL
|
43
47
|
[RSDL]: http://en.wikipedia.org/wiki/RSDL
|
48
|
+
[Swagger]: https://developers.helloreverb.com/swagger/
|
data/aepic.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_runtime_dependency 'has_scope'
|
25
25
|
spec.add_runtime_dependency 'responders'
|
26
26
|
spec.add_runtime_dependency 'draper'
|
27
|
+
spec.add_runtime_dependency 'kaminari'
|
27
28
|
|
28
29
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
29
30
|
spec.add_development_dependency 'rake'
|
@@ -1,10 +1,14 @@
|
|
1
1
|
%h1= page_title(resource_class: resource_class.model_name.human)
|
2
2
|
|
3
|
-
%h2 JSON
|
3
|
+
%h2 JSON-LD Context:
|
4
|
+
%p
|
5
|
+
Link:
|
6
|
+
%code= link_to(collection_url(format: :jsonld))
|
4
7
|
%pre
|
5
|
-
|
8
|
+
JSON:
|
9
|
+
%code= JSON.pretty_generate resource_serializer.jsonld
|
6
10
|
|
7
|
-
%h2
|
11
|
+
%h2 Resources:
|
8
12
|
%ul
|
9
13
|
- if controller.respond_to?(:index)
|
10
14
|
%li
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= raw resource_serializer.jsonld.to_json %>
|
data/lib/aepic.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
1
|
require 'aepic/version'
|
2
2
|
require 'active_support'
|
3
|
+
require 'active_support/concern'
|
3
4
|
|
4
5
|
module Aepic
|
5
6
|
extend ActiveSupport::Autoload
|
6
7
|
|
7
8
|
autoload :Controller
|
9
|
+
autoload :Engine
|
8
10
|
autoload :Schema
|
11
|
+
autoload :Responder
|
12
|
+
autoload :Serializer
|
9
13
|
|
10
14
|
module Concerns
|
11
15
|
extend ActiveSupport::Autoload
|
12
16
|
|
13
17
|
autoload :Controller
|
18
|
+
autoload :Decorator
|
19
|
+
autoload :Responder
|
14
20
|
autoload :Serializer
|
15
21
|
end
|
16
22
|
end
|
23
|
+
|
24
|
+
require 'aepic/engine' if defined?(Rails)
|
@@ -2,6 +2,8 @@
|
|
2
2
|
require 'aepic'
|
3
3
|
require 'active_support/concern'
|
4
4
|
require 'inherited_resources'
|
5
|
+
require 'has_scope'
|
6
|
+
require 'kaminari'
|
5
7
|
|
6
8
|
module Aepic
|
7
9
|
module Concerns
|
@@ -10,6 +12,8 @@ module Aepic
|
|
10
12
|
|
11
13
|
included do
|
12
14
|
inherit_resources
|
15
|
+
self.perform_caching = true
|
16
|
+
self.responder = Aepic::Responder
|
13
17
|
|
14
18
|
respond_to :json
|
15
19
|
respond_to :jsonld, only: :index
|
@@ -18,8 +22,13 @@ module Aepic
|
|
18
22
|
ids = ids.to_s.split(',').map { |id| id.to_i }
|
19
23
|
scope.where(id: ids)
|
20
24
|
end
|
25
|
+
|
26
|
+
has_scope :page, only: :index, default: '1'
|
27
|
+
has_scope :per, only: :index
|
21
28
|
helper_method :resource_serializer
|
22
29
|
|
30
|
+
include Overrides
|
31
|
+
|
23
32
|
api_schema << self
|
24
33
|
end
|
25
34
|
|
@@ -29,31 +38,71 @@ module Aepic
|
|
29
38
|
resource_class.active_model_serializer
|
30
39
|
end
|
31
40
|
|
41
|
+
# @return [Draper::Decorator]
|
42
|
+
def resource_decorator
|
43
|
+
"#{resource_class.name}Decorator".safe_constantize
|
44
|
+
end
|
45
|
+
|
32
46
|
def api_schema
|
33
47
|
@api_schema ||= Schema.default
|
34
48
|
end
|
35
49
|
end
|
36
50
|
|
37
|
-
|
51
|
+
module Overrides
|
52
|
+
protected
|
38
53
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
54
|
+
# @return [ActiveModel::Serializer]
|
55
|
+
def resource_serializer
|
56
|
+
self.class.resource_serializer
|
57
|
+
end
|
43
58
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
59
|
+
# @return [Draper::Decorator]
|
60
|
+
def resource_decorator
|
61
|
+
self.class.resource_decorator
|
62
|
+
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
64
|
+
# @return [Draper::Decorator]
|
65
|
+
def resource
|
66
|
+
get_resource_ivar || set_resource_ivar(resource_decorator.decorate(super))
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Draper::Decorator]
|
70
|
+
def build_resource
|
71
|
+
get_resource_ivar || set_resource_ivar(resource_decorator.decorate(super))
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Draper::CollectionDecorator]
|
75
|
+
def collection
|
76
|
+
get_collection_ivar || set_collection_ivar(resource_decorator.decorate_collection(super))
|
77
|
+
end
|
53
78
|
|
54
|
-
|
55
|
-
|
56
|
-
|
79
|
+
# @see http://jsonapi.org/format/
|
80
|
+
# Singular resources are represented as JSON objects.
|
81
|
+
# However, they are still wrapped inside an array:
|
82
|
+
# {"posts": [{ ... }]}
|
83
|
+
# This simplifies processing, as you can know that a resource key
|
84
|
+
# will always be a list.
|
85
|
+
def _render_option_json(resource, options)
|
86
|
+
options[:meta] ||= {}
|
87
|
+
|
88
|
+
etags = combine_etags(resource)
|
89
|
+
key = ActiveSupport::Cache.expand_cache_key(etags)
|
90
|
+
etag = %("#{Digest::MD5.hexdigest(key)}")
|
91
|
+
options[:meta][:etag] = etag
|
92
|
+
|
93
|
+
resource = Array.wrap(resource) unless resource.respond_to?(:length)
|
94
|
+
if resource.respond_to?(:total_count)
|
95
|
+
options[:meta][:total] = resource.total_count
|
96
|
+
end
|
97
|
+
|
98
|
+
json = ActiveModel::Serializer.build_json(self, resource, options)
|
99
|
+
|
100
|
+
if json
|
101
|
+
super(json, options)
|
102
|
+
else
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
57
106
|
end
|
58
107
|
end
|
59
108
|
end
|
@@ -1,10 +1,20 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'aepic'
|
4
|
+
|
3
5
|
module Aepic
|
4
6
|
module Concerns
|
5
7
|
module Decorator
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def jsonld_context
|
12
|
+
@json_context ||= h.polymorphic_url(object_class, format: :jsonld)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
6
16
|
def jsonld_context
|
7
|
-
|
17
|
+
self.class.jsonld_context
|
8
18
|
end
|
9
19
|
end
|
10
20
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'aepic'
|
2
|
+
require 'responders'
|
3
|
+
|
4
|
+
module Aepic
|
5
|
+
module Concerns
|
6
|
+
module Responder
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
include Responders::HttpCacheResponder
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def do_http_cache?
|
14
|
+
get? && (@http_cache != false) && persisted? && resourceful? && resource_item.respond_to?(:updated_at)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Boolean]
|
18
|
+
def do_http_cache!
|
19
|
+
last_modified = resource_item.updated_at
|
20
|
+
etag = resource_collection
|
21
|
+
|
22
|
+
resource_collection.each do |resource|
|
23
|
+
last_modified = resource.updated_at if resource.updated_at > last_modified
|
24
|
+
end if resource_collection.length > 1
|
25
|
+
|
26
|
+
!controller.stale?(etag: etag, last_modified: last_modified)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Array] array of resources
|
30
|
+
def resource_collection
|
31
|
+
@resource_collection ||= resource.is_a?(Array) ? resource : resources
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Object] just one resource
|
35
|
+
def resource_item
|
36
|
+
@resource_item ||= resource.is_a?(Array) ? resource.last : resource
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -4,27 +4,49 @@ require 'aepic'
|
|
4
4
|
module Aepic
|
5
5
|
module Concerns
|
6
6
|
module Serializer
|
7
|
-
|
7
|
+
extend ActiveSupport::Concern
|
8
8
|
|
9
|
-
XSD_TYPES = Hash.new
|
9
|
+
XSD_TYPES = Hash.new do |hash, key|
|
10
|
+
hash[key] = "xsd:#{key}"
|
11
|
+
end.merge({
|
10
12
|
})
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
included { attributes :id }
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def jsonld_context
|
18
|
+
{}.tap do |context|
|
19
|
+
schema[:attributes].each do |name, type|
|
20
|
+
context[name] = XSD_TYPES[type]
|
21
|
+
end
|
22
|
+
schema[:associations].each do |name, type|
|
23
|
+
class_name = name.to_s
|
24
|
+
if class_name =~ /_ids?\Z/
|
25
|
+
context[name] = 'xsd:integer'
|
26
|
+
else
|
27
|
+
class_name = name.to_s.classify
|
28
|
+
associated_class = "#{class_name}Decorator".constantize
|
29
|
+
context[name] = associated_class.jsonld_context
|
30
|
+
end
|
31
|
+
end
|
16
32
|
end
|
17
33
|
end
|
18
|
-
end
|
19
34
|
|
20
|
-
|
21
|
-
|
35
|
+
def jsonld
|
36
|
+
{'@context' => {xsd: 'http://www.w3.org/2001/XMLSchema#'}.merge(jsonld_context)}
|
37
|
+
end
|
22
38
|
end
|
23
39
|
|
40
|
+
#def root_name
|
41
|
+
# self.class._root
|
42
|
+
#end
|
43
|
+
|
24
44
|
def attributes
|
25
|
-
|
26
|
-
|
27
|
-
|
45
|
+
{'@context' => jsonld_context}.merge(super)
|
46
|
+
end
|
47
|
+
|
48
|
+
def jsonld_context
|
49
|
+
object.jsonld_context
|
28
50
|
end
|
29
51
|
end
|
30
52
|
end
|
data/lib/aepic/engine.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'aepic'
|
4
|
+
require 'rails/engine'
|
5
|
+
|
6
|
+
module Aepic
|
7
|
+
class Engine < Rails::Engine
|
8
|
+
initializer 'aepic.mime_types' do
|
9
|
+
# Unable to add Mime type synonym (only extension synonyms supported), so reregister JSON
|
10
|
+
Mime::Type.unregister :json
|
11
|
+
Mime::Type.register 'application/json', :json, %w( text/x-json application/jsonrequest application/vnd.api+json )
|
12
|
+
Mime::Type.register 'application/ld+json', :jsonld
|
13
|
+
|
14
|
+
require 'action_controller/metal/renderers'
|
15
|
+
ActionController::Renderers.add(:jsonld) do |object, options|
|
16
|
+
self.content_type = Mime[:jsonld]
|
17
|
+
object.respond_to?(:jsonld) ? object.jsonld.to_json(options) : object
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/aepic/schema.rb
CHANGED
@@ -17,11 +17,13 @@ module Aepic
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def resources
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
@resources ||=
|
21
|
+
controllers.inject do |resources, controller|
|
22
|
+
if controller.action_methods.include?('index')
|
23
|
+
resources << Resource.new()
|
24
|
+
end
|
25
|
+
resources
|
23
26
|
end
|
24
|
-
end
|
25
27
|
end
|
26
28
|
|
27
29
|
def controllers
|
data/lib/aepic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aepic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Semyonov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: kaminari
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: bundler
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +159,7 @@ extra_rdoc_files: []
|
|
145
159
|
files:
|
146
160
|
- .gitignore
|
147
161
|
- .rspec
|
162
|
+
- .ruby-version
|
148
163
|
- .travis.yml
|
149
164
|
- Gemfile
|
150
165
|
- LICENSE.txt
|
@@ -153,12 +168,17 @@ files:
|
|
153
168
|
- aepic.gemspec
|
154
169
|
- app/views/application/api.html.haml
|
155
170
|
- app/views/application/api.xml.builder
|
171
|
+
- app/views/application/index.jsonld.erb
|
156
172
|
- lib/aepic.rb
|
157
173
|
- lib/aepic/concerns/controller.rb
|
158
174
|
- lib/aepic/concerns/decorator.rb
|
175
|
+
- lib/aepic/concerns/responder.rb
|
159
176
|
- lib/aepic/concerns/serializer.rb
|
160
177
|
- lib/aepic/controller.rb
|
178
|
+
- lib/aepic/engine.rb
|
179
|
+
- lib/aepic/responder.rb
|
161
180
|
- lib/aepic/schema.rb
|
181
|
+
- lib/aepic/serializer.rb
|
162
182
|
- lib/aepic/version.rb
|
163
183
|
- spec/aepic_spec.rb
|
164
184
|
- spec/spec_helper.rb
|
@@ -182,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
202
|
version: '0'
|
183
203
|
requirements: []
|
184
204
|
rubyforge_project:
|
185
|
-
rubygems_version: 2.0.
|
205
|
+
rubygems_version: 2.0.7
|
186
206
|
signing_key:
|
187
207
|
specification_version: 4
|
188
208
|
summary: Æpic is for your epic APIs
|