json_api_resource 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: