json_api_resource 0.4.9 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86a8a63b0785492a9f4964e23c9a74a06a5bb627
4
- data.tar.gz: 2185bd954e63235cacc9e76d231cb77f5a4c0865
3
+ metadata.gz: 2e08b47087e75a6dcbf21993cca2a1cca415b13e
4
+ data.tar.gz: f8eb103c7b7259c308eb31cca0bfac82b26654e0
5
5
  SHA512:
6
- metadata.gz: f1a7eb2e44dbf6b7ee3d0eb50996f4743b56559596a26794b5ddabbe831d39df684b05670486c3e14e37e5b7ca312382282500fc6dec299233932269770e2184
7
- data.tar.gz: a45673f3cebca622d6a30c26f440f8cd981ad61a7e4a265003a3089d9ae45f9f1012ae9f335d1680a36aaf31b1ce51bcffa9e1074335c243de988b421b9b7e5d
6
+ metadata.gz: 157cab83d13c35c97dceab05d4008a608a029096506812ab20e46506dc52ab13e4b04813f2bc747473589eac70df8ecd6c9472ce5fff9211ecb2820b83f08c2e
7
+ data.tar.gz: 94127db2d17bfb3874cc3c15110e83007d691ae6323026714282f4de9a6598ebe76a22be1f23a78906a502f2ff1b94d014cb3e43fba00f1d5f190924c41b0792
@@ -2,7 +2,7 @@ module JsonApiResource
2
2
  module Cacheable
3
3
  extend ActiveSupport::Concern
4
4
  def cache_key
5
- @cache_key ||= Digest::SHA256.hexdigest(self.attributes.to_s)
5
+ @cache_key ||= Digest::SHA256.hexdigest(self.to_json)
6
6
  end
7
7
  end
8
8
  end
@@ -0,0 +1,16 @@
1
+ module JsonApiResource
2
+ module Clientable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :client_class
7
+ self.client_class = nil
8
+
9
+ class << self
10
+ def wraps(client)
11
+ self.client_class = client
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,23 +1,12 @@
1
1
  module JsonApiResource
2
2
  module Conversions
3
- def Address(*args)
4
- case args.first
5
- when Address then args.first
6
- when Hash then Address.new(args.first)
7
- when Address.client then Address.new(args.first.attributes)
8
- when Array then args.first.map { |attr| Address(attr) }
9
- when Integer then Address.new(* args)
10
- when String then Address.new(* args.first.split(':'). map(&:to_i))
11
- else raise TypeError, "Cannot convert #{ args.inspect} to Address"
12
- end
13
- end
14
-
15
3
  def ApiErrors(*args)
16
4
  case args.first
17
5
  when ActiveModel::Errors then args.first
18
6
  when Hash then args.first
19
7
  when Array then { base: args }
20
8
  when String then { base: [args] }
9
+ when NilClass then { base: [[]]}
21
10
  else raise TypeError, "Cannot convert #{ args.inspect} to Error"
22
11
  end
23
12
  end
@@ -55,19 +44,12 @@ module JsonApiResource
55
44
  end
56
45
  end
57
46
 
58
- def Symbolize(*args)
59
- case args.first
60
- when String then args.first.underscore.parameterize('_').to_sym
61
- else args.first
62
- end
63
- end
64
-
65
47
  def ApiResource(klass, *args)
66
48
  case args.first
67
49
  when klass then args.first
68
50
  when Hash then klass.new(args.first)
69
- when klass.client then klass.new(args.first.attributes)
70
- when Array then args.first.map { |attr| JsonApiResource(attr, klass) }
51
+ when klass.client_class then klass.new(args.first.attributes)
52
+ when Array then args.first.map { |attr| ApiResource(klass, attr) }
71
53
  else raise TypeError, "Cannot convert #{ args.inspect} to #{klass}"
72
54
  end
73
55
  end
@@ -0,0 +1,15 @@
1
+ module JsonApiResource
2
+ module Handlers
3
+ class FindHandler
4
+ attr_accessor :result
5
+
6
+ def initialize(results)
7
+ self.result = results.first
8
+
9
+ self.result.meta = results.meta
10
+
11
+ self.result.linked_data = results.try(:linked_data)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module JsonApiResource
2
+ module Handlers
3
+ autoload :FindHandler, 'json_api_resource/handlers/find_handler'
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module JsonApiResource
2
+ class JsonApiResourceError < StandardError
3
+ def initialize(opts = {})
4
+ @klass = opts.fetch :class, JsonApiResource::Resource
5
+ @message = opts.fetch :message, ""
6
+ end
7
+
8
+ def message
9
+ "#{@klass}: #{@message}"
10
+ end
11
+ end
12
+ end
@@ -2,91 +2,48 @@ module JsonApiResource
2
2
  module Queryable
3
3
  extend ActiveSupport::Concern
4
4
 
5
- attr_accessor :meta
6
- attr_accessor :linked_data
7
- attr_accessor :errors
5
+ included do
8
6
 
9
- MAX_PAGES_FOR_ALL = 25
7
+ define_model_callbacks :save, :update_attributes
10
8
 
11
- module ClassMethods
9
+ around_save :catch_errors
10
+ around_update_attributes :catch_errors
12
11
 
13
- include JsonApiResource::Conversions
12
+ class << self
14
13
 
15
- def find(id)
16
- return nil unless id.present?
17
- results = self.client_klass.find(id).map! do |result|
18
- self.new(:client => result)
19
- end
20
- results.size == 1 ? single_result(results) : results
21
- rescue JsonApiClient::Errors::ServerError => e
22
- pretty_error e
23
- end
14
+ MAX_PAGES_FOR_ALL = 25
24
15
 
25
- def create(attr = {})
26
- new(:client => self.client_klass.create(attr)).save
27
- end
16
+ def find(id)
17
+ return nil unless id.present?
28
18
 
29
- def where(opts = {})
30
- opts[:per_page] = opts.fetch(:per_page, self.per_page) if self.per_page
31
- (self.client_klass.where(opts).all).map! do |result|
32
- self.new(:client => result)
19
+ results = request(:find, id: id)
20
+ JsonApiResource::Handlers::FindHandler.new(results).result # <= <#JsonApiclient::ResultSet @errors => <...>, @data => <...>, @linked_data => <...>>
33
21
  end
34
- rescue JsonApiClient::Errors::ServerError => e
35
- pretty_error e
36
- end
37
22
 
38
- def all_without_pagination(opts = {})
39
- page_total = 1
40
- current_page = 1
41
- all_results = []
42
- until (current_page > page_total) || (current_page > MAX_PAGES_FOR_ALL)
43
- page_of_results = where({:page => current_page}.merge(opts))
44
- all_results << page_of_results
45
- page_total = page_of_results.meta[:total_pages] || 1
46
- current_page = current_page + 1
23
+ def where(opts = {})
24
+ opts[:per_page] = opts.fetch(:per_page, self.per_page)
25
+ request(:where, opts)
47
26
  end
48
- JsonApiClient::ResultSet.new(all_results.flatten.compact)
49
27
  end
50
28
 
51
- private
52
-
53
- # When we return a collection, these extra attributes on top of the result array from JsonApiClient are present.
54
- # When we find just one thing and return the first element like ActiveRecord would,
55
- # we lose these things. We want them, so we will assign them to this object.
56
- def single_result(results)
57
- result = results.first
58
-
59
- result.meta = results.meta
60
-
61
- result.linked_data = results.linked_data if results.respond_to? :linked_data
62
-
63
- return result
29
+
30
+ def save
31
+ request :save
64
32
  end
65
33
 
66
- def pretty_error(e)
67
- case e.class.to_s
68
-
69
- when 'JsonApiClient::Errors::NotFound'
70
- error_response 404, { name: "RecordNotFound", message: e.message }
71
-
72
- when 'JsonApiClient::Errors::UnexpectedStatus'
73
- error_response e.code, { name: "UnexpectedStatus", message: e.message }
74
-
75
- else
76
- error_response 500, { name: "ServerError", message: e.message }
77
- end
34
+ def update_attributes(attrs = {})
35
+ request :update_attributes, attrs
78
36
  end
79
37
 
80
- def error_response(status, error)
81
- result = JsonApiClient::ResultSet.new
38
+ def catch_errors
39
+ yield
82
40
 
83
- result.meta = {status: status}
84
-
85
- result.errors = ActiveModel::Errors.new(result)
86
- result.errors.add(error[:name], Array(error[:message]).join(', '))
87
-
88
- result
41
+ self.errors ||= ActiveModel::Errors.new(self)
42
+ ApiErrors(self.client.errors).each do | k,messages|
43
+ self.errors.add(k.to_sym, Array(messages).join(', '))
44
+ end
45
+ self.errors
89
46
  end
90
47
  end
91
48
  end
92
- end
49
+ end
@@ -0,0 +1,72 @@
1
+ module JsonApiResource
2
+ module Requestable
3
+ extend ActiveModel::Callbacks
4
+ extend ActiveSupport::Concern
5
+ extend ActiveSupport::Callbacks
6
+
7
+ included do
8
+ def request(action, *args)
9
+ run_callbacks action do
10
+ self.client.send(action, *args)
11
+ end
12
+ self
13
+
14
+ rescue JsonApiClient::Errors::ServerError => e
15
+ add_error e
16
+ end
17
+
18
+ class << self
19
+ def request(action, *args)
20
+ result = self.client_class.send(action, *args)
21
+
22
+ result = result.all if result.is_a? JsonApiClient::Scope
23
+
24
+ JsonApiClient::ResultSet.new(
25
+ result.map do |result|
26
+ new(client: result)
27
+ end
28
+ )
29
+ rescue JsonApiClient::Errors::ServerError => e
30
+ empty_set_with_errors e
31
+ end
32
+
33
+ def empty_set_with_errors(e)
34
+ append_errors e do |status, error|
35
+ error_response status, error
36
+ end
37
+ end
38
+
39
+ def append_errors(e, &block)
40
+ case e.class.to_s
41
+
42
+ when "JsonApiClient::Errors::NotFound"
43
+ yield 404, { name: "RecordNotFound", message: e.message }
44
+
45
+ when "JsonApiClient::Errors::UnexpectedStatus"
46
+ yield e.code, { name: "UnexpectedStatus", message: e.message }
47
+
48
+ else
49
+ yield 500, { name: "ServerError", message: e.message }
50
+ end
51
+ end
52
+
53
+ def error_response(status, error)
54
+ result = JsonApiClient::ResultSet.new
55
+
56
+ result.meta = {status: status}
57
+
58
+ result.errors = ActiveModel::Errors.new(result)
59
+ result.errors.add(error[:name], Array(error[:message]).join(', '))
60
+
61
+ result
62
+ end
63
+ end
64
+
65
+ def add_error(e, &block)
66
+ self.class.append_errors e do |status, error|
67
+ errors.add error[:name], error[:message]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,24 +1,37 @@
1
+ require 'active_support'
2
+ require 'active_support/callbacks'
3
+ require 'active_support/concern'
4
+ require 'active_support/core_ext/module'
5
+ require 'active_support/core_ext/class/attribute'
6
+ require 'active_model'
7
+ require 'active_model/model'
8
+ require 'active_model/validations'
9
+ require 'active_model/callbacks'
10
+
1
11
  module JsonApiResource
2
12
  class Resource
3
13
  include ActiveModel::Model
4
14
  include ActiveModel::Validations
5
15
  extend ActiveModel::Callbacks
6
16
 
17
+ extend ActiveSupport::Callbacks
18
+
19
+ include JsonApiResource::Clientable
7
20
  include JsonApiResource::Schemable
8
21
  include JsonApiResource::Queryable
22
+ include JsonApiResource::Requestable
9
23
  include JsonApiResource::Conversions
10
24
  include JsonApiResource::Cacheable
11
25
 
12
26
  attr_accessor :client, :cache_expires_in
13
- class_attribute :client_klass, :per_page
14
-
15
- define_model_callbacks :save, :update_attributes
27
+ class_attribute :per_page
16
28
 
17
- around_save :update_meta
18
- around_update_attributes :update_meta
29
+ delegate :to_json, to: :attributes
19
30
 
20
31
  def initialize(opts={})
21
- self.client = self.client_klass.new(self.schema)
32
+ raise( JsonApiResourceError, class: self.class, message: "A resource must have a client class" ) unless client_class.present?
33
+
34
+ self.client = self.client_class.new(self.schema)
22
35
  self.errors = ActiveModel::Errors.new(self)
23
36
  self.attributes = opts
24
37
  end
@@ -31,25 +44,9 @@ module JsonApiResource
31
44
  !new_record?
32
45
  end
33
46
 
34
- def save
35
- run_callbacks :save do
36
- self.client.save
37
- end
38
- rescue JsonApiClient::Errors::ServerError => e
39
- pretty_error e
40
- end
41
-
42
- def update_attributes(attrs = {})
43
- run_callbacks :update_attributes do
44
- self.client.update_attributes(attrs)
45
- end
46
- rescue JsonApiClient::Errors::ServerError => e
47
- pretty_error e
48
- end
49
-
50
47
  def attributes=(attr = {})
51
48
  client_params = attr.delete(:client)
52
- if attr.is_a? self.client_klass
49
+ if attr.is_a? self.client_class
53
50
  self.client = attr
54
51
  elsif client_params
55
52
  self.client = client_params
@@ -62,55 +59,41 @@ module JsonApiResource
62
59
 
63
60
  def method_missing(method, *args, &block)
64
61
  if match = method.to_s.match(/^(.*=)$/)
65
- self.client.send(match[1], args.first)
62
+ self.client.send(match[0], args.first)
66
63
  elsif self.client.respond_to?(method.to_sym)
67
- is_method = self.client.methods.include?(method.to_sym)
68
- argument_count = (is_method ? self.client.method(method.to_sym).arity : 0)
69
- argument_count = args.length if argument_count == -1
70
- if (argument_count == 0) || args.blank?
71
- self.client.send(method)
72
- else
73
- self.client.send(method, *args.take(argument_count))
74
- end
64
+ self.client.send(method, *args)
75
65
  else
76
66
  super
77
67
  end
78
68
 
79
69
  rescue JsonApiClient::Errors::ServerError => e
80
- pretty_error e
81
- end
82
-
83
- def update_meta
84
- yield
85
-
86
- self.errors ||= ActiveModel::Errors.new(self)
87
- ApiErrors(self.client.errors).each do | k,messages|
88
- self.errors.add(k.to_sym, Array(messages).join(', '))
89
- end
90
- self.errors
91
-
92
- self.meta = self.client.last_request_meta
70
+ add_error e
71
+ rescue ArgumentError => e
72
+ raise JsonApiResourceError, class: self.class, message: "#{method}: #{e.message}"
93
73
  end
94
74
 
95
75
  def self.method_missing(method, *args, &block)
96
76
  if match = method.to_s.match(/^(.*)=$/)
97
- self.client_klass.send(match[1], args.first)
98
-
99
- elsif self.client_klass.respond_to?(method.to_sym)
100
- results = self.client_klass.send(method, *args)
77
+ self.client_class.send(match[0], args.first)
78
+
79
+ elsif self.client_class.respond_to?(method.to_sym)
80
+ results = self.client_class.send(method, *args)
101
81
 
102
82
  if results.is_a? JsonApiClient::ResultSet
103
- results.map! do |result|
83
+ results = results.map do |result|
104
84
  self.new(:client => result)
105
85
  end
106
86
  end
87
+
107
88
  results
89
+
108
90
  else
109
91
  super
110
92
  end
111
-
112
93
  rescue JsonApiClient::Errors::ServerError => e
113
- pretty_error e
94
+ empty_set_with_errors e
95
+ rescue ArgumentError => e
96
+ raise JsonApiResourceError, class: self, message: "#{method}: #{e.message}"
114
97
  end
115
98
 
116
99
  def respond_to_missing?(method_name, include_private = false)
@@ -118,7 +101,7 @@ module JsonApiResource
118
101
  end
119
102
 
120
103
  def self.respond_to_missing?(method_name, include_private = false)
121
- client_klass.respond_to?(method_name.to_sym) || super
104
+ client_class.respond_to?(method_name.to_sym) || super
122
105
  end
123
106
  end
124
107
  end
@@ -6,21 +6,19 @@ module JsonApiResource
6
6
  included do
7
7
  class_attribute :schema
8
8
  self.schema = {}
9
- end
9
+
10
+ class << self
11
+ def properties(opts = {})
12
+ self.schema = schema.dup
13
+ opts.each_pair do |name, default|
14
+ property name, default
15
+ end
16
+ end
10
17
 
11
- module ClassMethods
12
- def property(opts = {})
13
- opts.each do |attr_name,default|
14
- self.schema[attr_name.to_sym] = default || nil
18
+ def property(name, default = nil)
19
+ self.schema = schema.merge name.to_sym => default
15
20
  end
16
21
  end
17
22
  end
18
-
19
- protected
20
-
21
- def load_schema
22
- self.client = self.client_klass.new(self.schema)
23
- end
24
-
25
23
  end
26
24
  end
@@ -1,3 +1,3 @@
1
1
  module JsonApiResource
2
- VERSION = "0.4.9"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,9 +1,13 @@
1
1
  require 'json_api_client'
2
2
 
3
3
  module JsonApiResource
4
- autoload :Conversions, 'json_api_resource/conversions'
5
- autoload :Queryable, 'json_api_resource/queryable'
6
- autoload :Schemable, 'json_api_resource/schemable'
7
- autoload :Resource, 'json_api_resource/resource'
8
- autoload :Cacheable, 'json_api_resource/cacheable'
4
+ autoload :Cacheable, 'json_api_resource/cacheable'
5
+ autoload :Clientable, 'json_api_resource/clientable'
6
+ autoload :Conversions, 'json_api_resource/conversions'
7
+ autoload :Handlers, 'json_api_resource/handlers'
8
+ autoload :JsonApiResourceError, 'json_api_resource/json_api_resource_error'
9
+ autoload :Queryable, 'json_api_resource/queryable'
10
+ autoload :Resource, 'json_api_resource/resource'
11
+ autoload :Requestable, 'json_api_resource/requestable'
12
+ autoload :Schemable, 'json_api_resource/schemable'
9
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_api_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Sislow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-13 00:00:00.000000000 Z
11
+ date: 2016-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json_api_client
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: webmock
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -63,12 +91,17 @@ files:
63
91
  - Rakefile
64
92
  - lib/json_api_resource.rb
65
93
  - lib/json_api_resource/cacheable.rb
94
+ - lib/json_api_resource/clientable.rb
66
95
  - lib/json_api_resource/conversions.rb
96
+ - lib/json_api_resource/handlers.rb
97
+ - lib/json_api_resource/handlers/find_handler.rb
98
+ - lib/json_api_resource/json_api_resource_error.rb
67
99
  - lib/json_api_resource/queryable.rb
100
+ - lib/json_api_resource/requestable.rb
68
101
  - lib/json_api_resource/resource.rb
69
102
  - lib/json_api_resource/schemable.rb
70
103
  - lib/json_api_resource/version.rb
71
- homepage: http://gitlab.corp.avvo.com/api/api_resource
104
+ homepage: https://github.com/avvo/json_api_resource
72
105
  licenses:
73
106
  - MIT
74
107
  metadata: {}
@@ -88,8 +121,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
121
  version: '0'
89
122
  requirements: []
90
123
  rubyforge_project:
91
- rubygems_version: 2.4.6
124
+ rubygems_version: 2.4.5
92
125
  signing_key:
93
126
  specification_version: 4
94
127
  summary: Build wrapper/adapter objects around JsonApiClient instances
95
128
  test_files: []
129
+ has_rdoc: