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 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