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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02a135b8f945df6ce5bc603d613d4e7618f5797c
4
- data.tar.gz: 8a80b4f63e684fec3af33334ed7cc9add21d3201
3
+ metadata.gz: e0b84ed455960e7c9b19f9406984a7dc49f14529
4
+ data.tar.gz: 48ca4c4d21750b579bb7f1498fb6aa1a146bc432
5
5
  SHA512:
6
- metadata.gz: 3aa6e4eef60ce11e7999dc574ffb1f9ad0ea622afbe7aeb4dfe6e037a1b6089adbf667ba08a037cc6649a2aba3741e0a84173499c67880f2c15f0a9a9a97fbed
7
- data.tar.gz: 4e8eb70e130b0168f3b92d65b63c4a44ef11aa4464484cd0581edc1b6ce80c516792e5eeab991fa36ec9721c4d6c24497c2b582922b0e1f12dbfe2e4fa11c49c
6
+ metadata.gz: b7bd2a420c029dbb10e07ef2becf4815c20abd010c2d3ca01edcf044f7ed9b14f2c824316ec21f2b8f3b115e8bcfd1b78fedb10b75717ba8df2cdd2d12d21974
7
+ data.tar.gz: c6fdd4a3987f7772476e693f7def5eff5c081b66dfc5f6656e0b3c9677f0d343c3f4527ffd7959b603d67a9d4521cc76ec1833c39f3f19e4bba8f7fd14da3def
@@ -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][] for [API][]
28
- * TODO: Provide [RSDL][] for [API][]
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/
@@ -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 LD Context:
3
+ %h2 JSON-LD Context:
4
+ %p
5
+ Link:
6
+ %code= link_to(collection_url(format: :jsonld))
4
7
  %pre
5
- %code= resource_serializer.jsonld
8
+ JSON:
9
+ %code= JSON.pretty_generate resource_serializer.jsonld
6
10
 
7
- %h2 Available endpoints:
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 %>
@@ -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
- protected
51
+ module Overrides
52
+ protected
38
53
 
39
- # @return [ActiveModel::Serializer]
40
- def resource_serializer
41
- self.class.resource_serializer
42
- end
54
+ # @return [ActiveModel::Serializer]
55
+ def resource_serializer
56
+ self.class.resource_serializer
57
+ end
43
58
 
44
- # @return [Draper::Decorator]
45
- def resource
46
- get_resource_ivar || set_resource_ivar(super.decorate)
47
- end
59
+ # @return [Draper::Decorator]
60
+ def resource_decorator
61
+ self.class.resource_decorator
62
+ end
48
63
 
49
- # @return [Draper::Decorator]
50
- def build_resource
51
- get_resource_ivar || set_resource_ivar(super.decorate)
52
- end
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
- # @return [Draper::CollectionDecorator]
55
- def collection
56
- get_collection_ivar || set_collection_ivar(super.decorate)
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
- h.polymorphic_url(object.class, format: :jsonld)
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
- attributes :id
7
+ extend ActiveSupport::Concern
8
8
 
9
- XSD_TYPES = Hash.new { |hash, key| hash[key] = "xsd:#{key}"}.merge({
9
+ XSD_TYPES = Hash.new do |hash, key|
10
+ hash[key] = "xsd:#{key}"
11
+ end.merge({
10
12
  })
11
13
 
12
- def self.jsonld_context
13
- {}.tap do |context|
14
- schema[:attributes].each do |name, type|
15
- context[name] = XSD_TYPES[type]
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
- def self.jsonld
21
- {'@context' => jsonld_context.merge(xsd: 'http://www.w3.org/2001/XMLSchema#')}
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
- hash = super
26
- hash['@context'] = object.jsonld_context
27
- hash
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
@@ -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
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+ require 'aepic'
3
+ require 'aepic/concerns/responder'
4
+
5
+ module Aepic
6
+ class Responder < ActionController::Responder
7
+ include Aepic::Concerns::Responder
8
+ end
9
+ end
@@ -17,11 +17,13 @@ module Aepic
17
17
  end
18
18
 
19
19
  def resources
20
- controllers.each do |controller|
21
- if controller.action_methods.include?('index')
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
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+ require 'aepic'
3
+ require 'active_model_serializers'
4
+
5
+ module Aepic
6
+ class Serializer < ActiveModel::Serializer
7
+ include Aepic::Concerns::Serializer
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Aepic
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
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.1
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-04 00:00:00.000000000 Z
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.3
205
+ rubygems_version: 2.0.7
186
206
  signing_key:
187
207
  specification_version: 4
188
208
  summary: Æpic is for your epic APIs