api_resource 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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