aepic 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|