json_api_resource 0.4.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 +7 -0
- data/LICENSE +22 -0
- data/README.md +17 -0
- data/Rakefile +12 -0
- data/lib/json_api_resource/cacheable.rb +8 -0
- data/lib/json_api_resource/conversions.rb +75 -0
- data/lib/json_api_resource/queryable.rb +79 -0
- data/lib/json_api_resource/resource.rb +108 -0
- data/lib/json_api_resource/schemable.rb +26 -0
- data/lib/json_api_resource/version.rb +3 -0
- data/lib/json_api_resource.rb +9 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8de53cf54fc4d7b2dac22f9412edab5c7e9f468c
|
4
|
+
data.tar.gz: 6d3d904ef873a695ec4140739de2c89e29523c9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 203292b024a04149a33e06d93bbf0dbe4623c9db4aff903f23d1d2f5a96215879a7c531b962cab75b1b14a1bbf493d0d437a723e0f279e3b539c20e8c758e284
|
7
|
+
data.tar.gz: 94e8199d4670a43fb50a1ef5d2da834ea30822a4f8f617386d3940b1242a4c6868fcd738f573c7b9d8fce3cafe53f7f13185405526de7e7637e58fce4265798f
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Avvo, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# JsonApiResource
|
2
|
+
|
3
|
+
Common code wrapper object or Adapter class to extend a JsonApiClient::Resource
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
### Basic
|
8
|
+
|
9
|
+
```
|
10
|
+
class Customer < JsonApiResource::Resource
|
11
|
+
property :name => 'name', :email => '', :permissions => []
|
12
|
+
api_client Ledger::Client::Customer
|
13
|
+
end
|
14
|
+
|
15
|
+
item = Customer.new
|
16
|
+
#<Customer:0x007f84b7a72568 @client=#<Ledger::Client::Customer:0x007f84b7a71398 @attributes={"id"=>nil, "name"=>"name", "email"=>"", "permissions"=>[]}>>
|
17
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module JsonApiResource
|
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
|
+
def ApiErrors(*args)
|
16
|
+
case args.first
|
17
|
+
when ActiveModel::Errors then args.first
|
18
|
+
when Hash then args.first
|
19
|
+
when Array then { base: args }
|
20
|
+
when String then { base: [args] }
|
21
|
+
else raise TypeError, "Cannot convert #{ args.inspect} to Error"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def Date(*args)
|
26
|
+
case args.first
|
27
|
+
when String then Date.parse(args.first)
|
28
|
+
when Date then args.first
|
29
|
+
else raise TypeError, "Cannot convert #{ args.inspect} to Date"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def DateTime(*args)
|
34
|
+
case args.first
|
35
|
+
when String then DateTime.parse(args.first)
|
36
|
+
when DateTime then args.first
|
37
|
+
else raise TypeError, "Cannot convert #{ args.inspect} to DateTime"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def Boolean(*args)
|
42
|
+
case args.first
|
43
|
+
when FalseClass then args.first
|
44
|
+
when TrueClass then args.first
|
45
|
+
when String
|
46
|
+
if %w(true 1).include?(args.first.downcase)
|
47
|
+
true
|
48
|
+
elsif %w(false 0).include?(args.first.downcase)
|
49
|
+
false
|
50
|
+
else
|
51
|
+
raise TypeError, "Cannot convert #{ args.inspect} to Boolean"
|
52
|
+
end
|
53
|
+
when Integer then args.first != 0
|
54
|
+
else raise TypeError, "Cannot convert #{ args.inspect} to Boolean"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
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
|
+
def ApiResource(klass, *args)
|
66
|
+
case args.first
|
67
|
+
when klass then args.first
|
68
|
+
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) }
|
71
|
+
else raise TypeError, "Cannot convert #{ args.inspect} to #{klass}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module JsonApiResource
|
2
|
+
module Queryable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
attr_accessor :meta
|
6
|
+
attr_accessor :linked_data
|
7
|
+
attr_accessor :errors
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
include JsonApiResource::Conversions
|
12
|
+
|
13
|
+
def find(id)
|
14
|
+
return nil unless id.present?
|
15
|
+
results = self.client_klass.find(id).map! do |result|
|
16
|
+
self.new(:client => result)
|
17
|
+
end
|
18
|
+
results.size == 1 ? single_result(results) : results
|
19
|
+
rescue JsonApiClient::Errors::ServerError => e
|
20
|
+
pretty_error e
|
21
|
+
end
|
22
|
+
|
23
|
+
def create(attr = {})
|
24
|
+
run_callbacks :create do
|
25
|
+
new(:client => self.client_klass.create(attr))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def where(opts = {})
|
30
|
+
opts[:per_page] = opts.fetch(:per_page, self.per_page)
|
31
|
+
(self.client_klass.where(opts).all).map! do |result|
|
32
|
+
self.new(:client => result)
|
33
|
+
end
|
34
|
+
rescue JsonApiClient::Errors::ServerError => e
|
35
|
+
pretty_error e
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# When we return a collection, these extra attributes on top of the result array from JsonApiClient are present.
|
41
|
+
# When we find just one thing and return the first element like ActiveRecord would,
|
42
|
+
# we lose these things. We want them, so we will assign them to this object.
|
43
|
+
def single_result(results)
|
44
|
+
result = results.first
|
45
|
+
|
46
|
+
result.meta = results.meta
|
47
|
+
|
48
|
+
result.linked_data = results.linked_data if results.respond_to? :linked_data
|
49
|
+
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
|
53
|
+
def pretty_error(e)
|
54
|
+
case e.class.to_s
|
55
|
+
|
56
|
+
when 'JsonApiClient::Errors::NotFound'
|
57
|
+
error_response 404, { name: "RecordNotFound", message: e.message }
|
58
|
+
|
59
|
+
when 'JsonApiClient::Errors::UnexpectedStatus'
|
60
|
+
error_response e.code, { name: "UnexpectedStatus", message: e.message }
|
61
|
+
|
62
|
+
else
|
63
|
+
error_response 500, { name: "ServerError", message: e.message }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def error_response(status, error)
|
68
|
+
result = JsonApiClient::ResultSet.new
|
69
|
+
|
70
|
+
result.meta = {status: status}
|
71
|
+
|
72
|
+
result.errors = ActiveModel::Errors.new(result)
|
73
|
+
result.errors.add(error[:name], Array(error[:message]).join(', '))
|
74
|
+
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module JsonApiResource
|
2
|
+
class Resource
|
3
|
+
include ActiveModel::Model
|
4
|
+
include ActiveModel::Validations
|
5
|
+
extend ActiveModel::Callbacks
|
6
|
+
|
7
|
+
include JsonApiResource::Schemable
|
8
|
+
include JsonApiResource::Queryable
|
9
|
+
include JsonApiResource::Conversions
|
10
|
+
include JsonApiResource::Cacheable
|
11
|
+
|
12
|
+
attr_accessor :client, :cache_expires_in
|
13
|
+
class_attribute :client_klass, :per_page
|
14
|
+
|
15
|
+
define_model_callbacks :save, :create, :update_attributes
|
16
|
+
|
17
|
+
around_create :catch_errors
|
18
|
+
around_save :catch_errors
|
19
|
+
around_update_attributes :catch_errors
|
20
|
+
|
21
|
+
def initialize(opts={})
|
22
|
+
self.client = self.client_klass.new(self.schema)
|
23
|
+
self.errors = ActiveModel::Errors.new(self)
|
24
|
+
self.attributes = opts
|
25
|
+
end
|
26
|
+
|
27
|
+
def new_record?
|
28
|
+
self.id.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def persisted?
|
32
|
+
!new_record?
|
33
|
+
end
|
34
|
+
|
35
|
+
def save
|
36
|
+
run_callbacks :save do
|
37
|
+
self.client.save
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_attributes(attrs = {})
|
42
|
+
run_callbacks :update_attributes do
|
43
|
+
self.client.update_attributes(attrs)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes=(attr = {})
|
48
|
+
client_params = attr.delete(:client)
|
49
|
+
if attr.is_a? self.client_klass
|
50
|
+
self.client = attr
|
51
|
+
elsif client_params
|
52
|
+
self.client = client_params
|
53
|
+
else
|
54
|
+
self.client.attributes = attr
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def method_missing(method, *args, &block)
|
61
|
+
if match = method.to_s.match(/^(.*=)$/)
|
62
|
+
self.client.send(match[1], args.first)
|
63
|
+
elsif self.client.respond_to?(method.to_sym)
|
64
|
+
is_method = self.client.methods.include?(method.to_sym)
|
65
|
+
argument_count = (is_method ? self.client.method(method.to_sym).arity : 0)
|
66
|
+
argument_count = args.length if argument_count == -1
|
67
|
+
if (argument_count == 0) || args.blank?
|
68
|
+
self.client.send(method)
|
69
|
+
else
|
70
|
+
self.client.send(method, *args.take(argument_count))
|
71
|
+
end
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def catch_errors
|
78
|
+
yield
|
79
|
+
|
80
|
+
self.errors ||= ActiveModel::Errors.new(self)
|
81
|
+
ApiErrors(self.client.errors).each do | k,messages|
|
82
|
+
self.errors.add(k.to_sym, Array(messages).join(', '))
|
83
|
+
end
|
84
|
+
self.errors
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.method_missing(method, *args, &block)
|
88
|
+
if match = method.to_s.match(/^(.*)=$/)
|
89
|
+
self.client_klass.send(match[1], args.first)
|
90
|
+
|
91
|
+
elsif self.client_klass.respond_to?(method.to_sym)
|
92
|
+
results = self.client_klass.send(method, *args)
|
93
|
+
|
94
|
+
if results.is_a? JsonApiClient::ResultSet
|
95
|
+
results.map! do |result|
|
96
|
+
self.new(:client => result)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
results
|
100
|
+
else
|
101
|
+
super
|
102
|
+
end
|
103
|
+
|
104
|
+
rescue JsonApiClient::Errors::ServerError => e
|
105
|
+
pretty_error e
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JsonApiResource
|
2
|
+
module Schemable
|
3
|
+
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :schema
|
8
|
+
self.schema = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def property(opts = {})
|
13
|
+
opts.each do |attr_name,default|
|
14
|
+
self.schema[attr_name.to_sym] = default || nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def load_schema
|
22
|
+
self.client = self.client_klass.new(self.schema)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'json_api_client'
|
2
|
+
|
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'
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json_api_resource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brandon Sislow
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json_api_client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json_api_client_mock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: webmock
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Wrapper Gem to extend the JsonApiClient::Resource
|
56
|
+
email: brandon.silsow@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- LICENSE
|
62
|
+
- README.md
|
63
|
+
- Rakefile
|
64
|
+
- lib/json_api_resource.rb
|
65
|
+
- lib/json_api_resource/cacheable.rb
|
66
|
+
- lib/json_api_resource/conversions.rb
|
67
|
+
- lib/json_api_resource/queryable.rb
|
68
|
+
- lib/json_api_resource/resource.rb
|
69
|
+
- lib/json_api_resource/schemable.rb
|
70
|
+
- lib/json_api_resource/version.rb
|
71
|
+
homepage: http://gitlab.corp.avvo.com/api/api_resource
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.4.6
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Build wrapper/adapter objects around JsonApiClient instances
|
95
|
+
test_files: []
|
96
|
+
has_rdoc:
|