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 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,12 @@
1
+ Bundler::GemHelper.install_tasks
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = false
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1,8 @@
1
+ module JsonApiResource
2
+ module Cacheable
3
+ extend ActiveSupport::Concern
4
+ def cache_key
5
+ @cache_key ||= Digest::SHA256.hexdigest(self.to_json)
6
+ end
7
+ end
8
+ end
@@ -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,3 @@
1
+ module JsonApiResource
2
+ VERSION = "0.4.0"
3
+ 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: