her 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/README.md +83 -37
- data/Rakefile +0 -1
- data/UPGRADE.md +13 -13
- data/examples/twitter-oauth/app.rb +6 -5
- data/examples/twitter-search/app.rb +10 -8
- data/her.gemspec +13 -13
- data/lib/her.rb +7 -4
- data/lib/her/api.rb +20 -12
- data/lib/her/collection.rb +12 -0
- data/lib/her/middleware.rb +4 -3
- data/lib/her/middleware/accept_json.rb +15 -0
- data/lib/her/model.rb +8 -8
- data/lib/her/model/hooks.rb +24 -0
- data/lib/her/model/http.rb +19 -19
- data/lib/her/model/orm.rb +59 -46
- data/lib/her/model/relationships.rb +40 -27
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +41 -15
- data/spec/middleware/accept_json_spec.rb +10 -0
- data/spec/model/hooks_spec.rb +7 -7
- data/spec/model/http_spec.rb +44 -59
- data/spec/model/introspection_spec.rb +6 -5
- data/spec/model/orm_spec.rb +128 -23
- data/spec/model/paths_spec.rb +8 -10
- data/spec/model/relationships_spec.rb +54 -10
- data/spec/spec_helper.rb +0 -1
- metadata +59 -69
data/lib/her/middleware.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
require "her/middleware/first_level_parse_json"
|
2
|
+
require "her/middleware/second_level_parse_json"
|
3
|
+
require "her/middleware/accept_json"
|
4
|
+
|
1
5
|
module Her
|
2
6
|
module Middleware
|
3
|
-
autoload :FirstLevelParseJSON, "her/middleware/first_level_parse_json"
|
4
|
-
autoload :SecondLevelParseJSON, "her/middleware/second_level_parse_json"
|
5
|
-
|
6
7
|
DefaultParseJSON = FirstLevelParseJSON
|
7
8
|
end
|
8
9
|
end
|
@@ -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
|
data/lib/her/model.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
require "her/model/base"
|
2
|
+
require "her/model/http"
|
3
|
+
require "her/model/orm"
|
4
|
+
require "her/model/relationships"
|
5
|
+
require "her/model/hooks"
|
6
|
+
require "her/model/introspection"
|
7
|
+
require "her/model/paths"
|
8
|
+
|
1
9
|
module Her
|
2
10
|
# This module is the main element of Her. After creating a Her::API object,
|
3
11
|
# include this module in your models to get a few magic methods defined in them.
|
@@ -10,14 +18,6 @@ module Her
|
|
10
18
|
# @user = User.new(:name => "Rémi")
|
11
19
|
# @user.save
|
12
20
|
module Model
|
13
|
-
autoload :Base, "her/model/base"
|
14
|
-
autoload :HTTP, "her/model/http"
|
15
|
-
autoload :ORM, "her/model/orm"
|
16
|
-
autoload :Relationships, "her/model/relationships"
|
17
|
-
autoload :Hooks, "her/model/hooks"
|
18
|
-
autoload :Introspection, "her/model/introspection"
|
19
|
-
autoload :Paths, "her/model/paths"
|
20
|
-
|
21
21
|
extend ActiveSupport::Concern
|
22
22
|
|
23
23
|
# Instance methods
|
data/lib/her/model/hooks.rb
CHANGED
@@ -51,6 +51,14 @@ module Her
|
|
51
51
|
# @param [Symbol, &block] method A method or a block to be called
|
52
52
|
def after_destroy(method=nil, &block); set_hook(:after, :destroy, method || block); end
|
53
53
|
|
54
|
+
# Wrap a block between “before” and “after” hooks
|
55
|
+
# @private
|
56
|
+
def wrap_in_hooks(resource, *hooks) # {{{
|
57
|
+
perform_before_hooks(resource, *hooks)
|
58
|
+
yield(resource, resource.class)
|
59
|
+
perform_after_hooks(resource, *hooks.reverse)
|
60
|
+
end # }}}
|
61
|
+
|
54
62
|
private
|
55
63
|
# @private
|
56
64
|
def hooks # {{{
|
@@ -75,6 +83,22 @@ module Her
|
|
75
83
|
end
|
76
84
|
end
|
77
85
|
end # }}}
|
86
|
+
|
87
|
+
# Perform “after” hooks on a resource
|
88
|
+
# @private
|
89
|
+
def perform_after_hooks(resource, *hooks) # {{{
|
90
|
+
hooks.each do |hook|
|
91
|
+
perform_hook(resource, :after, hook)
|
92
|
+
end
|
93
|
+
end # }}}
|
94
|
+
|
95
|
+
# Perform “before” hooks on a resource
|
96
|
+
# @private
|
97
|
+
def perform_before_hooks(resource, *hooks) # {{{
|
98
|
+
hooks.each do |hook|
|
99
|
+
perform_hook(resource, :before, hook)
|
100
|
+
end
|
101
|
+
end # }}}
|
78
102
|
end
|
79
103
|
end
|
80
104
|
end
|
data/lib/her/model/http.rb
CHANGED
@@ -26,9 +26,9 @@ module Her
|
|
26
26
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
27
27
|
get_raw(path, attrs) do |parsed_data|
|
28
28
|
if parsed_data[:data].is_a?(Array)
|
29
|
-
new_collection(parsed_data
|
29
|
+
new_collection(parsed_data)
|
30
30
|
else
|
31
|
-
new(parsed_data[:data])
|
31
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end # }}}
|
@@ -43,7 +43,7 @@ module Her
|
|
43
43
|
def get_collection(path, attrs={}) # {{{
|
44
44
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
45
45
|
get_raw(path, attrs) do |parsed_data|
|
46
|
-
new_collection(parsed_data
|
46
|
+
new_collection(parsed_data)
|
47
47
|
end
|
48
48
|
end # }}}
|
49
49
|
|
@@ -51,7 +51,7 @@ module Her
|
|
51
51
|
def get_resource(path, attrs={}) # {{{
|
52
52
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
53
53
|
get_raw(path, attrs) do |parsed_data|
|
54
|
-
new(parsed_data[:data])
|
54
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
55
55
|
end
|
56
56
|
end # }}}
|
57
57
|
|
@@ -60,9 +60,9 @@ module Her
|
|
60
60
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
61
61
|
post_raw(path, attrs) do |parsed_data|
|
62
62
|
if parsed_data[:data].is_a?(Array)
|
63
|
-
new_collection(parsed_data
|
63
|
+
new_collection(parsed_data)
|
64
64
|
else
|
65
|
-
new(parsed_data[:data])
|
65
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end # }}}
|
@@ -77,7 +77,7 @@ module Her
|
|
77
77
|
def post_collection(path, attrs={}) # {{{
|
78
78
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
79
79
|
post_raw(path, attrs) do |parsed_data|
|
80
|
-
new_collection(parsed_data
|
80
|
+
new_collection(parsed_data)
|
81
81
|
end
|
82
82
|
end # }}}
|
83
83
|
|
@@ -94,9 +94,9 @@ module Her
|
|
94
94
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
95
95
|
put_raw(path, attrs) do |parsed_data|
|
96
96
|
if parsed_data[:data].is_a?(Array)
|
97
|
-
new_collection(parsed_data
|
97
|
+
new_collection(parsed_data)
|
98
98
|
else
|
99
|
-
new(parsed_data[:data])
|
99
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end # }}}
|
@@ -111,7 +111,7 @@ module Her
|
|
111
111
|
def put_collection(path, attrs={}) # {{{
|
112
112
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
113
113
|
put_raw(path, attrs) do |parsed_data|
|
114
|
-
new_collection(parsed_data
|
114
|
+
new_collection(parsed_data)
|
115
115
|
end
|
116
116
|
end # }}}
|
117
117
|
|
@@ -119,7 +119,7 @@ module Her
|
|
119
119
|
def put_resource(path, attrs={}) # {{{
|
120
120
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
121
121
|
put_raw(path, attrs) do |parsed_data|
|
122
|
-
new(parsed_data[:data])
|
122
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
123
123
|
end
|
124
124
|
end # }}}
|
125
125
|
|
@@ -128,9 +128,9 @@ module Her
|
|
128
128
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
129
129
|
patch_raw(path, attrs) do |parsed_data|
|
130
130
|
if parsed_data[:data].is_a?(Array)
|
131
|
-
new_collection(parsed_data
|
131
|
+
new_collection(parsed_data)
|
132
132
|
else
|
133
|
-
new(parsed_data[:data])
|
133
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end # }}}
|
@@ -145,7 +145,7 @@ module Her
|
|
145
145
|
def patch_collection(path, attrs={}) # {{{
|
146
146
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
147
147
|
patch_raw(path, attrs) do |parsed_data|
|
148
|
-
new_collection(parsed_data
|
148
|
+
new_collection(parsed_data)
|
149
149
|
end
|
150
150
|
end # }}}
|
151
151
|
|
@@ -153,7 +153,7 @@ module Her
|
|
153
153
|
def patch_resource(path, attrs={}) # {{{
|
154
154
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
155
155
|
patch_raw(path, attrs) do |parsed_data|
|
156
|
-
new(parsed_data[:data])
|
156
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
157
157
|
end
|
158
158
|
end # }}}
|
159
159
|
|
@@ -162,9 +162,9 @@ module Her
|
|
162
162
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
163
163
|
delete_raw(path, attrs) do |parsed_data|
|
164
164
|
if parsed_data[:data].is_a?(Array)
|
165
|
-
new_collection(parsed_data
|
165
|
+
new_collection(parsed_data)
|
166
166
|
else
|
167
|
-
new(parsed_data[:data])
|
167
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
168
168
|
end
|
169
169
|
end
|
170
170
|
end # }}}
|
@@ -179,7 +179,7 @@ module Her
|
|
179
179
|
def delete_collection(path, attrs={}) # {{{
|
180
180
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
181
181
|
delete_raw(path, attrs) do |parsed_data|
|
182
|
-
new_collection(parsed_data
|
182
|
+
new_collection(parsed_data)
|
183
183
|
end
|
184
184
|
end # }}}
|
185
185
|
|
@@ -187,7 +187,7 @@ module Her
|
|
187
187
|
def delete_resource(path, attrs={}) # {{{
|
188
188
|
path = "#{build_request_path(attrs)}/#{path}" if path.is_a?(Symbol)
|
189
189
|
delete_raw(path, attrs) do |parsed_data|
|
190
|
-
new(parsed_data[:data])
|
190
|
+
new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
|
191
191
|
end
|
192
192
|
end # }}}
|
193
193
|
|
data/lib/her/model/orm.rb
CHANGED
@@ -2,17 +2,29 @@ module Her
|
|
2
2
|
module Model
|
3
3
|
# This module adds ORM-like capabilities to the model
|
4
4
|
module ORM
|
5
|
+
attr_reader :metadata, :errors
|
6
|
+
|
5
7
|
# Initialize a new object with data received from an HTTP request
|
6
8
|
# @private
|
7
|
-
def initialize(
|
8
|
-
@data =
|
9
|
-
@
|
9
|
+
def initialize(data={}) # {{{
|
10
|
+
@data = {}
|
11
|
+
@metadata = data.delete(:_metadata) || {}
|
12
|
+
@errors = data.delete(:_errors) || {}
|
13
|
+
cleaned_data = data.inject({}) do |memo, item|
|
14
|
+
key, value = item
|
15
|
+
send "#{key}=".to_sym, value unless value.nil?
|
16
|
+
respond_to?("#{key}=") ? memo : memo.merge({ key => value })
|
17
|
+
end
|
18
|
+
@data.merge! self.class.parse_relationships(cleaned_data)
|
10
19
|
end # }}}
|
11
20
|
|
12
21
|
# Initialize a collection of resources
|
13
22
|
# @private
|
14
|
-
def self.initialize_collection(name,
|
15
|
-
collection_data.map
|
23
|
+
def self.initialize_collection(name, parsed_data={}) # {{{
|
24
|
+
collection_data = parsed_data[:data].map do |item_data|
|
25
|
+
Object.const_get(name.to_s.classify).new(item_data)
|
26
|
+
end
|
27
|
+
Her::Collection.new(collection_data, parsed_data[:metadata], parsed_data[:errors])
|
16
28
|
end # }}}
|
17
29
|
|
18
30
|
# Handles missing methods by routing them through @data
|
@@ -20,10 +32,11 @@ module Her
|
|
20
32
|
def method_missing(method, attrs=nil) # {{{
|
21
33
|
assignment_method = method.to_s =~ /\=$/
|
22
34
|
method = method.to_s.gsub(/(\?|\!|\=)$/, "").to_sym
|
23
|
-
if attrs and assignment_method
|
35
|
+
if !attrs.nil? and assignment_method
|
36
|
+
@data ||= {}
|
24
37
|
@data[method.to_s.gsub(/\=$/, "").to_sym] = attrs
|
25
38
|
else
|
26
|
-
if @data.include?(method)
|
39
|
+
if @data and @data.include?(method)
|
27
40
|
@data[method]
|
28
41
|
else
|
29
42
|
super
|
@@ -39,9 +52,9 @@ module Her
|
|
39
52
|
|
40
53
|
# Initialize a collection of resources with raw data from an HTTP request
|
41
54
|
#
|
42
|
-
# @param [Array]
|
43
|
-
def new_collection(
|
44
|
-
Her::Model::ORM.initialize_collection(self.to_s.underscore,
|
55
|
+
# @param [Array] parsed_data
|
56
|
+
def new_collection(parsed_data) # {{{
|
57
|
+
Her::Model::ORM.initialize_collection(self.to_s.underscore, parsed_data)
|
45
58
|
end # }}}
|
46
59
|
|
47
60
|
# Return `true` if a resource was not saved yet
|
@@ -49,6 +62,16 @@ module Her
|
|
49
62
|
!@data.include?(:id)
|
50
63
|
end # }}}
|
51
64
|
|
65
|
+
# Return `true` if a resource does not contain errors
|
66
|
+
def valid? # {{{
|
67
|
+
@errors.empty?
|
68
|
+
end # }}}
|
69
|
+
|
70
|
+
# Return `true` if a resource contains errors
|
71
|
+
def invalid? # {{{
|
72
|
+
@errors.any?
|
73
|
+
end # }}}
|
74
|
+
|
52
75
|
# Fetch a specific resource based on an ID
|
53
76
|
#
|
54
77
|
# @example
|
@@ -67,7 +90,7 @@ module Her
|
|
67
90
|
# # Fetched via GET "/users"
|
68
91
|
def all(params={}) # {{{
|
69
92
|
request(params.merge(:_method => :get, :_path => "#{build_request_path(params)}")) do |parsed_data|
|
70
|
-
new_collection(parsed_data
|
93
|
+
new_collection(parsed_data)
|
71
94
|
end
|
72
95
|
end # }}}
|
73
96
|
|
@@ -78,17 +101,16 @@ module Her
|
|
78
101
|
# # Called via POST "/users/1"
|
79
102
|
def create(params={}) # {{{
|
80
103
|
resource = new(params)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
104
|
+
wrap_in_hooks(resource, :create, :save) do |resource, klass|
|
105
|
+
params = resource.instance_eval { @data }
|
106
|
+
request(params.merge(:_method => :post, :_path => "#{build_request_path(params)}")) do |parsed_data|
|
107
|
+
resource.instance_eval do
|
108
|
+
@data = parsed_data[:data]
|
109
|
+
@metadata = parsed_data[:metadata]
|
110
|
+
@errors = parsed_data[:errors]
|
111
|
+
end
|
87
112
|
end
|
88
113
|
end
|
89
|
-
perform_hook(resource, :after, :save)
|
90
|
-
perform_hook(resource, :after, :create)
|
91
|
-
|
92
114
|
resource
|
93
115
|
end # }}}
|
94
116
|
|
@@ -118,30 +140,20 @@ module Her
|
|
118
140
|
def save # {{{
|
119
141
|
params = @data.dup
|
120
142
|
resource = self
|
143
|
+
|
121
144
|
if @data[:id]
|
122
|
-
|
123
|
-
|
124
|
-
perform_hook(resource, :before, :save)
|
125
|
-
end
|
126
|
-
self.class.request(params.merge(:_method => :put, :_path => "#{request_path}")) do |parsed_data|
|
127
|
-
@data = parsed_data[:data]
|
128
|
-
end
|
129
|
-
self.class.class_eval do
|
130
|
-
perform_hook(resource, :after, :save)
|
131
|
-
perform_hook(resource, :after, :update)
|
132
|
-
end
|
133
|
-
self
|
145
|
+
hooks = [:update, :save]
|
146
|
+
method = :put
|
134
147
|
else
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
148
|
+
hooks = [:create, :save]
|
149
|
+
method = :post
|
150
|
+
end
|
151
|
+
|
152
|
+
self.class.wrap_in_hooks(resource, *hooks) do |resource, klass|
|
153
|
+
klass.request(params.merge(:_method => method, :_path => "#{request_path}")) do |parsed_data|
|
140
154
|
@data = parsed_data[:data]
|
141
|
-
|
142
|
-
|
143
|
-
perform_hook(resource, :after, :save)
|
144
|
-
perform_hook(resource, :after, :create)
|
155
|
+
@metadata = parsed_data[:metadata]
|
156
|
+
@errors = parsed_data[:errors]
|
145
157
|
end
|
146
158
|
end
|
147
159
|
self
|
@@ -154,13 +166,14 @@ module Her
|
|
154
166
|
# @user.destroy
|
155
167
|
# # Called via DELETE "/users/1"
|
156
168
|
def destroy # {{{
|
157
|
-
params = @data.dup
|
158
169
|
resource = self
|
159
|
-
self.class.
|
160
|
-
|
161
|
-
|
170
|
+
self.class.wrap_in_hooks(resource, :destroy) do |resource, klass|
|
171
|
+
klass.request(:_method => :delete, :_path => "#{request_path}") do |parsed_data|
|
172
|
+
@data = parsed_data[:data]
|
173
|
+
@metadata = parsed_data[:metadata]
|
174
|
+
@errors = parsed_data[:errors]
|
175
|
+
end
|
162
176
|
end
|
163
|
-
self.class.class_eval { perform_hook(resource, :after, :destroy) }
|
164
177
|
self
|
165
178
|
end # }}}
|
166
179
|
|
@@ -14,14 +14,16 @@ module Her
|
|
14
14
|
@her_relationships ||= {}
|
15
15
|
@her_relationships.each_pair do |type, relationships|
|
16
16
|
relationships.each do |relationship|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
name = relationship[:name]
|
18
|
+
class_name = relationship[:class_name]
|
19
|
+
next if !data.include?(name) or data[name].nil?
|
20
|
+
data[name] = case type
|
21
|
+
when :has_many
|
22
|
+
Her::Model::ORM.initialize_collection(class_name, :data => data[name])
|
23
|
+
when :has_one, :belongs_to
|
24
|
+
Object.const_get(class_name).new(data[name])
|
25
|
+
else
|
26
|
+
nil
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -47,14 +49,8 @@ module Her
|
|
47
49
|
# @user.articles # => [#<Article(articles/2) id=2 title="Hello world.">]
|
48
50
|
# # Fetched via GET "/users/1/articles"
|
49
51
|
def has_many(name, attrs={}) # {{{
|
50
|
-
@her_relationships ||= {}
|
51
52
|
attrs = { :class_name => name.to_s.classify, :name => name }.merge(attrs)
|
52
|
-
(
|
53
|
-
|
54
|
-
define_method(name) do
|
55
|
-
return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
|
56
|
-
Object.const_get(attrs[:class_name]).get_collection("#{self.class.build_request_path(:id => id)}/#{name.to_s.pluralize}")
|
57
|
-
end
|
53
|
+
define_relationship(:has_many, attrs)
|
58
54
|
end # }}}
|
59
55
|
|
60
56
|
# Define an *has_one* relationship.
|
@@ -76,14 +72,8 @@ module Her
|
|
76
72
|
# @user.organization # => #<Organization(organizations/2) id=2 name="Foobar Inc.">
|
77
73
|
# # Fetched via GET "/users/1/organization"
|
78
74
|
def has_one(name, attrs={}) # {{{
|
79
|
-
|
80
|
-
|
81
|
-
(@her_relationships[:has_one] ||= []) << attrs
|
82
|
-
|
83
|
-
define_method(name) do
|
84
|
-
return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
|
85
|
-
Object.const_get(attrs[:class_name]).get_resource("#{self.class.build_request_path(:id => id)}/#{name.to_s.singularize}")
|
86
|
-
end
|
75
|
+
attrs = { :class_name => name.to_s.classify, :name => name }.merge(attrs)
|
76
|
+
define_relationship(:has_one, attrs)
|
87
77
|
end # }}}
|
88
78
|
|
89
79
|
# Define a *belongs_to* relationship.
|
@@ -105,13 +95,36 @@ module Her
|
|
105
95
|
# @user.team # => #<Team(teams/2) id=2 name="Developers">
|
106
96
|
# # Fetched via GET "/teams/2"
|
107
97
|
def belongs_to(name, attrs={}) # {{{
|
108
|
-
@her_relationships ||= {}
|
109
98
|
attrs = { :class_name => name.to_s.classify, :name => name, :foreign_key => "#{name}_id" }.merge(attrs)
|
110
|
-
(
|
99
|
+
define_relationship(:belongs_to, attrs)
|
100
|
+
end # }}}
|
111
101
|
|
102
|
+
private
|
103
|
+
# @private
|
104
|
+
def define_relationship(type, attrs) # {{{
|
105
|
+
@her_relationships ||= {}
|
106
|
+
(@her_relationships[type] ||= []) << attrs
|
107
|
+
relationship_accessor(type, attrs)
|
108
|
+
end # }}}
|
109
|
+
|
110
|
+
# @private
|
111
|
+
def relationship_accessor(type, attrs) # {{{
|
112
|
+
name = attrs[:name]
|
113
|
+
class_name = attrs[:class_name]
|
112
114
|
define_method(name) do
|
113
|
-
return @data[name] if @data.include?(name)
|
114
|
-
|
115
|
+
return @data[name] if @data.include?(name)
|
116
|
+
|
117
|
+
klass = Object.const_get(class_name)
|
118
|
+
path = self.class.build_request_path(:id => id)
|
119
|
+
@data[name] = case type
|
120
|
+
when :belongs_to
|
121
|
+
foreign_key = attrs[:foreign_key].to_sym
|
122
|
+
klass.get_resource("#{klass.build_request_path(:id => @data[foreign_key])}")
|
123
|
+
when :has_many
|
124
|
+
klass.get_collection("#{path}/#{name.to_s.pluralize}")
|
125
|
+
when :has_one
|
126
|
+
klass.get_resource("#{path}/#{name.to_s.singularize}")
|
127
|
+
end
|
115
128
|
end
|
116
129
|
end # }}}
|
117
130
|
end
|