api_resource 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile.lock +27 -29
- data/README.md +1 -1
- data/api_resource.gemspec +2 -4
- data/lib/api_resource/associations.rb +25 -5
- data/lib/api_resource/associations/has_one_remote_object_proxy.rb +2 -1
- data/lib/api_resource/associations/multi_object_proxy.rb +13 -4
- data/lib/api_resource/associations/single_object_proxy.rb +9 -2
- data/lib/api_resource/base.rb +12 -12
- data/lib/api_resource/conditions.rb +2 -0
- data/lib/api_resource/conditions/abstract_condition.rb +24 -5
- data/lib/api_resource/conditions/association_condition.rb +2 -1
- data/lib/api_resource/conditions/multi_object_association_condition.rb +1 -1
- data/lib/api_resource/conditions/single_object_association_condition.rb +1 -1
- data/lib/api_resource/connection.rb +1 -2
- data/lib/api_resource/finders.rb +41 -49
- data/lib/api_resource/finders/abstract_finder.rb +26 -10
- data/lib/api_resource/finders/multi_object_association_finder.rb +16 -5
- data/lib/api_resource/finders/resource_finder.rb +31 -15
- data/lib/api_resource/finders/single_finder.rb +45 -0
- data/lib/api_resource/finders/single_object_association_finder.rb +14 -4
- data/lib/api_resource/version.rb +1 -1
- data/spec/lib/associations_spec.rb +2 -0
- data/spec/lib/base_spec.rb +3 -0
- data/spec/lib/conditions/abstract_conditions_spec.rb +2 -2
- data/spec/lib/finders/multi_object_association_finder_spec.rb +2 -2
- data/spec/lib/finders/resource_finder_spec.rb +29 -40
- data/spec/lib/finders/single_object_association_finder_spec.rb +2 -2
- data/spec/lib/finders_spec.rb +38 -0
- data/spec/lib/prefixes_spec.rb +5 -8
- metadata +10 -39
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
api_resource (0.
|
5
|
-
|
6
|
-
|
4
|
+
api_resource (0.6.0)
|
5
|
+
colorize
|
6
|
+
differ
|
7
7
|
json
|
8
8
|
log4r
|
9
9
|
rails
|
@@ -12,12 +12,12 @@ PATH
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
14
14
|
specs:
|
15
|
-
actionmailer (3.2.
|
16
|
-
actionpack (= 3.2.
|
15
|
+
actionmailer (3.2.10)
|
16
|
+
actionpack (= 3.2.10)
|
17
17
|
mail (~> 2.4.4)
|
18
|
-
actionpack (3.2.
|
19
|
-
activemodel (= 3.2.
|
20
|
-
activesupport (= 3.2.
|
18
|
+
actionpack (3.2.10)
|
19
|
+
activemodel (= 3.2.10)
|
20
|
+
activesupport (= 3.2.10)
|
21
21
|
builder (~> 3.0.0)
|
22
22
|
erubis (~> 2.7.0)
|
23
23
|
journey (~> 1.0.4)
|
@@ -25,18 +25,18 @@ GEM
|
|
25
25
|
rack-cache (~> 1.2)
|
26
26
|
rack-test (~> 0.6.1)
|
27
27
|
sprockets (~> 2.2.1)
|
28
|
-
activemodel (3.2.
|
29
|
-
activesupport (= 3.2.
|
28
|
+
activemodel (3.2.10)
|
29
|
+
activesupport (= 3.2.10)
|
30
30
|
builder (~> 3.0.0)
|
31
|
-
activerecord (3.2.
|
32
|
-
activemodel (= 3.2.
|
33
|
-
activesupport (= 3.2.
|
31
|
+
activerecord (3.2.10)
|
32
|
+
activemodel (= 3.2.10)
|
33
|
+
activesupport (= 3.2.10)
|
34
34
|
arel (~> 3.0.2)
|
35
35
|
tzinfo (~> 0.3.29)
|
36
|
-
activeresource (3.2.
|
37
|
-
activemodel (= 3.2.
|
38
|
-
activesupport (= 3.2.
|
39
|
-
activesupport (3.2.
|
36
|
+
activeresource (3.2.10)
|
37
|
+
activemodel (= 3.2.10)
|
38
|
+
activesupport (= 3.2.10)
|
39
|
+
activesupport (3.2.10)
|
40
40
|
i18n (~> 0.6)
|
41
41
|
multi_json (~> 1.0)
|
42
42
|
arel (3.0.2)
|
@@ -106,17 +106,17 @@ GEM
|
|
106
106
|
rack
|
107
107
|
rack-test (0.6.2)
|
108
108
|
rack (>= 1.0)
|
109
|
-
rails (3.2.
|
110
|
-
actionmailer (= 3.2.
|
111
|
-
actionpack (= 3.2.
|
112
|
-
activerecord (= 3.2.
|
113
|
-
activeresource (= 3.2.
|
114
|
-
activesupport (= 3.2.
|
109
|
+
rails (3.2.10)
|
110
|
+
actionmailer (= 3.2.10)
|
111
|
+
actionpack (= 3.2.10)
|
112
|
+
activerecord (= 3.2.10)
|
113
|
+
activeresource (= 3.2.10)
|
114
|
+
activesupport (= 3.2.10)
|
115
115
|
bundler (~> 1.0)
|
116
|
-
railties (= 3.2.
|
117
|
-
railties (3.2.
|
118
|
-
actionpack (= 3.2.
|
119
|
-
activesupport (= 3.2.
|
116
|
+
railties (= 3.2.10)
|
117
|
+
railties (3.2.10)
|
118
|
+
actionpack (= 3.2.10)
|
119
|
+
activesupport (= 3.2.10)
|
120
120
|
rack-ssl (~> 1.3.2)
|
121
121
|
rake (>= 0.8.7)
|
122
122
|
rdoc (~> 3.4)
|
@@ -162,8 +162,6 @@ PLATFORMS
|
|
162
162
|
|
163
163
|
DEPENDENCIES
|
164
164
|
api_resource!
|
165
|
-
colorize
|
166
|
-
differ
|
167
165
|
faker
|
168
166
|
flay
|
169
167
|
flog
|
data/README.md
CHANGED
data/api_resource.gemspec
CHANGED
@@ -33,14 +33,12 @@ Gem::Specification.new do |gem|
|
|
33
33
|
gem.add_development_dependency "rb-fsevent"
|
34
34
|
gem.add_development_dependency "simplecov"
|
35
35
|
# stuff that seems like crap
|
36
|
-
gem.add_development_dependency "differ"
|
37
|
-
gem.add_development_dependency "colorize"
|
38
36
|
gem.add_development_dependency "sqlite3"
|
39
37
|
|
40
38
|
gem.add_dependency "rails"
|
41
|
-
gem.add_dependency "activemodel"
|
42
|
-
gem.add_dependency "activesupport"
|
43
39
|
gem.add_dependency "json"
|
44
40
|
gem.add_dependency "rest-client"
|
45
41
|
gem.add_dependency "log4r"
|
42
|
+
gem.add_dependency "differ"
|
43
|
+
gem.add_dependency "colorize"
|
46
44
|
end
|
@@ -183,10 +183,19 @@ module ApiResource
|
|
183
183
|
if self.ancestors.include?(ApiResource::Base)
|
184
184
|
define_attribute_method(assoc_name)
|
185
185
|
end
|
186
|
+
|
187
|
+
id_method_name = assoc_name.to_s.singularize + "_id"
|
188
|
+
|
189
|
+
if assoc_type.to_s == "has_many"
|
190
|
+
id_method_name += "s"
|
191
|
+
end
|
186
192
|
|
187
193
|
# TODO: Come up with a better implementation for the foreign key thing
|
188
194
|
# implement the rest of the active record methods, refactor this into something
|
189
|
-
# a
|
195
|
+
# a little bit more sensible
|
196
|
+
|
197
|
+
# TODO: This should support saving the ids when they are modified and saving anything
|
198
|
+
# that is not created, associations need to be their own object
|
190
199
|
self.class_eval <<-EOE, __FILE__, __LINE__ + 1
|
191
200
|
def #{assoc_name}
|
192
201
|
@attributes_cache[:#{assoc_name}] ||= begin
|
@@ -200,17 +209,28 @@ module ApiResource
|
|
200
209
|
instance
|
201
210
|
end
|
202
211
|
end
|
203
|
-
def #{assoc_name}=(val)
|
204
|
-
|
205
|
-
|
206
|
-
|
212
|
+
def #{assoc_name}=(val, force = true)
|
213
|
+
if !force
|
214
|
+
#{assoc_name}_will_change!
|
215
|
+
elsif self.#{assoc_name}.internal_object != val
|
216
|
+
#{assoc_name}_will_change!
|
207
217
|
end
|
218
|
+
# This should not force a load
|
208
219
|
self.#{assoc_name}.internal_object = val
|
209
220
|
end
|
210
221
|
def #{assoc_name}?
|
211
222
|
self.#{assoc_name}.internal_object.present?
|
212
223
|
end
|
213
224
|
|
225
|
+
def #{id_method_name}
|
226
|
+
@attributes_cache[:#{id_method_name}] ||=
|
227
|
+
@attributes[:#{id_method_name}] || self.#{assoc_name}.collect(&:id)
|
228
|
+
end
|
229
|
+
|
230
|
+
def #{id_method_name}=(val)
|
231
|
+
@attributes_cache[:#{id_method_name}] = val
|
232
|
+
end
|
233
|
+
|
214
234
|
EOE
|
215
235
|
end
|
216
236
|
|
@@ -32,13 +32,19 @@ module ApiResource
|
|
32
32
|
|
33
33
|
def internal_object=(contents)
|
34
34
|
# if we were passed in a service uri, stop here
|
35
|
-
|
35
|
+
# but if we have a service uri already then don't overwrite
|
36
|
+
unless self.remote_path.present?
|
37
|
+
return true if self.set_remote_path(contents)
|
38
|
+
end
|
36
39
|
|
37
40
|
if contents.try(:first).is_a?(self.klass)
|
38
|
-
|
41
|
+
@loaded = true
|
42
|
+
return @internal_object = contents
|
39
43
|
elsif contents.instance_of?(self.class)
|
44
|
+
@loaded = true
|
40
45
|
return @internal_object = contents.internal_object
|
41
46
|
elsif contents.is_a?(Array)
|
47
|
+
@loaded = true
|
42
48
|
return @internal_object = self.klass.instantiate_collection(
|
43
49
|
contents
|
44
50
|
)
|
@@ -70,12 +76,15 @@ module ApiResource
|
|
70
76
|
protected
|
71
77
|
|
72
78
|
def to_condition
|
73
|
-
|
79
|
+
obj = nil
|
80
|
+
obj = self.internal_object if self.loaded?
|
81
|
+
ApiResource::Conditions::MultiObjectAssociationCondition.new(self.klass, self.remote_path, obj)
|
74
82
|
end
|
75
83
|
|
76
84
|
def load(opts = {})
|
85
|
+
res = self.to_condition.load
|
77
86
|
@loaded = true
|
78
|
-
|
87
|
+
res
|
79
88
|
end
|
80
89
|
|
81
90
|
def set_remote_path(opts)
|
@@ -22,8 +22,10 @@ module ApiResource
|
|
22
22
|
|
23
23
|
def internal_object=(contents)
|
24
24
|
if contents.is_a?(self.klass) || contents.nil?
|
25
|
+
@loaded = true
|
25
26
|
return @internal_object = contents
|
26
27
|
elsif contents.is_a?(self.class)
|
28
|
+
@loaded = true
|
27
29
|
return @internal_object = contents.internal_object
|
28
30
|
# a Hash may be attributes and/or a service_uri
|
29
31
|
elsif contents.is_a?(Hash)
|
@@ -32,6 +34,7 @@ module ApiResource
|
|
32
34
|
self.class.remote_path_element.to_sym
|
33
35
|
)
|
34
36
|
if contents.present?
|
37
|
+
@loaded = true
|
35
38
|
return @internal_object = self.klass.instantiate_record(contents)
|
36
39
|
end
|
37
40
|
else
|
@@ -58,13 +61,17 @@ module ApiResource
|
|
58
61
|
protected
|
59
62
|
|
60
63
|
def to_condition
|
61
|
-
|
64
|
+
obj = nil
|
65
|
+
obj = self.internal_object if self.loaded?
|
66
|
+
ApiResource::Conditions::SingleObjectAssociationCondition.new(self.klass, self.remote_path, obj)
|
62
67
|
end
|
63
68
|
|
64
69
|
# Should make a proper conditions object and call find on it
|
70
|
+
# It MUST set loaded to true after calling load
|
65
71
|
def load(opts = {})
|
72
|
+
res = self.to_condition.load
|
66
73
|
@loaded = true
|
67
|
-
|
74
|
+
res
|
68
75
|
end
|
69
76
|
|
70
77
|
|
data/lib/api_resource/base.rb
CHANGED
@@ -341,6 +341,18 @@ module ApiResource
|
|
341
341
|
connection.delete(element_path(id, options))
|
342
342
|
end
|
343
343
|
|
344
|
+
# split an option hash into two hashes, one containing the prefix options,
|
345
|
+
# and the other containing the leftovers.
|
346
|
+
def split_options(options = {})
|
347
|
+
prefix_options, query_options = {}, {}
|
348
|
+
(options || {}).each do |key, value|
|
349
|
+
next if key.blank?
|
350
|
+
(prefix_parameters.include?(key.to_sym) ? prefix_options : query_options)[key.to_sym] = value
|
351
|
+
end
|
352
|
+
|
353
|
+
[ prefix_options, query_options ]
|
354
|
+
end
|
355
|
+
|
344
356
|
protected
|
345
357
|
def method_missing(meth, *args, &block)
|
346
358
|
# make one attempt to load remote attrs
|
@@ -372,18 +384,6 @@ module ApiResource
|
|
372
384
|
"?#{options.to_query}" unless options.nil? || options.empty?
|
373
385
|
end
|
374
386
|
|
375
|
-
# split an option hash into two hashes, one containing the prefix options,
|
376
|
-
# and the other containing the leftovers.
|
377
|
-
def split_options(options = {})
|
378
|
-
prefix_options, query_options = {}, {}
|
379
|
-
(options || {}).each do |key, value|
|
380
|
-
next if key.blank?
|
381
|
-
(prefix_parameters.include?(key.to_sym) ? prefix_options : query_options)[key.to_sym] = value
|
382
|
-
end
|
383
|
-
|
384
|
-
[ prefix_options, query_options ]
|
385
|
-
end
|
386
|
-
|
387
387
|
def uri_parser
|
388
388
|
@uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
|
389
389
|
end
|
@@ -21,6 +21,8 @@ module ApiResource
|
|
21
21
|
@klass = klass
|
22
22
|
|
23
23
|
@conditions = args.with_indifferent_access
|
24
|
+
|
25
|
+
@klass.load_resource_definition
|
24
26
|
end
|
25
27
|
|
26
28
|
def each(&block)
|
@@ -48,14 +50,31 @@ module ApiResource
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def internal_object
|
51
|
-
@internal_object
|
52
|
-
|
53
|
-
|
53
|
+
return @internal_object if @loaded
|
54
|
+
@internal_object = self.instantiate_finder.load
|
55
|
+
@loaded = true
|
56
|
+
@internal_object
|
57
|
+
end
|
58
|
+
|
59
|
+
def all(*args)
|
60
|
+
if args.blank?
|
61
|
+
self.internal_object
|
62
|
+
else
|
63
|
+
self.find(*([:all] + args))
|
54
64
|
end
|
55
65
|
end
|
56
66
|
|
57
|
-
|
58
|
-
|
67
|
+
# implement find that accepts an optional
|
68
|
+
# condition object
|
69
|
+
def find(*args)
|
70
|
+
self.klass.find(*(args + [self]))
|
71
|
+
end
|
72
|
+
|
73
|
+
# TODO: review the hierarchy that makes this necessary
|
74
|
+
# consider changing it to alias method
|
75
|
+
def load
|
76
|
+
self.internal_object
|
77
|
+
end
|
59
78
|
|
60
79
|
def loaded?
|
61
80
|
@loaded == true
|
@@ -4,11 +4,12 @@ module ApiResource
|
|
4
4
|
|
5
5
|
class AssociationCondition < AbstractCondition
|
6
6
|
|
7
|
-
def initialize(klass, service_uri)
|
7
|
+
def initialize(klass, service_uri, internal_object= nil)
|
8
8
|
super({}, klass)
|
9
9
|
|
10
10
|
@assocaiton = true
|
11
11
|
@remote_path = service_uri
|
12
|
+
@internal_object = internal_object
|
12
13
|
end
|
13
14
|
|
14
15
|
end
|
@@ -119,8 +119,7 @@ module ApiResource
|
|
119
119
|
ActiveSupport::Notifications.instrument("request.api_resource") do |payload|
|
120
120
|
|
121
121
|
# debug logging
|
122
|
-
ApiResource.logger.
|
123
|
-
|
122
|
+
ApiResource.logger.info("#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}")
|
124
123
|
payload[:method] = method
|
125
124
|
payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
|
126
125
|
payload[:result] = http(path).send(method, *arguments)
|
data/lib/api_resource/finders.rb
CHANGED
@@ -7,6 +7,7 @@ module ApiResource
|
|
7
7
|
|
8
8
|
autoload :AbstractFinder
|
9
9
|
autoload :ResourceFinder
|
10
|
+
autoload :SingleFinder
|
10
11
|
autoload :SingleObjectAssociationFinder
|
11
12
|
autoload :MultiObjectAssociationFinder
|
12
13
|
|
@@ -16,22 +17,54 @@ module ApiResource
|
|
16
17
|
# It accepts arguments of the form "scope", "options={}"
|
17
18
|
# where options can be standard rails options or :expires_in.
|
18
19
|
# If :expires_in is set, it caches it for expires_in seconds.
|
19
|
-
def find(*arguments)
|
20
20
|
|
21
|
+
# Need to support the following cases
|
22
|
+
# => 1) Klass.find(1)
|
23
|
+
# => 2) Klass.find(:all, :params => {a => b})
|
24
|
+
# => 3) Klass.find(:first, :params => {a => b})
|
25
|
+
# => 4) Klass.includes(:assoc).find(1)
|
26
|
+
# => 5) Klass.active.find(1)
|
27
|
+
# => 6) Klass.includes(:assoc).find(:all, a => b)
|
28
|
+
def find(*arguments)
|
21
29
|
# make sure we have class data before loading
|
22
30
|
self.load_resource_definition
|
23
31
|
|
24
32
|
scope = arguments.slice!(0)
|
25
33
|
options = arguments.slice!(0) || {}
|
26
|
-
|
27
|
-
|
34
|
+
cond = arguments.slice!(0)
|
35
|
+
|
36
|
+
# TODO: Make this into a class attribute properly (if it isn't already)
|
37
|
+
# this is a little bit of a hack because options can sometimes be a Condition
|
38
|
+
expiry = (options.is_a?(Hash) ? options.delete(:expires_in) : nil) || ApiResource::Base.ttl || 0
|
28
39
|
ApiResource.with_ttl(expiry.to_f) do
|
29
40
|
case scope
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
41
|
+
when :all, :first, :last
|
42
|
+
final_cond = ApiResource::Conditions::ScopeCondition.new({}, self)
|
43
|
+
# we need new conditions here to take into account options, which could
|
44
|
+
# either be a Condition object or a hash
|
45
|
+
if options.is_a?(Hash)
|
46
|
+
opts = options.with_indifferent_access.delete(:params) || options || {}
|
47
|
+
final_cond = ApiResource::Conditions::ScopeCondition.new(opts, self)
|
48
|
+
# cond may be nil
|
49
|
+
unless cond == nil # THIS MUST BE == NOT nil?
|
50
|
+
final_cond = cond.merge!(final_cond)
|
51
|
+
end
|
52
|
+
elsif options.is_a?(ApiResource::Conditions::AbstractCondition)
|
53
|
+
final_cond = options
|
54
|
+
end
|
55
|
+
# now final cond contains all the conditions we should need to pass to the finder
|
56
|
+
fnd = ApiResource::Finders::ResourceFinder.new(self, final_cond)
|
57
|
+
fnd.send(scope)
|
58
|
+
else
|
59
|
+
# in this case scope is the id we want to find, and options should be a condition object or nil
|
60
|
+
final_cond = ApiResource::Conditions::ScopeCondition.new({:id => scope}, self)
|
61
|
+
if options.is_a?(ApiResource::Conditions::AbstractCondition)
|
62
|
+
final_cond = options.merge!(final_cond)
|
63
|
+
elsif options.is_a?(Hash)
|
64
|
+
opts = options.with_indifferent_access.delete(:params) || options || {}
|
65
|
+
final_cond = ApiResource::Conditions::ScopeCondition.new(opts, self).merge!(final_cond)
|
66
|
+
end
|
67
|
+
ApiResource::Finders::SingleFinder.new(self, final_cond).load
|
35
68
|
end
|
36
69
|
end
|
37
70
|
end
|
@@ -75,47 +108,6 @@ module ApiResource
|
|
75
108
|
ret
|
76
109
|
end
|
77
110
|
|
78
|
-
private
|
79
|
-
|
80
|
-
# Find every resource
|
81
|
-
def find_every(options)
|
82
|
-
begin
|
83
|
-
case from = options[:from]
|
84
|
-
when Symbol
|
85
|
-
instantiate_collection(get(from, options[:params]))
|
86
|
-
when String
|
87
|
-
path = "#{from}#{query_string(options[:params])}"
|
88
|
-
instantiate_collection(connection.get(path, headers) || [])
|
89
|
-
else
|
90
|
-
prefix_options, query_options = split_options(options[:params])
|
91
|
-
path = collection_path(prefix_options, query_options)
|
92
|
-
instantiate_collection( (connection.get(path, headers) || []))
|
93
|
-
end
|
94
|
-
rescue ApiResource::ResourceNotFound
|
95
|
-
# Swallowing ResourceNotFound exceptions and return nil - as per
|
96
|
-
# ActiveRecord.
|
97
|
-
nil
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Find a single resource from a one-off URL
|
102
|
-
def find_one(options)
|
103
|
-
case from = options[:from]
|
104
|
-
when Symbol
|
105
|
-
instantiate_record(get(from, options[:params]))
|
106
|
-
when String
|
107
|
-
path = "#{from}#{query_string(options[:params])}"
|
108
|
-
instantiate_record(connection.get(path, headers))
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# Find a single resource from the default URL
|
113
|
-
def find_single(scope, options)
|
114
|
-
prefix_options, query_options = split_options(options[:params])
|
115
|
-
path = element_path(scope, prefix_options, query_options)
|
116
|
-
instantiate_record(connection.get(path, headers))
|
117
|
-
end
|
118
|
-
|
119
111
|
end
|
120
112
|
end
|
121
113
|
|
@@ -9,16 +9,17 @@ module ApiResource
|
|
9
9
|
attr_reader :found, :internal_object
|
10
10
|
|
11
11
|
# TODO: Make this list longer since there are for sure more methods to delegate
|
12
|
-
delegate :to_s, :inspect, :reload, :present?, :blank?, :size, :to => :internal_object
|
12
|
+
delegate :to_s, :inspect, :reload, :present?, :blank?, :size, :count, :to => :internal_object
|
13
13
|
|
14
14
|
def initialize(klass, condition)
|
15
15
|
@klass = klass
|
16
16
|
@condition = condition
|
17
17
|
@found = false
|
18
|
-
|
18
|
+
|
19
|
+
@klass.load_resource_definition
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
+
def load
|
22
23
|
raise NotImplementedError("Must be defined in a subclass")
|
23
24
|
end
|
24
25
|
|
@@ -27,8 +28,16 @@ module ApiResource
|
|
27
28
|
if instance_variable_defined?(:@internal_object)
|
28
29
|
return instance_variable_get(:@internal_object)
|
29
30
|
end
|
30
|
-
# If we haven't tried to load then just call
|
31
|
-
self.
|
31
|
+
# If we haven't tried to load then just call load
|
32
|
+
self.load
|
33
|
+
end
|
34
|
+
|
35
|
+
def all(*args)
|
36
|
+
if args.blank?
|
37
|
+
self.internal_object
|
38
|
+
else
|
39
|
+
self.klass.send(:all, *args)
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
43
|
# proxy unknown methods to the internal_object
|
@@ -51,9 +60,10 @@ module ApiResource
|
|
51
60
|
id_hash = HashWithIndifferentAccess.new(id_hash)
|
52
61
|
# load each individually
|
53
62
|
self.condition.included_objects.inject(hsh) do |accum, assoc|
|
54
|
-
accum[assoc.to_sym] = self.klass.association_class(assoc).
|
55
|
-
:
|
56
|
-
|
63
|
+
accum[assoc.to_sym] = self.klass.association_class(assoc).all(
|
64
|
+
:params => {:ids => id_hash[assoc]}
|
65
|
+
)
|
66
|
+
accum
|
57
67
|
end
|
58
68
|
|
59
69
|
hsh
|
@@ -62,9 +72,15 @@ module ApiResource
|
|
62
72
|
def apply_includes(objects, includes)
|
63
73
|
Array.wrap(objects).each do |obj|
|
64
74
|
includes.each_pair do |assoc, vals|
|
65
|
-
ids_to_keep = obj.send(obj.class.association_foreign_key_field(assoc))
|
75
|
+
ids_to_keep = Array.wrap(obj.send(obj.class.association_foreign_key_field(assoc)))
|
66
76
|
to_keep = vals.select{|elm| ids_to_keep.include?(elm.id)}
|
67
|
-
|
77
|
+
# if this is a single association take the first
|
78
|
+
# TODO: subclass instead of this
|
79
|
+
if self.klass.has_many?(assoc)
|
80
|
+
obj.send("#{assoc}=", to_keep, false)
|
81
|
+
else
|
82
|
+
obj.send("#{assoc}=", to_keep.first, false)
|
83
|
+
end
|
68
84
|
end
|
69
85
|
end
|
70
86
|
end
|
@@ -4,17 +4,28 @@ module ApiResource
|
|
4
4
|
|
5
5
|
class MultiObjectAssociationFinder < AbstractFinder
|
6
6
|
|
7
|
-
|
7
|
+
# If they pass in the internal object just skip the first
|
8
|
+
# step and apply the includes
|
9
|
+
def initialize(klass, condition, internal_object = nil)
|
10
|
+
super(klass, condition)
|
11
|
+
|
12
|
+
@internal_object = internal_object
|
13
|
+
end
|
14
|
+
|
15
|
+
def load
|
8
16
|
# otherwise just instantiate the record
|
9
17
|
unless self.condition.remote_path
|
10
18
|
raise "Tried to load association without a remote path"
|
11
19
|
end
|
12
20
|
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
unless @internal_object
|
22
|
+
data = self.klass.connection.get(self.build_load_path)
|
23
|
+
return [] if data.blank?
|
16
24
|
|
17
|
-
|
25
|
+
@internal_object = self.klass.instantiate_collection(data)
|
26
|
+
end
|
27
|
+
|
28
|
+
@loaded = true
|
18
29
|
|
19
30
|
id_hash = self.condition.included_objects.inject({}) do |accum, assoc|
|
20
31
|
accum[assoc] = @internal_object.collect do |obj|
|
@@ -6,26 +6,42 @@ module ApiResource
|
|
6
6
|
|
7
7
|
# this is a little bit simpler, it's always a collection and does
|
8
8
|
# not require a remote path
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
def load
|
10
|
+
begin
|
11
|
+
@loaded = true
|
12
|
+
@internal_object = self.klass.connection.get(self.build_load_path)
|
13
|
+
return [] if @internal_object.blank?
|
14
|
+
|
15
|
+
@internal_object = self.klass.instantiate_collection(@internal_object)
|
16
|
+
|
17
|
+
id_hash = self.condition.included_objects.inject({}) do |accum, assoc|
|
18
|
+
accum[assoc] = @internal_object.collect do |obj|
|
19
|
+
obj.send(self.klass.association_foreign_key_field(assoc))
|
20
|
+
end
|
21
|
+
accum[assoc].flatten!
|
22
|
+
accum[assoc].uniq!
|
23
|
+
accum
|
17
24
|
end
|
18
|
-
|
19
|
-
accum[assoc].uniq!
|
20
|
-
accum
|
21
|
-
end
|
22
|
-
included_objects = self.load_includes(id_hash)
|
25
|
+
included_objects = self.load_includes(id_hash)
|
23
26
|
|
24
|
-
|
27
|
+
self.apply_includes(@internal_object, included_objects)
|
25
28
|
|
26
|
-
|
29
|
+
return @internal_object
|
30
|
+
rescue ApiResource::ResourceNotFound
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
@internal_object
|
27
34
|
end
|
28
35
|
|
36
|
+
protected
|
37
|
+
|
38
|
+
|
39
|
+
# Find every resource
|
40
|
+
def build_load_path
|
41
|
+
prefix_opts, query_opts = self.klass.split_options(self.condition.to_hash)
|
42
|
+
self.klass.collection_path(prefix_opts, query_opts)
|
43
|
+
end
|
44
|
+
|
29
45
|
end
|
30
46
|
|
31
47
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module ApiResource
|
2
|
+
|
3
|
+
module Finders
|
4
|
+
|
5
|
+
class SingleFinder < AbstractFinder
|
6
|
+
|
7
|
+
def load
|
8
|
+
data = self.klass.connection.get(self.build_load_path)
|
9
|
+
@loaded = true
|
10
|
+
return nil if data.blank?
|
11
|
+
@internal_object = self.klass.instantiate_record(data)
|
12
|
+
# now that the object is loaded, resolve the includes
|
13
|
+
id_hash = self.condition.included_objects.inject({}) do |accum, assoc|
|
14
|
+
accum[assoc] = Array.wrap(
|
15
|
+
@internal_object.send(
|
16
|
+
@internal_object.class.association_foreign_key_field(assoc)
|
17
|
+
)
|
18
|
+
)
|
19
|
+
accum
|
20
|
+
end
|
21
|
+
|
22
|
+
included_objects = self.load_includes(id_hash)
|
23
|
+
|
24
|
+
self.apply_includes(@internal_object, included_objects)
|
25
|
+
|
26
|
+
return @internal_object
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def build_load_path
|
32
|
+
if self.condition.to_hash["id"].nil?
|
33
|
+
raise "Invalid evaluation of a SingleFinder without an ID"
|
34
|
+
end
|
35
|
+
args = self.condition.to_hash
|
36
|
+
id = args.delete("id")
|
37
|
+
prefix_opts, query_opts = self.klass.split_options(args)
|
38
|
+
self.klass.element_path(id, prefix_opts, query_opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -4,18 +4,28 @@ module ApiResource
|
|
4
4
|
|
5
5
|
class SingleObjectAssociationFinder < AbstractFinder
|
6
6
|
|
7
|
+
def initialize(klass, condition, internal_object = nil)
|
8
|
+
super(klass, condition)
|
9
|
+
|
10
|
+
@internal_object = internal_object
|
11
|
+
end
|
12
|
+
|
7
13
|
# since it is only a single object we can just load from
|
8
14
|
# the service_uri and deal with includes
|
9
|
-
def
|
15
|
+
def load
|
10
16
|
# otherwise just instantiate the record
|
11
17
|
unless self.condition.remote_path
|
12
18
|
raise "Tried to load association without a remote path"
|
13
19
|
end
|
14
20
|
|
15
|
-
|
21
|
+
unless @internal_object
|
22
|
+
data = self.klass.connection.get(self.build_load_path)
|
23
|
+
|
24
|
+
return nil if data.blank?
|
25
|
+
@internal_object = self.klass.instantiate_record(data)
|
26
|
+
end
|
27
|
+
|
16
28
|
@loaded = true
|
17
|
-
return nil if data.blank?
|
18
|
-
@internal_object = self.klass.instantiate_record(data)
|
19
29
|
# now that the object is loaded, resolve the includes
|
20
30
|
id_hash = self.condition.included_objects.inject({}) do |accum, assoc|
|
21
31
|
accum[assoc] = Array.wrap(
|
data/lib/api_resource/version.rb
CHANGED
@@ -729,6 +729,7 @@ describe "Associations" do
|
|
729
729
|
TestAR.class_eval do
|
730
730
|
belongs_to_remote :my_favorite_thing, :class_name => "TestClassYay"
|
731
731
|
end
|
732
|
+
HasManyObject.reload_resource_definition
|
732
733
|
end
|
733
734
|
it "should define remote association types for AR" do
|
734
735
|
[:has_many_remote, :belongs_to_remote, :has_one_remote].each do |assoc|
|
@@ -788,6 +789,7 @@ describe "Associations" do
|
|
788
789
|
it "should attempt to load a collection of remote objects for a has_many relationship" do
|
789
790
|
tar = TestAR.new
|
790
791
|
tar.stubs(:id).returns(1)
|
792
|
+
HasManyObject.load_resource_definition
|
791
793
|
HasManyObject.connection.expects(:get).with("/has_many_objects.json?test_ar_id=1").once.returns([{"name" => "testing"}])
|
792
794
|
# load the test resource
|
793
795
|
tar.has_many_objects.first.name.should eql "testing"
|
data/spec/lib/base_spec.rb
CHANGED
@@ -7,6 +7,8 @@ describe "Base" do
|
|
7
7
|
|
8
8
|
before(:each) do
|
9
9
|
TestResource.reload_resource_definition
|
10
|
+
HasOneObject.reload_resource_definition
|
11
|
+
HasManyObject.reload_resource_definition
|
10
12
|
end
|
11
13
|
|
12
14
|
context ".new_element_path" do
|
@@ -795,6 +797,7 @@ describe "Base" do
|
|
795
797
|
|
796
798
|
before(:all) do
|
797
799
|
HasOneObject.reload_resource_definition
|
800
|
+
HasManyObject.load_resource_definition
|
798
801
|
end
|
799
802
|
|
800
803
|
it "should know if it is persisted" do
|
@@ -61,7 +61,7 @@ describe "Conditions" do
|
|
61
61
|
it "should create a resource finder when forced to load, and cache the result" do
|
62
62
|
obj = TestResource.includes(:has_many_objects)
|
63
63
|
|
64
|
-
ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:
|
64
|
+
ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:load => [1]))
|
65
65
|
obj.internal_object.should eql([1])
|
66
66
|
obj.all.should eql([1])
|
67
67
|
obj.first.should eql(1)
|
@@ -70,7 +70,7 @@ describe "Conditions" do
|
|
70
70
|
it "should proxy calls to enumerable and array methods to the loaded object" do
|
71
71
|
obj = TestResource.includes(:has_many_objects)
|
72
72
|
|
73
|
-
ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:
|
73
|
+
ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:load => [1,2]))
|
74
74
|
|
75
75
|
obj.collect{|o| o * 2}.should eql([2,4])
|
76
76
|
end
|
@@ -12,7 +12,7 @@ describe "MultiObjectAssociationFinder" do
|
|
12
12
|
ApiResource::Finders::MultiObjectAssociationFinder.new(
|
13
13
|
TestResource,
|
14
14
|
stub(:remote_path => "test_resources", :to_query => "id[]=1&id[]=2", :blank_conditions? => false)
|
15
|
-
).
|
15
|
+
).load
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should load a has many association properly" do
|
@@ -37,7 +37,7 @@ describe "MultiObjectAssociationFinder" do
|
|
37
37
|
finder.expects(:load_includes).with(:has_many_objects => [1,2]).returns(5)
|
38
38
|
finder.expects(:apply_includes).with([tr], 5).returns(6)
|
39
39
|
|
40
|
-
finder.
|
40
|
+
finder.load.should eql([tr])
|
41
41
|
end
|
42
42
|
|
43
43
|
end
|
@@ -4,83 +4,72 @@ describe "ResourceFinder" do
|
|
4
4
|
|
5
5
|
before(:each) do
|
6
6
|
TestResource.reload_resource_definition
|
7
|
+
|
7
8
|
end
|
8
9
|
|
9
|
-
it "should
|
10
|
-
TestResource.expects(:
|
10
|
+
it "should load normally without includes using connection.get" do
|
11
|
+
TestResource.connection.expects(:get).with("/test_resources.json")
|
11
12
|
|
12
13
|
ApiResource::Finders::ResourceFinder.new(
|
13
14
|
TestResource,
|
14
15
|
mock(:to_hash => {})
|
15
|
-
).
|
16
|
+
).load
|
16
17
|
end
|
17
18
|
|
18
|
-
it "should pass conditions into the
|
19
|
-
TestResource.expects(:
|
19
|
+
it "should pass conditions into the connection get method" do
|
20
|
+
TestResource.connection.expects(:get).with("/test_resources.json?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3")
|
20
21
|
|
21
22
|
ApiResource::Finders::ResourceFinder.new(
|
22
23
|
TestResource,
|
23
|
-
mock(:to_hash => {:
|
24
|
-
).
|
24
|
+
mock(:to_hash => {:ids => [1,2,3]})
|
25
|
+
).load
|
25
26
|
end
|
26
27
|
|
27
28
|
it "should try to load includes if it finds an object" do
|
28
|
-
obj_mock =
|
29
|
+
obj_mock = {:id => 1}
|
29
30
|
|
30
|
-
TestResource.expects(:
|
31
|
+
TestResource.connection.expects(:get).with("/test_resources.json").returns([obj_mock])
|
31
32
|
|
32
33
|
obj = ApiResource::Finders::ResourceFinder.new(
|
33
34
|
TestResource,
|
34
35
|
stub(:to_hash => {}, :eager_load? => false, :included_objects => [])
|
35
|
-
).
|
36
|
+
).load
|
36
37
|
|
37
|
-
|
38
|
+
# obj.first.id.should eql(1)
|
38
39
|
end
|
39
40
|
|
40
41
|
it "should load and distribute includes among the returned objects" do
|
41
|
-
inc_mock =
|
42
|
-
inc_mock2 =
|
43
|
-
|
44
|
-
tr = TestResource.new
|
45
|
-
tr.stubs(:id).returns(1)
|
46
|
-
tr.stubs(:has_many_object_ids).returns([1,2])
|
47
|
-
tr.expects(:has_many_objects=).with([inc_mock, inc_mock2])
|
48
|
-
tr.expects(:has_many_objects).returns([inc_mock, inc_mock2])
|
42
|
+
inc_mock = {:id => 1}
|
43
|
+
inc_mock2 = {:id => 2}
|
49
44
|
|
50
|
-
TestResource.expects(:
|
45
|
+
TestResource.connection.expects(:get)
|
46
|
+
.with("/test_resources.json")
|
47
|
+
.returns([{:id => 1, :has_many_object_ids => [1,2]}])
|
51
48
|
|
52
|
-
HasManyObject.expects(:
|
49
|
+
HasManyObject.connection.expects(:get)
|
50
|
+
.with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2")
|
51
|
+
.returns([inc_mock, inc_mock2])
|
53
52
|
|
54
53
|
obj = ApiResource::Finders::ResourceFinder.new(
|
55
54
|
TestResource,
|
56
55
|
stub(:to_hash => {}, :eager_load? => true, :included_objects => [:has_many_objects])
|
57
|
-
).
|
56
|
+
).load
|
58
57
|
obj.first.has_many_objects.collect(&:id).should eql([1,2])
|
59
58
|
end
|
60
59
|
|
61
60
|
it "should work with loading for multiple objects" do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
tr.expects(:has_many_objects).returns([inc_mock])
|
70
|
-
|
71
|
-
tr2 = TestResource.new
|
72
|
-
tr2.stubs(:id).returns(2)
|
73
|
-
tr2.stubs(:has_many_object_ids).returns([2])
|
74
|
-
tr2.expects(:has_many_objects=).with([inc_mock2]).returns([inc_mock2])
|
75
|
-
tr2.expects(:has_many_objects).returns([inc_mock2])
|
76
|
-
|
77
|
-
TestResource.expects(:find).with(:all, {}).returns([tr, tr2])
|
78
|
-
HasManyObject.expects(:find).with(:all, :id => [1,2]).returns([inc_mock2, inc_mock])
|
61
|
+
TestResource.connection.expects(:get).with("/test_resources.json").returns([
|
62
|
+
{:id => 1, :has_many_object_ids => [1]},
|
63
|
+
{:id => 2, :has_many_object_ids => [2]}
|
64
|
+
])
|
65
|
+
HasManyObject.connection.expects(:get)
|
66
|
+
.with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2")
|
67
|
+
.returns([{:id => 1}, {:id => 2}])
|
79
68
|
|
80
69
|
obj = ApiResource::Finders::ResourceFinder.new(
|
81
70
|
TestResource,
|
82
71
|
stub(:to_hash => {}, :eager_load? => true, :included_objects => [:has_many_objects])
|
83
|
-
).
|
72
|
+
).load
|
84
73
|
|
85
74
|
obj.first.has_many_objects.collect(&:id).should eql([1])
|
86
75
|
obj.second.has_many_objects.collect(&:id).should eql([2])
|
@@ -12,7 +12,7 @@ describe "SingleObjectAssociationFinder" do
|
|
12
12
|
ApiResource::Finders::SingleObjectAssociationFinder.new(
|
13
13
|
TestResource,
|
14
14
|
stub(:remote_path => "test_resources", :to_query => "id[]=1&id[]=2", :blank_conditions? => false)
|
15
|
-
).
|
15
|
+
).load
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should load a has many association properly" do
|
@@ -37,7 +37,7 @@ describe "SingleObjectAssociationFinder" do
|
|
37
37
|
finder.expects(:load_includes).with(:has_many_objects => [1,2]).returns(5)
|
38
38
|
finder.expects(:apply_includes).with(tr, 5).returns(6)
|
39
39
|
|
40
|
-
finder.
|
40
|
+
finder.load.should eql(tr)
|
41
41
|
end
|
42
42
|
|
43
43
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApiResource::Finders do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
TestResource.reload_resource_definition
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be able to find a single object" do
|
10
|
+
TestResource.connection.expects(:get).with("/test_resources/1.json")
|
11
|
+
|
12
|
+
TestResource.find(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to find with parameters, params syntax" do
|
16
|
+
TestResource.connection.expects(:get).with("/test_resources.json?active=true")
|
17
|
+
TestResource.all(:params => {:active => true})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should be able to find with parameters without the params syntax" do
|
21
|
+
TestResource.connection.expects(:get).with("/test_resources.json?active=true&passive=false")
|
22
|
+
|
23
|
+
TestResource.all(:active => true, :passive => false)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to chain find on top of a scope" do
|
27
|
+
TestResource.connection.expects(:get).with("/test_resources.json?active=true&passive=true")
|
28
|
+
TestResource.active.all(:passive => true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be able to chain find on top of an includes call" do
|
32
|
+
TestResource.connection.expects(:get).with("/test_resources/1.json").returns({"id" => 1, "has_many_object_ids" => [1,2]})
|
33
|
+
HasManyObject.connection.expects(:get).with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2").returns([])
|
34
|
+
|
35
|
+
TestResource.includes(:has_many_objects).find(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/spec/lib/prefixes_spec.rb
CHANGED
@@ -15,8 +15,7 @@ describe "With Prefixes" do
|
|
15
15
|
it "should use the prefix to find a single record when given as a param" do
|
16
16
|
PrefixModel.connection.expects(:get)
|
17
17
|
.with(
|
18
|
-
"/foreign/123/prefix_models/456.json"
|
19
|
-
instance_of(Hash)
|
18
|
+
"/foreign/123/prefix_models/456.json"
|
20
19
|
)
|
21
20
|
.returns({})
|
22
21
|
PrefixModel.find(456, :params => {:foreign_key_id => 123})
|
@@ -25,8 +24,7 @@ describe "With Prefixes" do
|
|
25
24
|
it "should not use the prefix to find a single record when not given as a param to avoid automatic failure" do
|
26
25
|
PrefixModel.connection.expects(:get)
|
27
26
|
.with(
|
28
|
-
"/prefix_models/456.json"
|
29
|
-
instance_of(Hash)
|
27
|
+
"/prefix_models/456.json"
|
30
28
|
)
|
31
29
|
.returns({})
|
32
30
|
PrefixModel.find(456)
|
@@ -52,8 +50,7 @@ describe "With Prefixes" do
|
|
52
50
|
it "should use the prefix to find records" do
|
53
51
|
prefix_model.send(:connection).expects(:get)
|
54
52
|
.with(
|
55
|
-
"/foreign/123/prefix_models.json"
|
56
|
-
instance_of(Hash)
|
53
|
+
"/foreign/123/prefix_models.json"
|
57
54
|
)
|
58
55
|
.returns([])
|
59
56
|
PrefixModel.first(:params => {:foreign_key_id => 123})
|
@@ -62,8 +59,7 @@ describe "With Prefixes" do
|
|
62
59
|
it "should not use the prefix to find records when not given as a param to avoid automatic failure" do
|
63
60
|
prefix_model.send(:connection).expects(:get)
|
64
61
|
.with(
|
65
|
-
"/prefix_models.json"
|
66
|
-
instance_of(Hash)
|
62
|
+
"/prefix_models.json"
|
67
63
|
)
|
68
64
|
.returns([])
|
69
65
|
PrefixModel.first
|
@@ -94,6 +90,7 @@ describe "With Prefixes" do
|
|
94
90
|
prefix_model.name = "changed name"
|
95
91
|
prefix_model.send(:connection).expects(:put)
|
96
92
|
.with(
|
93
|
+
|
97
94
|
"/foreign/123/prefix_models/456.json",
|
98
95
|
{"prefix_model" => {"name" => "changed name"}}.to_json,
|
99
96
|
instance_of(Hash)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-01-
|
14
|
+
date: 2013-01-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rake
|
@@ -237,38 +237,6 @@ dependencies:
|
|
237
237
|
- - ! '>='
|
238
238
|
- !ruby/object:Gem::Version
|
239
239
|
version: '0'
|
240
|
-
- !ruby/object:Gem::Dependency
|
241
|
-
name: differ
|
242
|
-
requirement: !ruby/object:Gem::Requirement
|
243
|
-
none: false
|
244
|
-
requirements:
|
245
|
-
- - ! '>='
|
246
|
-
- !ruby/object:Gem::Version
|
247
|
-
version: '0'
|
248
|
-
type: :development
|
249
|
-
prerelease: false
|
250
|
-
version_requirements: !ruby/object:Gem::Requirement
|
251
|
-
none: false
|
252
|
-
requirements:
|
253
|
-
- - ! '>='
|
254
|
-
- !ruby/object:Gem::Version
|
255
|
-
version: '0'
|
256
|
-
- !ruby/object:Gem::Dependency
|
257
|
-
name: colorize
|
258
|
-
requirement: !ruby/object:Gem::Requirement
|
259
|
-
none: false
|
260
|
-
requirements:
|
261
|
-
- - ! '>='
|
262
|
-
- !ruby/object:Gem::Version
|
263
|
-
version: '0'
|
264
|
-
type: :development
|
265
|
-
prerelease: false
|
266
|
-
version_requirements: !ruby/object:Gem::Requirement
|
267
|
-
none: false
|
268
|
-
requirements:
|
269
|
-
- - ! '>='
|
270
|
-
- !ruby/object:Gem::Version
|
271
|
-
version: '0'
|
272
240
|
- !ruby/object:Gem::Dependency
|
273
241
|
name: sqlite3
|
274
242
|
requirement: !ruby/object:Gem::Requirement
|
@@ -302,7 +270,7 @@ dependencies:
|
|
302
270
|
- !ruby/object:Gem::Version
|
303
271
|
version: '0'
|
304
272
|
- !ruby/object:Gem::Dependency
|
305
|
-
name:
|
273
|
+
name: json
|
306
274
|
requirement: !ruby/object:Gem::Requirement
|
307
275
|
none: false
|
308
276
|
requirements:
|
@@ -318,7 +286,7 @@ dependencies:
|
|
318
286
|
- !ruby/object:Gem::Version
|
319
287
|
version: '0'
|
320
288
|
- !ruby/object:Gem::Dependency
|
321
|
-
name:
|
289
|
+
name: rest-client
|
322
290
|
requirement: !ruby/object:Gem::Requirement
|
323
291
|
none: false
|
324
292
|
requirements:
|
@@ -334,7 +302,7 @@ dependencies:
|
|
334
302
|
- !ruby/object:Gem::Version
|
335
303
|
version: '0'
|
336
304
|
- !ruby/object:Gem::Dependency
|
337
|
-
name:
|
305
|
+
name: log4r
|
338
306
|
requirement: !ruby/object:Gem::Requirement
|
339
307
|
none: false
|
340
308
|
requirements:
|
@@ -350,7 +318,7 @@ dependencies:
|
|
350
318
|
- !ruby/object:Gem::Version
|
351
319
|
version: '0'
|
352
320
|
- !ruby/object:Gem::Dependency
|
353
|
-
name:
|
321
|
+
name: differ
|
354
322
|
requirement: !ruby/object:Gem::Requirement
|
355
323
|
none: false
|
356
324
|
requirements:
|
@@ -366,7 +334,7 @@ dependencies:
|
|
366
334
|
- !ruby/object:Gem::Version
|
367
335
|
version: '0'
|
368
336
|
- !ruby/object:Gem::Dependency
|
369
|
-
name:
|
337
|
+
name: colorize
|
370
338
|
requirement: !ruby/object:Gem::Requirement
|
371
339
|
none: false
|
372
340
|
requirements:
|
@@ -432,6 +400,7 @@ files:
|
|
432
400
|
- lib/api_resource/finders/abstract_finder.rb
|
433
401
|
- lib/api_resource/finders/multi_object_association_finder.rb
|
434
402
|
- lib/api_resource/finders/resource_finder.rb
|
403
|
+
- lib/api_resource/finders/single_finder.rb
|
435
404
|
- lib/api_resource/finders/single_object_association_finder.rb
|
436
405
|
- lib/api_resource/formats.rb
|
437
406
|
- lib/api_resource/formats/json_format.rb
|
@@ -464,6 +433,7 @@ files:
|
|
464
433
|
- spec/lib/finders/multi_object_association_finder_spec.rb
|
465
434
|
- spec/lib/finders/resource_finder_spec.rb
|
466
435
|
- spec/lib/finders/single_object_association_finder_spec.rb
|
436
|
+
- spec/lib/finders_spec.rb
|
467
437
|
- spec/lib/local_spec.rb
|
468
438
|
- spec/lib/mocks_spec.rb
|
469
439
|
- spec/lib/model_errors_spec.rb
|
@@ -523,6 +493,7 @@ test_files:
|
|
523
493
|
- spec/lib/finders/multi_object_association_finder_spec.rb
|
524
494
|
- spec/lib/finders/resource_finder_spec.rb
|
525
495
|
- spec/lib/finders/single_object_association_finder_spec.rb
|
496
|
+
- spec/lib/finders_spec.rb
|
526
497
|
- spec/lib/local_spec.rb
|
527
498
|
- spec/lib/mocks_spec.rb
|
528
499
|
- spec/lib/model_errors_spec.rb
|