api_resource 0.5.1 → 0.6.0

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.
Files changed (163) hide show
  1. data/.document +5 -0
  2. data/.gitignore +55 -0
  3. data/.rspec +8 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +3 -36
  6. data/Gemfile.lock +37 -57
  7. data/Guardfile +7 -1
  8. data/{LICENSE.txt → LICENSE} +4 -2
  9. data/README.md +29 -0
  10. data/README.rdoc +5 -1
  11. data/Rakefile +5 -36
  12. data/api_resource.gemspec +40 -104
  13. data/lib/api_resource.rb +4 -1
  14. data/lib/api_resource/associations.rb +30 -14
  15. data/lib/api_resource/associations/association_proxy.rb +97 -0
  16. data/lib/api_resource/associations/belongs_to_remote_object_proxy.rb +0 -1
  17. data/lib/api_resource/associations/has_many_remote_object_proxy.rb +0 -1
  18. data/lib/api_resource/associations/has_one_remote_object_proxy.rb +7 -4
  19. data/lib/api_resource/associations/multi_object_proxy.rb +11 -16
  20. data/lib/api_resource/associations/single_object_proxy.rb +8 -6
  21. data/lib/api_resource/attributes.rb +29 -41
  22. data/lib/api_resource/base.rb +31 -102
  23. data/lib/api_resource/conditions.rb +36 -0
  24. data/lib/api_resource/conditions/abstract_condition.rb +112 -0
  25. data/lib/api_resource/conditions/association_condition.rb +18 -0
  26. data/lib/api_resource/conditions/include_condition.rb +16 -0
  27. data/lib/api_resource/conditions/multi_object_association_condition.rb +17 -0
  28. data/lib/api_resource/conditions/scope_condition.rb +11 -0
  29. data/lib/api_resource/conditions/single_object_association_condition.rb +19 -0
  30. data/lib/api_resource/connection.rb +18 -12
  31. data/lib/api_resource/finders.rb +122 -0
  32. data/lib/api_resource/finders/abstract_finder.rb +89 -0
  33. data/lib/api_resource/finders/multi_object_association_finder.rb +39 -0
  34. data/lib/api_resource/finders/resource_finder.rb +33 -0
  35. data/lib/api_resource/finders/single_object_association_finder.rb +40 -0
  36. data/lib/api_resource/observing.rb +19 -3
  37. data/lib/api_resource/scopes.rb +3 -3
  38. data/lib/api_resource/typecast.rb +85 -0
  39. data/lib/api_resource/typecasters/array_typecaster.rb +19 -0
  40. data/lib/api_resource/typecasters/boolean_typecaster.rb +22 -0
  41. data/lib/api_resource/typecasters/date_typecaster.rb +35 -0
  42. data/lib/api_resource/typecasters/float_typecaster.rb +22 -0
  43. data/lib/api_resource/typecasters/integer_typecaster.rb +22 -0
  44. data/lib/api_resource/typecasters/string_typecaster.rb +19 -0
  45. data/lib/api_resource/typecasters/time_typecaster.rb +44 -0
  46. data/lib/api_resource/version.rb +3 -0
  47. data/spec/lib/api_resource_spec.rb +6 -0
  48. data/spec/lib/associations/association_scope_spec.rb +1 -1
  49. data/spec/lib/associations_spec.rb +17 -50
  50. data/spec/lib/base_spec.rb +22 -0
  51. data/spec/lib/conditions/abstract_conditions_spec.rb +78 -0
  52. data/spec/lib/connection_spec.rb +19 -0
  53. data/spec/lib/finders/multi_object_association_finder_spec.rb +43 -0
  54. data/spec/lib/finders/resource_finder_spec.rb +89 -0
  55. data/spec/lib/finders/single_object_association_finder_spec.rb +43 -0
  56. data/spec/lib/observing_spec.rb +96 -0
  57. data/spec/lib/typecast_spec.rb +174 -0
  58. data/spec/lib/typecasters/boolean_typecaster_spec.rb +33 -0
  59. data/spec/lib/typecasters/date_typecaster_spec.rb +62 -0
  60. data/spec/lib/typecasters/float_typecaster_spec.rb +39 -0
  61. data/spec/lib/typecasters/integer_typecaster_spec.rb +40 -0
  62. data/spec/lib/typecasters/string_typecaster_spec.rb +28 -0
  63. data/spec/lib/typecasters/time_typecaster_spec.rb +65 -0
  64. data/spec/spec_helper.rb +0 -1
  65. metadata +134 -194
  66. data/VERSION +0 -1
  67. data/coverage/assets/0.5.3/app.js +0 -88
  68. data/coverage/assets/0.5.3/fancybox/blank.gif +0 -0
  69. data/coverage/assets/0.5.3/fancybox/fancy_close.png +0 -0
  70. data/coverage/assets/0.5.3/fancybox/fancy_loading.png +0 -0
  71. data/coverage/assets/0.5.3/fancybox/fancy_nav_left.png +0 -0
  72. data/coverage/assets/0.5.3/fancybox/fancy_nav_right.png +0 -0
  73. data/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png +0 -0
  74. data/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png +0 -0
  75. data/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png +0 -0
  76. data/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png +0 -0
  77. data/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png +0 -0
  78. data/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png +0 -0
  79. data/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png +0 -0
  80. data/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png +0 -0
  81. data/coverage/assets/0.5.3/fancybox/fancy_title_left.png +0 -0
  82. data/coverage/assets/0.5.3/fancybox/fancy_title_main.png +0 -0
  83. data/coverage/assets/0.5.3/fancybox/fancy_title_over.png +0 -0
  84. data/coverage/assets/0.5.3/fancybox/fancy_title_right.png +0 -0
  85. data/coverage/assets/0.5.3/fancybox/fancybox-x.png +0 -0
  86. data/coverage/assets/0.5.3/fancybox/fancybox-y.png +0 -0
  87. data/coverage/assets/0.5.3/fancybox/fancybox.png +0 -0
  88. data/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css +0 -363
  89. data/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
  90. data/coverage/assets/0.5.3/favicon_green.png +0 -0
  91. data/coverage/assets/0.5.3/favicon_red.png +0 -0
  92. data/coverage/assets/0.5.3/favicon_yellow.png +0 -0
  93. data/coverage/assets/0.5.3/highlight.css +0 -129
  94. data/coverage/assets/0.5.3/highlight.pack.js +0 -1
  95. data/coverage/assets/0.5.3/jquery-1.6.2.min.js +0 -18
  96. data/coverage/assets/0.5.3/jquery.dataTables.min.js +0 -152
  97. data/coverage/assets/0.5.3/jquery.timeago.js +0 -141
  98. data/coverage/assets/0.5.3/jquery.url.js +0 -174
  99. data/coverage/assets/0.5.3/loading.gif +0 -0
  100. data/coverage/assets/0.5.3/magnify.png +0 -0
  101. data/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  102. data/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  103. data/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  104. data/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  105. data/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  106. data/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  107. data/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  108. data/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  109. data/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png +0 -0
  110. data/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  111. data/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png +0 -0
  112. data/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png +0 -0
  113. data/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  114. data/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css +0 -295
  115. data/coverage/assets/0.5.3/stylesheet.css +0 -383
  116. data/coverage/assets/0.7.1/application.css +0 -1110
  117. data/coverage/assets/0.7.1/application.js +0 -626
  118. data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
  119. data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
  120. data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
  121. data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
  122. data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
  123. data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
  124. data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
  125. data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
  126. data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
  127. data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
  128. data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
  129. data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
  130. data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
  131. data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
  132. data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
  133. data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
  134. data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
  135. data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
  136. data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
  137. data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
  138. data/coverage/assets/0.7.1/favicon_green.png +0 -0
  139. data/coverage/assets/0.7.1/favicon_red.png +0 -0
  140. data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
  141. data/coverage/assets/0.7.1/loading.gif +0 -0
  142. data/coverage/assets/0.7.1/magnify.png +0 -0
  143. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  144. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  145. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  146. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  147. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  148. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  149. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  150. data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  151. data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
  152. data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  153. data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
  154. data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
  155. data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  156. data/coverage/index.html +0 -3564
  157. data/lib/api_resource/associations/abstract_scope.rb +0 -191
  158. data/lib/api_resource/associations/association_scope.rb +0 -47
  159. data/lib/api_resource/associations/resource_scope.rb +0 -21
  160. data/lib/api_resource/associations/scope.rb +0 -34
  161. data/spec/lib/associations/resource_scope_spec.rb +0 -24
  162. data/spec/tmp/api_resource_test_db.sqlite +0 -0
  163. data/tmp/rspec_guard_result +0 -1
@@ -6,6 +6,30 @@ require 'active_support/string_inquirer'
6
6
  module ApiResource
7
7
 
8
8
  class Base
9
+
10
+ # TODO: There's way too much in this class as it stands, some glaring problems:
11
+ # => 1) class_attributes for connection options belong in the connection class
12
+ # => 2) Attributes about serialization belong with the serializers
13
+ # => 3) Logging seems to be an unmitigated disaster
14
+ # => 4) All the resource definition should be in its own module with the data mapper implementation
15
+ # => 5) Random shit about tokens all over the place, clearly does not belong
16
+ # => 6) Everything related to the pathing should go somewhere by itself
17
+ # => 7) Everything about saving should go in a persistence module
18
+ # => 8) Everything about loading data should go in a Finder module
19
+ # => 9) Delete serializable_hash and start again
20
+ # => 10) setup_create_call and setup_update_call should modify the results from another method
21
+ # => 11) nil_attributes probably belongs with the attributes
22
+ # => 12) Add instrumentation in some key places
23
+
24
+ # Other Random TODOs:
25
+ # => 1) Profile and benchmark this code
26
+ # => 2) Deal with arrays and hashes as attributes in a more reasonable way
27
+ # => 3) Finish implementing typecasting (to_api portion)
28
+ # => 4) Add a reasonable way to load and activate observers, verify that it works
29
+ # => 5) Hook up the custom_methods module
30
+ # => 6) Implement an IdentityMap
31
+ # => 7) Write documentation
32
+ # => 8) Write Examples
9
33
 
10
34
  class_attribute :site, :proxy, :user, :password, :auth_type, :format,
11
35
  :timeout, :open_timeout, :ssl_options, :token, :ttl
@@ -297,51 +321,6 @@ module ApiResource
297
321
  def create(attributes = {})
298
322
  self.new(attributes).tap{ |resource| resource.save }
299
323
  end
300
-
301
- # This decides which finder method to call.
302
- # It accepts arguments of the form "scope", "options={}"
303
- # where options can be standard rails options or :expires_in.
304
- # If :expires_in is set, it caches it for expires_in seconds.
305
- def find(*arguments)
306
-
307
- # make sure we have class data before loading
308
- self.load_resource_definition
309
-
310
- scope = arguments.slice!(0)
311
- options = arguments.slice!(0) || {}
312
-
313
- expiry = options.delete(:expires_in) || ApiResource::Base.ttl || 0
314
- ApiResource.with_ttl(expiry.to_f) do
315
- case scope
316
- when :all then find_every(options)
317
- when :first then find_every(options).first
318
- when :last then find_every(options).last
319
- when :one then find_one(options)
320
- else find_single(scope, options)
321
- end
322
- end
323
- end
324
-
325
-
326
- # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass
327
- # in all the same arguments to this method as you can to
328
- # <tt>find(:first)</tt>.
329
- def first(*args)
330
- find(:first, *args)
331
- end
332
-
333
- # A convenience wrapper for <tt>find(:last, *args)</tt>. You can pass
334
- # in all the same arguments to this method as you can to
335
- # <tt>find(:last)</tt>.
336
- def last(*args)
337
- find(:last, *args)
338
- end
339
-
340
- # This is an alias for find(:all). You can pass in all the same
341
- # arguments to this method as you can to <tt>find(:all)</tt>
342
- def all(*args)
343
- find(:all, *args)
344
- end
345
324
 
346
325
 
347
326
  # Deletes the resources with the ID in the +id+ parameter.
@@ -362,24 +341,6 @@ module ApiResource
362
341
  connection.delete(element_path(id, options))
363
342
  end
364
343
 
365
- def instantiate_collection(collection)
366
- collection.collect{|record|
367
- instantiate_record(record)
368
- }
369
- end
370
-
371
- def instantiate_record(record)
372
- self.load_resource_definition
373
- ret = self.allocate
374
- ret.instance_variable_set(
375
- :@attributes, record.with_indifferent_access
376
- )
377
- ret.instance_variable_set(
378
- :@attributes_cache, HashWithIndifferentAccess.new
379
- )
380
- ret
381
- end
382
-
383
344
  protected
384
345
  def method_missing(meth, *args, &block)
385
346
  # make one attempt to load remote attrs
@@ -390,44 +351,6 @@ module ApiResource
390
351
  end
391
352
 
392
353
  private
393
- # Find every resource
394
- def find_every(options)
395
- begin
396
- case from = options[:from]
397
- when Symbol
398
- instantiate_collection(get(from, options[:params]))
399
- when String
400
- path = "#{from}#{query_string(options[:params])}"
401
- instantiate_collection(connection.get(path, headers) || [])
402
- else
403
- prefix_options, query_options = split_options(options[:params])
404
- path = collection_path(prefix_options, query_options)
405
- instantiate_collection( (connection.get(path, headers) || []))
406
- end
407
- rescue ApiResource::ResourceNotFound
408
- # Swallowing ResourceNotFound exceptions and return nil - as per
409
- # ActiveRecord.
410
- nil
411
- end
412
- end
413
-
414
- # Find a single resource from a one-off URL
415
- def find_one(options)
416
- case from = options[:from]
417
- when Symbol
418
- instantiate_record(get(from, options[:params]))
419
- when String
420
- path = "#{from}#{query_string(options[:params])}"
421
- instantiate_record(connection.get(path, headers))
422
- end
423
- end
424
-
425
- # Find a single resource from the default URL
426
- def find_single(scope, options)
427
- prefix_options, query_options = split_options(options[:params])
428
- path = element_path(scope, prefix_options, query_options)
429
- instantiate_record(connection.get(path, headers))
430
- end
431
354
 
432
355
  # Accepts a URI and creates the site URI from that.
433
356
  def create_site_uri_from(site)
@@ -582,6 +505,10 @@ module ApiResource
582
505
  self.class.include_root_in_json ? {self.class.element_name => self.serializable_hash(options)}.to_json : self.serializable_hash(options).to_json
583
506
  end
584
507
 
508
+ # TODO: this method needs to change seriously to fit in with the
509
+ # new typecasting scheme, it should call self.outgoing_attributes which
510
+ # should return the converted versions after calling to_api, that should
511
+ # be implemented in the attributes module though
585
512
  def serializable_hash(options = {})
586
513
 
587
514
  action = options[:action]
@@ -683,6 +610,7 @@ module ApiResource
683
610
  opts[:include_associations] = opts[:include_associations] ? opts[:include_associations].concat(args) : []
684
611
  opts[:include_extras] ||= []
685
612
  opts[:action] = "create"
613
+ # TODO: Remove this dependency for saving files
686
614
  body = RestClient::Payload.has_file?(self.attributes) ? self.serializable_hash(opts) : encode(opts)
687
615
  end
688
616
 
@@ -706,6 +634,7 @@ module ApiResource
706
634
  opts[:include_extras] ||= []
707
635
  opts[:action] = "update"
708
636
  opts[:except] = [:id] if self.class.include_all_attributes_on_update
637
+ # TODO: Remove this dependency for saving files
709
638
  body = RestClient::Payload.has_file?(self.attributes) ? self.serializable_hash(opts) : encode(opts)
710
639
  end
711
640
 
@@ -724,7 +653,7 @@ module ApiResource
724
653
  include AssociationActivation
725
654
  self.activate_associations
726
655
 
727
- include Scopes, Callbacks, Attributes, ModelErrors
656
+ include Scopes, Callbacks, Observing, Attributes, ModelErrors, Conditions, Finders
728
657
 
729
658
  end
730
659
 
@@ -0,0 +1,36 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ extend ActiveSupport::Autoload
6
+ extend ActiveSupport::Concern
7
+
8
+ autoload :AbstractCondition
9
+ autoload :AssociationCondition
10
+ autoload :SingleObjectAssociationCondition
11
+ autoload :MultiObjectAssociationCondition
12
+ autoload :IncludeCondition
13
+ autoload :ScopeCondition
14
+
15
+ module ClassMethods
16
+
17
+ def includes(*args)
18
+
19
+ # everything in args must be an association
20
+ args.each do |arg|
21
+ unless self.association?(arg)
22
+ raise ArgumentError, "Unknown association #{arg} to eager load"
23
+ end
24
+ end
25
+
26
+ # Everything looks good so just create the scope
27
+ ApiResource::Conditions::IncludeCondition.new(self, args)
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+
36
+ end
@@ -0,0 +1,112 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ class AbstractCondition
6
+
7
+ include Enumerable
8
+
9
+ attr_reader :conditions, :klass, :included_objects, :internal_object, :association,
10
+ :remote_path
11
+
12
+ # TODO: add the other load forcing methods here for collections
13
+ delegate :[], :[]=, :<<, :first, :second, :last, :blank?, :nil?, :include?, :push, :pop,
14
+ :+, :concat, :flatten, :flatten!, :compact, :compact!, :empty?, :fetch, :map,
15
+ :reject, :reject!, :reverse, :select, :select!, :size, :sort, :sort!, :uniq, :uniq!,
16
+ :to_a, :sample, :slice, :slice!, :count, :present?, :to => :internal_object
17
+
18
+ # need to figure out what to do with args in the subclass,
19
+ # parent is the set of scopes we have right now
20
+ def initialize(args, klass)
21
+ @klass = klass
22
+
23
+ @conditions = args.with_indifferent_access
24
+ end
25
+
26
+ def each(&block)
27
+ self.internal_object.each(&block)
28
+ end
29
+
30
+ def blank_conditions?
31
+ self.conditions.blank?
32
+ end
33
+
34
+ def eager_load?
35
+ self.included_objects.present?
36
+ end
37
+
38
+ def included_objects
39
+ Array.wrap(@included_objects)
40
+ end
41
+
42
+ def to_query
43
+ CGI.unescape(to_query_safe_hash(self.to_hash).to_query)
44
+ end
45
+
46
+ def to_hash
47
+ self.conditions
48
+ end
49
+
50
+ def internal_object
51
+ @internal_object ||= begin
52
+ @loaded = true
53
+ self.instantiate_finder.find
54
+ end
55
+ end
56
+
57
+ alias_method :find, :internal_object
58
+ alias_method :all, :internal_object
59
+
60
+ def loaded?
61
+ @loaded == true
62
+ end
63
+
64
+ def reload
65
+ if instance_variable_defined?(:@internal_object)
66
+ remove_instance_variable(:@internal_object)
67
+ end
68
+ @loaded = false
69
+ end
70
+
71
+ def method_missing(sym, *args, &block)
72
+ result = @klass.send(sym, *args, &block)
73
+
74
+ if result.is_a?(ApiResource::Conditions::AbstractCondition)
75
+ return self.dup.merge!(result)
76
+ else
77
+ return result
78
+ end
79
+ end
80
+
81
+ def expires_in(time)
82
+ ApiResource::Decorators::CachingDecorator.new(self, time)
83
+ end
84
+
85
+ # TODO: Remove the bang, this doesn't modify anything
86
+ def merge!(cond)
87
+ @included_objects = (@included_objects || []).concat(cond.included_objects || []).uniq
88
+ @conditions = @conditions.merge(cond.to_hash)
89
+ @association = cond.association || self.association
90
+ @remote_path = self.remote_path ? self.remote_path : cond.remote_path
91
+ return self
92
+ end
93
+
94
+ protected
95
+
96
+ def instantiate_finder
97
+ ApiResource::Finders::ResourceFinder.new(self.klass, self)
98
+ end
99
+
100
+ def to_query_safe_hash(hash)
101
+ hash.each_pair do |k,v|
102
+ hash[k] = to_query_safe_hash(v) if v.is_a?(Hash)
103
+ hash[k] = true if v == {}
104
+ end
105
+ return hash
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,18 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ class AssociationCondition < AbstractCondition
6
+
7
+ def initialize(klass, service_uri)
8
+ super({}, klass)
9
+
10
+ @assocaiton = true
11
+ @remote_path = service_uri
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,16 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ class IncludeCondition < AbstractCondition
6
+
7
+ def initialize(klass, incs)
8
+ super({}, klass)
9
+ @included_objects = Array.wrap(incs)
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,17 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ class MultiObjectAssociationCondition < AssociationCondition
6
+
7
+ protected
8
+
9
+ def instantiate_finder
10
+ ApiResource::Finders::MultiObjectAssociationFinder.new(self.klass, self)
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,11 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ class ScopeCondition < AbstractCondition
6
+
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,19 @@
1
+ module ApiResource
2
+
3
+ module Conditions
4
+
5
+ # Special class for passing into a finder object
6
+ # just defines all the proper methods
7
+ class SingleObjectAssociationCondition < AssociationCondition
8
+
9
+ protected
10
+
11
+ def instantiate_finder
12
+ ApiResource::Finders::SingleObjectAssociationFinder.new(self.klass, self)
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -70,22 +70,28 @@ module ApiResource
70
70
  request(:head, path, build_request_headers(headers, :head, self.site.merge(path)))
71
71
  end
72
72
 
73
-
73
+ # make a put request
74
74
  def put(path, body = {}, headers = self.headers)
75
- # If there's a file to send then we can't use JSON or XML
76
- if !body.is_a?(String) && RestClient::Payload.has_file?(body)
77
- format.decode(request(:put, path, body, build_request_headers(headers, :put, self.site.merge(path))))
78
- else
79
- format.decode(request(:put, path, body, build_request_headers(headers, :put, self.site.merge(path))))
80
- end
75
+ format.decode(
76
+ request(
77
+ :put,
78
+ path,
79
+ body,
80
+ build_request_headers(headers, :put, self.site.merge(path))
81
+ )
82
+ )
81
83
  end
82
84
 
85
+ # make a post request
83
86
  def post(path, body = {}, headers = self.headers)
84
- if !body.is_a?(String) && RestClient::Payload.has_file?(body)
85
- format.decode(request(:post, path, body, build_request_headers(headers, :post, self.site.merge(path))))
86
- else
87
- format.decode(request(:post, path, body, build_request_headers(headers, :post, self.site.merge(path))))
88
- end
87
+ format.decode(
88
+ request(
89
+ :post,
90
+ path,
91
+ body,
92
+ build_request_headers(headers, :post, self.site.merge(path))
93
+ )
94
+ )
89
95
  end
90
96
 
91
97
  protected