her 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +2 -2
  3. data/.rspec +1 -2
  4. data/.travis.yml +2 -2
  5. data/README.md +10 -16
  6. data/UPGRADE.md +4 -0
  7. data/examples/grape-and-her/.env.default +3 -0
  8. data/examples/grape-and-her/Procfile +2 -0
  9. data/examples/grape-and-her/README.md +27 -0
  10. data/examples/grape-and-her/api/Gemfile +11 -0
  11. data/examples/grape-and-her/api/Rakefile +14 -0
  12. data/examples/grape-and-her/api/app/api.rb +49 -0
  13. data/examples/grape-and-her/api/app/models/organization.rb +7 -0
  14. data/examples/grape-and-her/api/app/models/user.rb +9 -0
  15. data/examples/grape-and-her/api/app/views/organizations/_base.rabl +2 -0
  16. data/examples/grape-and-her/api/app/views/organizations/index.rabl +3 -0
  17. data/examples/grape-and-her/api/app/views/organizations/show.rabl +3 -0
  18. data/examples/grape-and-her/api/app/views/users/_base.rabl +8 -0
  19. data/examples/grape-and-her/api/app/views/users/index.rabl +3 -0
  20. data/examples/grape-and-her/api/app/views/users/show.rabl +3 -0
  21. data/examples/grape-and-her/api/config.ru +5 -0
  22. data/examples/grape-and-her/api/config/boot.rb +17 -0
  23. data/examples/grape-and-her/api/config/unicorn.rb +7 -0
  24. data/examples/grape-and-her/api/db/migrations/001_create_users.rb +11 -0
  25. data/examples/grape-and-her/api/db/migrations/002_create_organizations.rb +8 -0
  26. data/examples/grape-and-her/consumer/Gemfile +23 -0
  27. data/examples/grape-and-her/consumer/app/assets/stylesheets/application.scss +190 -0
  28. data/examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss +53 -0
  29. data/examples/grape-and-her/consumer/app/consumer.rb +74 -0
  30. data/examples/grape-and-her/consumer/app/models/organization.rb +13 -0
  31. data/examples/grape-and-her/consumer/app/models/user.rb +13 -0
  32. data/examples/grape-and-her/consumer/app/views/index.haml +9 -0
  33. data/examples/grape-and-her/consumer/app/views/layout.haml +20 -0
  34. data/examples/grape-and-her/consumer/app/views/organizations/index.haml +25 -0
  35. data/examples/grape-and-her/consumer/app/views/organizations/show.haml +11 -0
  36. data/examples/grape-and-her/consumer/app/views/users/index.haml +33 -0
  37. data/examples/grape-and-her/consumer/app/views/users/show.haml +9 -0
  38. data/examples/grape-and-her/consumer/config.ru +20 -0
  39. data/examples/grape-and-her/consumer/config/boot.rb +30 -0
  40. data/examples/grape-and-her/consumer/config/unicorn.rb +7 -0
  41. data/examples/grape-and-her/consumer/lib/response_logger.rb +18 -0
  42. data/her.gemspec +2 -2
  43. data/lib/her/model.rb +22 -26
  44. data/lib/her/model/associations.rb +19 -19
  45. data/lib/her/model/attributes.rb +173 -0
  46. data/lib/her/model/base.rb +17 -0
  47. data/lib/her/model/http.rb +58 -242
  48. data/lib/her/model/introspection.rb +7 -8
  49. data/lib/her/model/nested_attributes.rb +3 -3
  50. data/lib/her/model/orm.rb +15 -205
  51. data/lib/her/model/parse.rb +86 -0
  52. data/lib/her/model/paths.rb +54 -14
  53. data/lib/her/version.rb +1 -1
  54. data/spec/model/attributes_spec.rb +139 -0
  55. data/spec/model/dirty_spec.rb +40 -0
  56. data/spec/model/introspection_spec.rb +5 -5
  57. data/spec/model/orm_spec.rb +14 -128
  58. data/spec/model/paths_spec.rb +26 -0
  59. data/spec/model/validations_spec.rb +17 -0
  60. data/spec/spec_helper.rb +7 -32
  61. data/spec/support/extensions/array.rb +5 -0
  62. data/spec/support/extensions/hash.rb +5 -0
  63. data/spec/support/macros/model_macros.rb +29 -0
  64. metadata +52 -15
  65. data/examples/twitter-oauth/Gemfile +0 -13
  66. data/examples/twitter-oauth/app.rb +0 -50
  67. data/examples/twitter-oauth/config.ru +0 -5
  68. data/examples/twitter-oauth/views/index.haml +0 -9
  69. data/examples/twitter-search/Gemfile +0 -12
  70. data/examples/twitter-search/app.rb +0 -55
  71. data/examples/twitter-search/config.ru +0 -5
  72. data/examples/twitter-search/views/index.haml +0 -9
@@ -18,12 +18,12 @@ module Her
18
18
  alias :get_relationship :get_association
19
19
 
20
20
  module ClassMethods
21
- # Return @her_associations, lazily initialized with copy of the
21
+ # Return @_her_associations, lazily initialized with copy of the
22
22
  # superclass' her_associations, or an empty hash.
23
23
  #
24
24
  # @private
25
25
  def associations
26
- @her_associations ||= begin
26
+ @_her_associations ||= begin
27
27
  if superclass.respond_to?(:associations)
28
28
  superclass.associations.dup
29
29
  else
@@ -42,12 +42,12 @@ module Her
42
42
  data_key = association[:data_key]
43
43
  next unless data[data_key]
44
44
 
45
- klass = self.nearby_class(association[:class_name])
45
+ klass = self.her_nearby_class(association[:class_name])
46
46
  name = association[:name]
47
47
 
48
48
  data[name] = case type
49
49
  when :has_many
50
- Her::Model::ORM.initialize_collection(klass, :data => data[data_key])
50
+ Her::Model::Attributes.initialize_collection(klass, :data => data[data_key])
51
51
  when :has_one, :belongs_to
52
52
  klass.new(data[data_key])
53
53
  else
@@ -65,12 +65,12 @@ module Her
65
65
  #
66
66
  # @example
67
67
  # class User
68
- # include Her::API
68
+ # include Her::Model
69
69
  # has_many :articles
70
70
  # end
71
71
  #
72
72
  # class Article
73
- # include Her::API
73
+ # include Her::Model
74
74
  # end
75
75
  #
76
76
  # @user = User.find(1)
@@ -88,13 +88,13 @@ module Her
88
88
 
89
89
  define_method(name) do |*method_attrs|
90
90
  method_attrs = method_attrs[0] || {}
91
- klass = self.class.nearby_class(attrs[:class_name])
91
+ klass = self.class.her_nearby_class(attrs[:class_name])
92
92
 
93
93
  return Her::Collection.new if @attributes.include?(name) && @attributes[name].empty? && method_attrs.empty?
94
94
 
95
95
  if @attributes[name].blank? || method_attrs.any?
96
96
  path = begin
97
- self.class.build_request_path(@attributes.merge(method_attrs))
97
+ request_path(method_attrs)
98
98
  rescue Her::Errors::PathError
99
99
  return nil
100
100
  end
@@ -115,16 +115,16 @@ module Her
115
115
  # Define an *has_one* association.
116
116
  #
117
117
  # @param [Symbol] name The name of the model
118
- # @param [Hash] attrs Options (currently not used)
118
+ # @param [Hash] attrs Options
119
119
  #
120
120
  # @example
121
121
  # class User
122
- # include Her::API
122
+ # include Her::Model
123
123
  # has_one :organization
124
124
  # end
125
125
  #
126
126
  # class Organization
127
- # include Her::API
127
+ # include Her::Model
128
128
  # end
129
129
  #
130
130
  # @user = User.find(1)
@@ -141,13 +141,13 @@ module Her
141
141
 
142
142
  define_method(name) do |*method_attrs|
143
143
  method_attrs = method_attrs[0] || {}
144
- klass = self.class.nearby_class(attrs[:class_name])
144
+ klass = self.class.her_nearby_class(attrs[:class_name])
145
145
 
146
146
  return nil if @attributes.include?(name) && @attributes[name].nil? && method_attrs.empty?
147
147
 
148
148
  if @attributes[name].blank? || method_attrs.any?
149
149
  path = begin
150
- self.class.build_request_path(@attributes.merge(method_attrs))
150
+ request_path(method_attrs)
151
151
  rescue Her::Errors::PathError
152
152
  return nil
153
153
  end
@@ -162,19 +162,19 @@ module Her
162
162
  # Define a *belongs_to* association.
163
163
  #
164
164
  # @param [Symbol] name The name of the model
165
- # @param [Hash] attrs Options (currently not used)
165
+ # @param [Hash] attrs Options
166
166
  #
167
167
  # @example
168
168
  # class User
169
- # include Her::API
169
+ # include Her::Model
170
170
  # belongs_to :team, :class_name => "Group"
171
171
  # end
172
172
  #
173
173
  # class Group
174
- # include Her::API
174
+ # include Her::Model
175
175
  # end
176
176
  #
177
- # @user = User.find(1)
177
+ # @user = User.find(1) # => #<User(users/1) id=1 team_id=2 name="Tobias">
178
178
  # @user.team # => #<Team(teams/2) id=2 name="Developers">
179
179
  # # Fetched via GET "/teams/2"
180
180
  def belongs_to(name, attrs={})
@@ -189,13 +189,13 @@ module Her
189
189
 
190
190
  define_method(name) do |*method_attrs|
191
191
  method_attrs = method_attrs[0] || {}
192
- klass = self.class.nearby_class(attrs[:class_name])
192
+ klass = self.class.her_nearby_class(attrs[:class_name])
193
193
 
194
194
  return nil if @attributes.include?(name) && @attributes[name].nil? && method_attrs.empty?
195
195
 
196
196
  if @attributes[name].blank? || method_attrs.any?
197
197
  path = begin
198
- klass.build_request_path(@attributes.merge(method_attrs.merge(:id => @attributes[attrs[:foreign_key].to_sym])))
198
+ klass.build_request_path(@attributes.merge(method_attrs.merge(klass.primary_key => @attributes[attrs[:foreign_key].to_sym])))
199
199
  rescue Her::Errors::PathError
200
200
  return nil
201
201
  end
@@ -0,0 +1,173 @@
1
+ module Her
2
+ module Model
3
+ # This module handles all methods related to model attributes
4
+ module Attributes
5
+ extend ActiveSupport::Concern
6
+
7
+ attr_accessor :attributes, :metadata, :response_errors
8
+ alias :data :attributes
9
+ alias :data= :attributes=
10
+
11
+ # Initialize a new object with data
12
+ def initialize(attributes={})
13
+ attributes ||= {}
14
+ @metadata = attributes.delete(:_metadata) || {}
15
+ @response_errors = attributes.delete(:_errors) || {}
16
+ @destroyed = attributes.delete(:_destroyed) || false
17
+
18
+ assign_attributes(attributes)
19
+ end
20
+
21
+ # Initialize a collection of resources
22
+ # @private
23
+ def self.initialize_collection(klass, parsed_data={})
24
+ collection_data = parsed_data[:data].map do |item_data|
25
+ resource = klass.new(klass.parse(item_data))
26
+ resource.run_callbacks :find
27
+ resource
28
+ end
29
+ Her::Collection.new(collection_data, parsed_data[:metadata], parsed_data[:errors])
30
+ end
31
+
32
+ # Use setter methods of model for each key / value pair in params
33
+ # Return key / value pairs for which no setter method was defined on the model
34
+ # @private
35
+ def self.use_setter_methods(model, params)
36
+ setter_method_names = model.class.setter_method_names
37
+ params ||= {}
38
+ params.inject({}) do |memo, (key, value)|
39
+ setter_method = key.to_s + '='
40
+ if setter_method_names.include?(setter_method)
41
+ model.send(setter_method, value)
42
+ else
43
+ if key.is_a?(String)
44
+ key = key.to_sym
45
+ end
46
+ memo[key] = value
47
+ end
48
+ memo
49
+ end
50
+ end
51
+
52
+ # Handles missing methods
53
+ # @private
54
+ def method_missing(method, *args, &blk)
55
+ if method.to_s =~ /[?=]$/ || attributes.include?(method)
56
+ # Extract the attribute
57
+ attribute = method.to_s.sub(/[?=]$/, '')
58
+
59
+ # Create a new `attribute` methods set
60
+ self.class.attributes(*attribute)
61
+
62
+ # Resend the method!
63
+ send(method, *args, &blk)
64
+ else
65
+ super
66
+ end
67
+ end
68
+
69
+ # @private
70
+ def respond_to?(method, include_private = false)
71
+ method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || super
72
+ end
73
+
74
+ # @private
75
+ def respond_to_missing?(method, include_private = false)
76
+ method.to_s.end_with?('=') || method.to_s.end_with?('?') || @attributes.include?(method) || @attributes.include?(method) || super
77
+ end
78
+
79
+ # Assign new attributes
80
+ # @private
81
+ def assign_attributes(raw_data)
82
+ @attributes ||= {}
83
+ # Use setter methods first, then translate attributes of associations
84
+ # into association instances, then merge the parsed_data into @attributes.
85
+ unset_attributes = Her::Model::Attributes.use_setter_methods(self, raw_data)
86
+ parsed_attributes = self.class.parse_associations(unset_attributes)
87
+ attributes.update(parsed_attributes)
88
+ end
89
+ alias :update_attributes :assign_attributes
90
+ alias :assign_data :assign_attributes
91
+
92
+ # Handles returning true for the accessible attributes
93
+ # @private
94
+ def has_attribute?(attribute_name)
95
+ attributes.include?(attribute_name)
96
+ end
97
+ alias :has_data? :has_attribute?
98
+
99
+ # Handles returning data for a specific attribute
100
+ # @private
101
+ def get_attribute(attribute_name)
102
+ attributes[attribute_name]
103
+ end
104
+ alias :get_data :get_attribute
105
+
106
+ # Override the method to prevent from returning the object ID
107
+ # @private
108
+ def id
109
+ attributes[self.class.primary_key] || super
110
+ end
111
+
112
+ # Return `true` if the other object is also a Her::Model and has matching data
113
+ # @private
114
+ def ==(other)
115
+ other.is_a?(Her::Model) && attributes == other.attributes
116
+ end
117
+
118
+ # Delegate to the == method
119
+ # @private
120
+ def eql?(other)
121
+ self == other
122
+ end
123
+
124
+ # Delegate to @attributes, allowing models to act correctly in code like:
125
+ # [ Model.find(1), Model.find(1) ].uniq # => [ Model.find(1) ]
126
+ # @private
127
+ def hash
128
+ attributes.hash
129
+ end
130
+
131
+ module ClassMethods
132
+ # Initialize a collection of resources with raw data from an HTTP request
133
+ #
134
+ # @param [Array] parsed_data
135
+ def new_collection(parsed_data)
136
+ Her::Model::Attributes.initialize_collection(self, parsed_data)
137
+ end
138
+
139
+ # Define the attributes that will be used to track dirty attributes and validations
140
+ #
141
+ # @param [Array] attributes
142
+ def attributes(*attributes)
143
+ define_attribute_methods attributes
144
+
145
+ attributes.each do |attribute|
146
+ attribute = attribute.to_sym
147
+
148
+ define_method "#{attribute}".to_sym do
149
+ @attributes.include?(attribute) ? @attributes[attribute] : nil
150
+ end
151
+
152
+ define_method "#{attribute}=".to_sym do |value|
153
+ self.send("#{attribute}_will_change!".to_sym) if @attributes[attribute] != value
154
+ @attributes[attribute] = value
155
+ end
156
+
157
+ define_method "#{attribute}?".to_sym do
158
+ @attributes.include?(attribute) && @attributes[attribute].present?
159
+ end
160
+ end
161
+ end
162
+
163
+ # @private
164
+ def setter_method_names
165
+ @_her_setter_method_names ||= instance_methods.inject(Set.new) do |memo, method_name|
166
+ memo << method_name.to_s if method_name.to_s.end_with?('=')
167
+ memo
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -2,6 +2,23 @@ module Her
2
2
  module Model
3
3
  # This module includes basic functionnality to Her::Model
4
4
  module Base
5
+ extend ActiveSupport::Concern
6
+
7
+ # Returns true if attribute_name is
8
+ # * in resource attributes
9
+ # * an association
10
+ def has_key?(attribute_name)
11
+ has_attribute?(attribute_name) ||
12
+ has_association?(attribute_name)
13
+ end
14
+
15
+ # Returns
16
+ # * the value of the attribute_name attribute if it's in orm data
17
+ # * the resource/collection corrsponding to attribute_name if it's an association
18
+ def [](attribute_name)
19
+ get_attribute(attribute_name) ||
20
+ get_association(attribute_name)
21
+ end
5
22
  end
6
23
  end
7
24
  end
@@ -2,266 +2,82 @@ module Her
2
2
  module Model
3
3
  # This module interacts with Her::API to fetch HTTP data
4
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
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ # Automatically inherit a superclass' api
9
+ def her_api
10
+ @_her_api ||= begin
11
+ if superclass.respond_to?(:her_api)
12
+ superclass.her_api
13
+ else
14
+ Her::API.default_api
15
+ end
12
16
  end
13
17
  end
14
- end
15
18
 
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
- request = her_api.request(attrs)
25
- if block_given?
26
- yield request[:parsed_data], request[:response]
27
- else
28
- { :parsed_data => request[:parsed_data], :response => request[:response] }
19
+ # Link a model with a Her::API object
20
+ def uses_api(api)
21
+ @_her_api = api
29
22
  end
30
- end
31
23
 
32
- # Make a GET request and return either a collection or a resource
33
- #
34
- # @example
35
- # class User
36
- # include Her::Model
37
- # end
38
- #
39
- # @popular_users = User.get(:popular)
40
- # # Fetched via GET "/users/popular"
41
- def get(path, attrs={})
42
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
43
- get_raw(path, attrs) do |parsed_data, response|
44
- if parsed_data[:data].is_a?(Array)
45
- new_collection(parsed_data)
46
- else
47
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
48
- end
49
- end
50
- end
24
+ # Main request wrapper around Her::API. Used to make custom request to the API.
25
+ # @private
26
+ def request(attrs={})
27
+ request = her_api.request(attrs)
51
28
 
52
- # Make a GET request and return the parsed JSON response (not mapped to objects)
53
- def get_raw(path, attrs={}, &block)
54
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
55
- request(attrs.merge(:_method => :get, :_path => path), &block)
56
- end
57
-
58
- # Make a GET request and return a collection of resources
59
- def get_collection(path=nil, attrs={})
60
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
61
- get_raw(path, attrs) do |parsed_data, response|
62
- new_collection(parsed_data)
63
- end
64
- end
65
-
66
- # Make a GET request and return a collection of resources
67
- def get_resource(path, attrs={})
68
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
69
- get_raw(path, attrs) do |parsed_data, response|
70
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
71
- end
72
- end
73
-
74
- # Make a POST request and return either a collection or a resource
75
- def post(path, attrs={})
76
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
77
- post_raw(path, attrs) do |parsed_data, response|
78
- if parsed_data[:data].is_a?(Array)
79
- new_collection(parsed_data)
29
+ if block_given?
30
+ yield request[:parsed_data], request[:response]
80
31
  else
81
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
32
+ { :parsed_data => request[:parsed_data], :response => request[:response] }
82
33
  end
83
34
  end
84
- end
85
35
 
86
- # Make a POST request and return the parsed JSON response (not mapped to objects)
87
- def post_raw(path, attrs={}, &block)
88
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
89
- request(attrs.merge(:_method => :post, :_path => path), &block)
90
- end
91
-
92
- # Make a POST request and return a collection of resources
93
- def post_collection(path, attrs={})
94
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
95
- post_raw(path, attrs) do |parsed_data, response|
96
- new_collection(parsed_data)
97
- end
98
- end
99
-
100
- # Make a POST request and return a collection of resources
101
- def post_resource(path, attrs={})
102
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
103
- post_raw(path, attrs) do |parsed_data, response|
104
- new(parse(parsed_data[:data]))
105
- end
106
- end
107
-
108
- # Make a PUT request and return either a collection or a resource
109
- def put(path, attrs={})
110
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
111
- put_raw(path, attrs) do |parsed_data, response|
112
- if parsed_data[:data].is_a?(Array)
113
- new_collection(parsed_data)
114
- else
115
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
36
+ # For each HTTP method, define these methods:
37
+ #
38
+ # - <method>(path, attrs)
39
+ # - <method>_raw(path, attrs, &block)
40
+ # - <method>_collection(path, attrs, &block)
41
+ # - <method>_resource(path, attrs, &block)
42
+ # - custom_<method>(path, attrs)
43
+ %w{GET POST PUT PATCH DELETE}.map(&:downcase).map(&:to_sym).each do |method|
44
+ define_method method do |path, attrs={}|
45
+ path = build_request_path_from_string_or_symbol(path, attrs)
46
+ send("#{method}_raw".to_sym, path, attrs) do |parsed_data, response|
47
+ if parsed_data[:data].is_a?(Array)
48
+ new_collection(parsed_data)
49
+ else
50
+ new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
51
+ end
52
+ end
116
53
  end
117
- end
118
- end
119
-
120
- # Make a PUT request and return the parsed JSON response (not mapped to objects)
121
- def put_raw(path, attrs={}, &block)
122
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
123
- request(attrs.merge(:_method => :put, :_path => path), &block)
124
- end
125
-
126
- # Make a PUT request and return a collection of resources
127
- def put_collection(path, attrs={})
128
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
129
- put_raw(path, attrs) do |parsed_data, response|
130
- new_collection(parsed_data)
131
- end
132
- end
133
-
134
- # Make a PUT request and return a collection of resources
135
- def put_resource(path, attrs={})
136
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
137
- put_raw(path, attrs) do |parsed_data, response|
138
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
139
- end
140
- end
141
54
 
142
- # Make a PATCH request and return either a collection or a resource
143
- def patch(path, attrs={})
144
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
145
- patch_raw(path, attrs) do |parsed_data, response|
146
- if parsed_data[:data].is_a?(Array)
147
- new_collection(parsed_data)
148
- else
149
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
150
- end
151
- end
152
- end
153
-
154
- # Make a PATCH request and return the parsed JSON response (not mapped to objects)
155
- def patch_raw(path, attrs={}, &block)
156
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
157
- request(attrs.merge(:_method => :patch, :_path => path), &block)
158
- end
159
-
160
- # Make a PATCH request and return a collection of resources
161
- def patch_collection(path, attrs={})
162
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
163
- patch_raw(path, attrs) do |parsed_data, response|
164
- new_collection(parsed_data)
165
- end
166
- end
167
-
168
- # Make a PATCH request and return a collection of resources
169
- def patch_resource(path, attrs={})
170
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
171
- patch_raw(path, attrs) do |parsed_data, response|
172
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
173
- end
174
- end
175
-
176
- # Make a DELETE request and return either a collection or a resource
177
- def delete(path, attrs={})
178
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
179
- delete_raw(path, attrs) do |parsed_data, response|
180
- if parsed_data[:data].is_a?(Array)
181
- new_collection(parsed_data)
182
- else
183
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
184
- end
185
- end
186
- end
187
-
188
- # Make a DELETE request and return the parsed JSON response (not mapped to objects)
189
- def delete_raw(path, attrs={}, &block)
190
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
191
- request(attrs.merge(:_method => :delete, :_path => path), &block)
192
- end
193
-
194
- # Make a DELETE request and return a collection of resources
195
- def delete_collection(path, attrs={})
196
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
197
- delete_raw(path, attrs) do |parsed_data, response|
198
- new_collection(parsed_data)
199
- end
200
- end
201
-
202
- # Make a DELETE request and return a collection of resources
203
- def delete_resource(path, attrs={})
204
- path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
205
- delete_raw(path, attrs) do |parsed_data, response|
206
- new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
207
- end
208
- end
209
-
210
- # Define custom GET requests
211
- #
212
- # @example
213
- # class User
214
- # include Her::Model
215
- # custom_get :popular
216
- # end
217
- #
218
- # User.popular
219
- # # Fetched from GET "/users/popular"
220
- def custom_get(*paths)
221
- metaclass = (class << self; self; end)
222
- paths.each do |path|
223
- metaclass.send(:define_method, path.to_sym) do |*attrs|
224
- get(path, attrs.first || Hash.new)
225
- end
226
- end
227
- end
228
-
229
- # Define custom POST requests
230
- def custom_post(*paths)
231
- metaclass = (class << self; self; end)
232
- paths.each do |path|
233
- metaclass.send(:define_method, path.to_sym) do |*attrs|
234
- post(path, attrs.first || Hash.new)
55
+ define_method "#{method}_raw".to_sym do |path, attrs={}, &block|
56
+ path = build_request_path_from_string_or_symbol(path, attrs)
57
+ request(attrs.merge(:_method => method, :_path => path), &block)
235
58
  end
236
- end
237
- end
238
59
 
239
- # Define custom PUT requests
240
- def custom_put(*paths)
241
- metaclass = (class << self; self; end)
242
- paths.each do |path|
243
- metaclass.send(:define_method, path.to_sym) do |*attrs|
244
- put(path, attrs.first || Hash.new)
60
+ define_method "#{method}_collection".to_sym do |path=nil, attrs={}|
61
+ path = build_request_path_from_string_or_symbol(path, attrs)
62
+ send("#{method}_raw".to_sym, build_request_path_from_string_or_symbol(path, attrs), attrs) do |parsed_data, response|
63
+ new_collection(parsed_data)
64
+ end
245
65
  end
246
- end
247
- end
248
66
 
249
- # Define custom PATCH requests
250
- def custom_patch(*paths)
251
- metaclass = (class << self; self; end)
252
- paths.each do |path|
253
- metaclass.send(:define_method, path.to_sym) do |*attrs|
254
- patch(path, attrs.first || Hash.new)
67
+ define_method "#{method}_resource".to_sym do |path, attrs={}|
68
+ path = build_request_path_from_string_or_symbol(path, attrs)
69
+ send("#{method}_raw".to_sym, path, attrs) do |parsed_data, response|
70
+ new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:metadata], :_errors => parsed_data[:errors])
71
+ end
255
72
  end
256
- end
257
- end
258
73
 
259
- # Define custom DELETE requests
260
- def custom_delete(*paths)
261
- metaclass = (class << self; self; end)
262
- paths.each do |path|
263
- metaclass.send(:define_method, path.to_sym) do |*attrs|
264
- delete(path, attrs.first || Hash.new)
74
+ define_method "custom_#{method}".to_sym do |*paths|
75
+ metaclass = (class << self; self; end)
76
+ paths.each do |path|
77
+ metaclass.send(:define_method, path.to_sym) do |*attrs|
78
+ send(method, path, attrs.first || Hash.new)
79
+ end
80
+ end
265
81
  end
266
82
  end
267
83
  end