extended_her 0.5
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.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CONTRIBUTING.md +26 -0
- data/Gemfile +2 -0
- data/LICENSE +7 -0
- data/README.md +723 -0
- data/Rakefile +11 -0
- data/UPGRADE.md +32 -0
- data/examples/twitter-oauth/Gemfile +13 -0
- data/examples/twitter-oauth/app.rb +50 -0
- data/examples/twitter-oauth/config.ru +5 -0
- data/examples/twitter-oauth/views/index.haml +9 -0
- data/examples/twitter-search/Gemfile +12 -0
- data/examples/twitter-search/app.rb +55 -0
- data/examples/twitter-search/config.ru +5 -0
- data/examples/twitter-search/views/index.haml +9 -0
- data/extended_her.gemspec +27 -0
- data/lib/her.rb +23 -0
- data/lib/her/api.rb +108 -0
- data/lib/her/base.rb +17 -0
- data/lib/her/collection.rb +12 -0
- data/lib/her/errors.rb +5 -0
- data/lib/her/exceptions/exception.rb +4 -0
- data/lib/her/exceptions/record_invalid.rb +8 -0
- data/lib/her/exceptions/record_not_found.rb +13 -0
- data/lib/her/middleware.rb +9 -0
- data/lib/her/middleware/accept_json.rb +15 -0
- data/lib/her/middleware/first_level_parse_json.rb +34 -0
- data/lib/her/middleware/second_level_parse_json.rb +28 -0
- data/lib/her/model.rb +69 -0
- data/lib/her/model/base.rb +7 -0
- data/lib/her/model/hooks.rb +114 -0
- data/lib/her/model/http.rb +284 -0
- data/lib/her/model/introspection.rb +57 -0
- data/lib/her/model/orm.rb +191 -0
- data/lib/her/model/orm/comparison_methods.rb +20 -0
- data/lib/her/model/orm/create_methods.rb +29 -0
- data/lib/her/model/orm/destroy_methods.rb +53 -0
- data/lib/her/model/orm/error_methods.rb +19 -0
- data/lib/her/model/orm/fields_definition.rb +15 -0
- data/lib/her/model/orm/find_methods.rb +46 -0
- data/lib/her/model/orm/persistance_methods.rb +22 -0
- data/lib/her/model/orm/relation_mapper.rb +21 -0
- data/lib/her/model/orm/save_methods.rb +58 -0
- data/lib/her/model/orm/serialization_methods.rb +28 -0
- data/lib/her/model/orm/update_methods.rb +31 -0
- data/lib/her/model/paths.rb +82 -0
- data/lib/her/model/relationships.rb +191 -0
- data/lib/her/paginated_collection.rb +20 -0
- data/lib/her/relation.rb +94 -0
- data/lib/her/version.rb +3 -0
- data/spec/api_spec.rb +131 -0
- data/spec/collection_spec.rb +26 -0
- data/spec/middleware/accept_json_spec.rb +10 -0
- data/spec/middleware/first_level_parse_json_spec.rb +42 -0
- data/spec/middleware/second_level_parse_json_spec.rb +25 -0
- data/spec/model/hooks_spec.rb +406 -0
- data/spec/model/http_spec.rb +184 -0
- data/spec/model/introspection_spec.rb +59 -0
- data/spec/model/orm_spec.rb +552 -0
- data/spec/model/paths_spec.rb +286 -0
- data/spec/model/relationships_spec.rb +222 -0
- data/spec/model_spec.rb +31 -0
- data/spec/spec_helper.rb +46 -0
- metadata +222 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module Her
|
2
|
+
module Middleware
|
3
|
+
# This middleware adds a "Accept: application/json" HTTP header
|
4
|
+
class AcceptJSON < Faraday::Middleware
|
5
|
+
def add_header(headers)
|
6
|
+
headers.merge! "Accept" => "application/json"
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
add_header(env[:request_headers])
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Her
|
2
|
+
module Middleware
|
3
|
+
# This middleware treat the received first-level JSON structure as the resource data.
|
4
|
+
class FirstLevelParseJSON < Faraday::Response::Middleware
|
5
|
+
# Parse the response body
|
6
|
+
#
|
7
|
+
# @param [String] body The response body
|
8
|
+
# @return [Mixed] the parsed response
|
9
|
+
def parse(body)
|
10
|
+
json = MultiJson.load(body, :symbolize_keys => true)
|
11
|
+
errors = json.delete(:errors) || {}
|
12
|
+
metadata = json.delete(:metadata) || []
|
13
|
+
{
|
14
|
+
:data => json,
|
15
|
+
:errors => errors,
|
16
|
+
:metadata => metadata
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
# This method is triggered when the response has been received. It modifies
|
21
|
+
# the value of `env[:body]`.
|
22
|
+
#
|
23
|
+
# @param [Hash] env The response environment
|
24
|
+
def on_complete(env)
|
25
|
+
case env[:status]
|
26
|
+
when 204
|
27
|
+
env[:body] = parse('{}')
|
28
|
+
else
|
29
|
+
env[:body] = parse(env[:body])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Her
|
2
|
+
module Middleware
|
3
|
+
# This middleware expects the resource/collection data to be contained in the `data`
|
4
|
+
# key of the JSON object
|
5
|
+
class SecondLevelParseJSON < Faraday::Response::Middleware
|
6
|
+
# Parse the response body
|
7
|
+
#
|
8
|
+
# @param [String] body The response body
|
9
|
+
# @return [Mixed] the parsed response
|
10
|
+
def parse(body)
|
11
|
+
json = MultiJson.load(body, :symbolize_keys => true)
|
12
|
+
{
|
13
|
+
:data => json[:data],
|
14
|
+
:errors => json[:errors],
|
15
|
+
:metadata => json[:metadata]
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# This method is triggered when the response has been received. It modifies
|
20
|
+
# the value of `env[:body]`.
|
21
|
+
#
|
22
|
+
# @param [Hash] env The response environment
|
23
|
+
def on_complete(env)
|
24
|
+
env[:body] = parse(env[:body])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/her/model.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'her/model/base'
|
2
|
+
require 'her/model/http'
|
3
|
+
require 'her/model/orm/comparison_methods'
|
4
|
+
require 'her/model/orm/create_methods'
|
5
|
+
require 'her/model/orm/destroy_methods'
|
6
|
+
require 'her/model/orm/error_methods'
|
7
|
+
require 'her/model/orm/fields_definition'
|
8
|
+
require 'her/model/orm/find_methods'
|
9
|
+
require 'her/model/orm/persistance_methods'
|
10
|
+
require 'her/model/orm/relation_mapper'
|
11
|
+
require 'her/model/orm/save_methods'
|
12
|
+
require 'her/model/orm/serialization_methods'
|
13
|
+
require 'her/model/orm/update_methods'
|
14
|
+
require 'her/model/orm'
|
15
|
+
require 'her/model/relationships'
|
16
|
+
require 'her/model/hooks'
|
17
|
+
require 'her/model/introspection'
|
18
|
+
require 'her/model/paths'
|
19
|
+
|
20
|
+
module Her
|
21
|
+
# This module is the main element of Her. After creating a Her::API object,
|
22
|
+
# include this module in your models to get a few magic methods defined in them.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# class User
|
26
|
+
# include Her::Model
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @user = User.new(:name => "Rémi")
|
30
|
+
# @user.save
|
31
|
+
module Model
|
32
|
+
extend ActiveSupport::Concern
|
33
|
+
|
34
|
+
# Instance methods
|
35
|
+
include Her::Model::ORM
|
36
|
+
include Her::Model::Introspection
|
37
|
+
include Her::Model::Paths
|
38
|
+
include Her::Model::Relationships
|
39
|
+
|
40
|
+
# Class methods
|
41
|
+
included do
|
42
|
+
extend Her::Model::Base
|
43
|
+
extend Her::Model::HTTP
|
44
|
+
extend Her::Model::Hooks
|
45
|
+
|
46
|
+
# Define default settings
|
47
|
+
root_element name.demodulize.underscore
|
48
|
+
collection_path root_element.pluralize
|
49
|
+
resource_path [collection_path, '/:id'].join
|
50
|
+
uses_api Her::API.default_api
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns true if attribute_name is
|
54
|
+
# * in orm data
|
55
|
+
# * a relationship
|
56
|
+
def has_key?(attribute_name)
|
57
|
+
has_data?(attribute_name) ||
|
58
|
+
has_relationship?(attribute_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns
|
62
|
+
# * the value of the attribute_nane attribute if it's in orm data
|
63
|
+
# * the resource/collection corrsponding to attribute_name if it's a relationship
|
64
|
+
def [](attribute_name)
|
65
|
+
get_data(attribute_name) ||
|
66
|
+
get_relationship(attribute_name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
# Her supports hooks/callbacks that are triggered whenever resources are created, updated or destroyed.
|
4
|
+
#
|
5
|
+
# @example Defining a hook with a block
|
6
|
+
# class User
|
7
|
+
# include Her::Model
|
8
|
+
# before_save { |resource| resource.internal_id = 42 }
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @example Defining a hook with a method name
|
12
|
+
# class User
|
13
|
+
# include Her::Model
|
14
|
+
# before_save :set_internal_id
|
15
|
+
#
|
16
|
+
# private
|
17
|
+
# def set_internal_id
|
18
|
+
# self.internal_id = 42
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
module Hooks
|
22
|
+
# Add a *before save* callback. Triggered before a resource is created or updated.
|
23
|
+
# @param [Symbol, &block] method A method or a block to be called
|
24
|
+
def before_save(method=nil, &block); set_hook(:before, :save, method || block); end
|
25
|
+
|
26
|
+
# Add a *before create* callback. Triggered before a resource is created.
|
27
|
+
# @param [Symbol, &block] method A method or a block to be called
|
28
|
+
def before_create(method=nil, &block); set_hook(:before, :create, method || block); end
|
29
|
+
|
30
|
+
# Add a *before update* callback. Triggered before a resource is updated.
|
31
|
+
# @param [Symbol, &block] method A method or a block to be called
|
32
|
+
def before_update(method=nil, &block); set_hook(:before, :update, method || block); end
|
33
|
+
|
34
|
+
# Add a *before destroy* callback. Triggered before a resource is destroyed.
|
35
|
+
# @param [Symbol, &block] method A method or a block to be called
|
36
|
+
def before_destroy(method=nil, &block); set_hook(:before, :destroy, method || block); end
|
37
|
+
|
38
|
+
# Do not add a *before find* callback. Only *after find* is supported.
|
39
|
+
def before_find(method=nil, &block); raise NoMethodError, "undefined method `before_find' for #{self}"; end
|
40
|
+
|
41
|
+
# Add a *after save* callback. Triggered after a resource is created or updated.
|
42
|
+
# @param [Symbol, &block] method A method or a block to be called
|
43
|
+
def after_save(method=nil, &block); set_hook(:after, :save, method || block); end
|
44
|
+
|
45
|
+
# Add a *after create* callback. Triggered after a resource is created.
|
46
|
+
# @param [Symbol, &block] method A method or a block to be called
|
47
|
+
def after_create(method=nil, &block); set_hook(:after, :create, method || block); end
|
48
|
+
|
49
|
+
# Add a *after update* callback. Triggered after a resource is updated.
|
50
|
+
# @param [Symbol, &block] method A method or a block to be called
|
51
|
+
def after_update(method=nil, &block); set_hook(:after, :update, method || block); end
|
52
|
+
|
53
|
+
# Add a *after destroy* callback. Triggered after a resource is destroyed.
|
54
|
+
# @param [Symbol, &block] method A method or a block to be called
|
55
|
+
def after_destroy(method=nil, &block); set_hook(:after, :destroy, method || block); end
|
56
|
+
|
57
|
+
# Add a *after find* callback. Triggered after a resource is found.
|
58
|
+
# @param [Symbol, &block] method A method or a block to be called
|
59
|
+
def after_find(method=nil, &block); set_hook(:after, :find, method || block); end
|
60
|
+
|
61
|
+
# Wrap a block between “before” and “after” hooks
|
62
|
+
# @private
|
63
|
+
def wrap_in_hooks(resource, *hooks)
|
64
|
+
perform_before_hooks(resource, *hooks)
|
65
|
+
yield(resource, resource.class) if block_given?
|
66
|
+
perform_after_hooks(resource, *hooks.reverse)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @private
|
70
|
+
def hooks
|
71
|
+
@her_hooks ||= begin
|
72
|
+
if superclass.respond_to?(:hooks)
|
73
|
+
superclass.hooks.dup
|
74
|
+
else
|
75
|
+
{}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
# @private
|
82
|
+
def set_hook(time, name, action)
|
83
|
+
(self.hooks["#{time}_#{name}".to_sym] ||= []) << action
|
84
|
+
end
|
85
|
+
|
86
|
+
# @private
|
87
|
+
def perform_hook(record, time, name)
|
88
|
+
Array(self.hooks["#{time}_#{name}".to_sym]).each do |hook|
|
89
|
+
if hook.is_a? Symbol
|
90
|
+
record.send(hook)
|
91
|
+
else
|
92
|
+
hook.call(record)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Perform “after” hooks on a resource
|
98
|
+
# @private
|
99
|
+
def perform_after_hooks(resource, *hooks)
|
100
|
+
hooks.each do |hook|
|
101
|
+
perform_hook(resource, :after, hook)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Perform “before” hooks on a resource
|
106
|
+
# @private
|
107
|
+
def perform_before_hooks(resource, *hooks)
|
108
|
+
hooks.each do |hook|
|
109
|
+
perform_hook(resource, :before, hook)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
# This module interacts with Her::API to fetch HTTP data
|
4
|
+
module HTTP
|
5
|
+
# Automatically inherit a superclass' api
|
6
|
+
def her_api
|
7
|
+
@her_api ||= begin
|
8
|
+
if superclass.respond_to?(:her_api)
|
9
|
+
superclass.her_api
|
10
|
+
else
|
11
|
+
Her::API.default_api
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Link a model with a Her::API object
|
17
|
+
def uses_api(api)
|
18
|
+
@her_api = api
|
19
|
+
end
|
20
|
+
|
21
|
+
# Main request wrapper around Her::API. Used to make custom request to the API.
|
22
|
+
# @private
|
23
|
+
def request(attrs={})
|
24
|
+
initial_attrs = attrs.dup
|
25
|
+
started = Time.now.to_f
|
26
|
+
parsed_data = her_api.request(attrs)
|
27
|
+
request_time = Time.now.to_f - started
|
28
|
+
log(initial_attrs, request_time)
|
29
|
+
|
30
|
+
if block_given?
|
31
|
+
yield parsed_data
|
32
|
+
else
|
33
|
+
parsed_data
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def log(attrs, time)
|
38
|
+
return unless defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger.respond_to?(:debug)
|
39
|
+
|
40
|
+
method = attrs.delete(:_method).to_s.upcase
|
41
|
+
path = attrs.delete(:_path)
|
42
|
+
|
43
|
+
Rails.logger.debug("* HER request: #{method} #{path} [#{time}s] #{attrs}")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Make a GET request and return either a collection or a resource
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# class User
|
50
|
+
# include Her::Model
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# @popular_users = User.get(:popular)
|
54
|
+
# # Fetched via GET "/users/popular"
|
55
|
+
def get(path, attrs={})
|
56
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
57
|
+
get_raw(path, attrs) do |parsed_data|
|
58
|
+
if parsed_data[:data].is_a?(Array)
|
59
|
+
new_collection(parsed_data)
|
60
|
+
else
|
61
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Make a GET request and return the parsed JSON response (not mapped to objects)
|
67
|
+
def get_raw(path, attrs={}, &block)
|
68
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
69
|
+
request(attrs.merge(:_method => :get, :_path => path), &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Make a GET request and return a collection of resources
|
73
|
+
def get_collection(path=nil, attrs={})
|
74
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
75
|
+
get_raw(path, attrs) do |parsed_data|
|
76
|
+
new_collection(parsed_data)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Make a GET request and return a collection of resources
|
81
|
+
def get_resource(path, attrs={})
|
82
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
83
|
+
get_raw(path, attrs) do |parsed_data|
|
84
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Make a POST request and return either a collection or a resource
|
89
|
+
def post(path, attrs={})
|
90
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
91
|
+
post_raw(path, attrs) do |parsed_data|
|
92
|
+
if parsed_data[:data].is_a?(Array)
|
93
|
+
new_collection(parsed_data)
|
94
|
+
else
|
95
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Make a POST request and return the parsed JSON response (not mapped to objects)
|
101
|
+
def post_raw(path, attrs={}, &block)
|
102
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
103
|
+
request(attrs.merge(:_method => :post, :_path => path), &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Make a POST request and return a collection of resources
|
107
|
+
def post_collection(path, attrs={})
|
108
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
109
|
+
post_raw(path, attrs) do |parsed_data|
|
110
|
+
new_collection(parsed_data)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Make a POST request and return a collection of resources
|
115
|
+
def post_resource(path, attrs={})
|
116
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
117
|
+
post_raw(path, attrs) do |parsed_data|
|
118
|
+
new(parse(parsed_data[:data]))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Make a PUT request and return either a collection or a resource
|
123
|
+
def put(path, attrs={})
|
124
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
125
|
+
put_raw(path, attrs) do |parsed_data|
|
126
|
+
if parsed_data[:data].is_a?(Array)
|
127
|
+
new_collection(parsed_data)
|
128
|
+
else
|
129
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Make a PUT request and return the parsed JSON response (not mapped to objects)
|
135
|
+
def put_raw(path, attrs={}, &block)
|
136
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
137
|
+
request(attrs.merge(:_method => :put, :_path => path), &block)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Make a PUT request and return a collection of resources
|
141
|
+
def put_collection(path, attrs={})
|
142
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
143
|
+
put_raw(path, attrs) do |parsed_data|
|
144
|
+
new_collection(parsed_data)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Make a PUT request and return a collection of resources
|
149
|
+
def put_resource(path, attrs={})
|
150
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
151
|
+
put_raw(path, attrs) do |parsed_data|
|
152
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Make a PATCH request and return either a collection or a resource
|
157
|
+
def patch(path, attrs={})
|
158
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
159
|
+
patch_raw(path, attrs) do |parsed_data|
|
160
|
+
if parsed_data[:data].is_a?(Array)
|
161
|
+
new_collection(parsed_data)
|
162
|
+
else
|
163
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Make a PATCH request and return the parsed JSON response (not mapped to objects)
|
169
|
+
def patch_raw(path, attrs={}, &block)
|
170
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
171
|
+
request(attrs.merge(:_method => :patch, :_path => path), &block)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Make a PATCH request and return a collection of resources
|
175
|
+
def patch_collection(path, attrs={})
|
176
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
177
|
+
patch_raw(path, attrs) do |parsed_data|
|
178
|
+
new_collection(parsed_data)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Make a PATCH request and return a collection of resources
|
183
|
+
def patch_resource(path, attrs={})
|
184
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
185
|
+
patch_raw(path, attrs) do |parsed_data|
|
186
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Make a DELETE request and return either a collection or a resource
|
191
|
+
def delete(path, attrs={})
|
192
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
193
|
+
delete_raw(path, attrs) do |parsed_data|
|
194
|
+
if parsed_data[:data].is_a?(Array)
|
195
|
+
new_collection(parsed_data)
|
196
|
+
else
|
197
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Make a DELETE request and return the parsed JSON response (not mapped to objects)
|
203
|
+
def delete_raw(path, attrs={}, &block)
|
204
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
205
|
+
request(attrs.merge(:_method => :delete, :_path => path), &block)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Make a DELETE request and return a collection of resources
|
209
|
+
def delete_collection(path, attrs={})
|
210
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
211
|
+
delete_raw(path, attrs) do |parsed_data|
|
212
|
+
new_collection(parsed_data)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Make a DELETE request and return a collection of resources
|
217
|
+
def delete_resource(path, attrs={})
|
218
|
+
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
219
|
+
delete_raw(path, attrs) do |parsed_data|
|
220
|
+
new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Define custom GET requests
|
225
|
+
#
|
226
|
+
# @example
|
227
|
+
# class User
|
228
|
+
# include Her::Model
|
229
|
+
# custom_get :popular
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# User.popular
|
233
|
+
# # Fetched from GET "/users/popular"
|
234
|
+
def custom_get(*paths)
|
235
|
+
metaclass = (class << self; self; end)
|
236
|
+
paths.each do |path|
|
237
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
238
|
+
get(path, attrs.first || Hash.new)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Define custom POST requests
|
244
|
+
def custom_post(*paths)
|
245
|
+
metaclass = (class << self; self; end)
|
246
|
+
paths.each do |path|
|
247
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
248
|
+
post(path, attrs.first || Hash.new)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Define custom PUT requests
|
254
|
+
def custom_put(*paths)
|
255
|
+
metaclass = (class << self; self; end)
|
256
|
+
paths.each do |path|
|
257
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
258
|
+
put(path, attrs.first || Hash.new)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Define custom PATCH requests
|
264
|
+
def custom_patch(*paths)
|
265
|
+
metaclass = (class << self; self; end)
|
266
|
+
paths.each do |path|
|
267
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
268
|
+
patch(path, attrs.first || Hash.new)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Define custom DELETE requests
|
274
|
+
def custom_delete(*paths)
|
275
|
+
metaclass = (class << self; self; end)
|
276
|
+
paths.each do |path|
|
277
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
278
|
+
delete(path, attrs.first || Hash.new)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|