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
@@ -0,0 +1,19 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ module ArrayTypecaster
6
+
7
+ def self.from_api(value)
8
+ return Array.wrap(value)
9
+ end
10
+
11
+ def self.to_api(value)
12
+ return Array.wrap(value)
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,22 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
6
+ FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
7
+
8
+ module BooleanTypecaster
9
+
10
+ def self.from_api(value)
11
+ TRUE_VALUES.include?(value)
12
+ end
13
+
14
+ def self.to_api(value)
15
+ value
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,35 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
6
+
7
+ module DateTypecaster
8
+
9
+ def self.from_api(value)
10
+ return value if value.is_a?(Date)
11
+
12
+ value = value.to_s
13
+ if value =~ ApiResource::Typecast::ISO_DATE
14
+ return self.new_date($1.to_i, $2.to_i, $3.to_i)
15
+ end
16
+
17
+ self.new_date(*::Date._parse(value, false).values_at(:year, :mon, :mday))
18
+ end
19
+
20
+ def self.to_api(value)
21
+ return value.to_s
22
+ end
23
+
24
+ protected
25
+
26
+ def self.new_date(year, month, day)
27
+ return nil unless year && year != 0
28
+ return Date.new(year, month, day) rescue nil
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,22 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ module FloatTypecaster
6
+
7
+ def self.from_api(value)
8
+ return value.to_f if value.respond_to?(:to_f)
9
+ # Special case for true to return 1.0
10
+ return 1.0 if value.class == TrueClass
11
+ return value.to_s.to_f
12
+ end
13
+
14
+ def self.to_api(value)
15
+ value
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ module IntegerTypecaster
6
+
7
+ def self.from_api(value)
8
+ return value.to_i if value.respond_to?(:to_i)
9
+ # Special case so that true typecasts to 1
10
+ return 1 if value.class == TrueClass
11
+ return value.to_s.to_i
12
+ end
13
+
14
+ def self.to_api(value)
15
+ value
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,19 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ module StringTypecaster
6
+
7
+ def self.from_api(value)
8
+ return value.to_s
9
+ end
10
+
11
+ def self.to_api(value)
12
+ return value
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,44 @@
1
+ require 'active_support/time'
2
+
3
+ module ApiResource
4
+
5
+ module Typecast
6
+
7
+ ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
8
+
9
+ module TimeTypecaster
10
+
11
+ def self.from_api(value)
12
+ return value if value.is_a?(Time)
13
+ value = value.to_s
14
+ return nil if value.empty?
15
+
16
+ if value =~ ApiResource::Typecast::ISO_DATETIME
17
+ micro = ($7.to_f * 1_000_000).to_i
18
+ return self.new_time($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, micro)
19
+ end
20
+
21
+ time_info = Date._parse(value)
22
+ time_info[:micro] = ((time_info[:sec_fraction].to_f % 1) * 1_000_000).to_i
23
+
24
+ new_time(*time_info.values_at(:year, :mon, :mday, :hour, :min, :sec, :micro))
25
+
26
+ end
27
+
28
+ def self.to_api(value)
29
+ return value.to_s
30
+ end
31
+
32
+ protected
33
+
34
+ def self.new_time(*args)
35
+ year = args.first
36
+ return nil if year.nil? || year == 0
37
+ Time.utc(*args) rescue nil
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ module ApiResource
2
+ VERSION = "0.6.0"
3
+ end
@@ -4,6 +4,12 @@ describe ApiResource do
4
4
 
5
5
  context ".cache" do
6
6
 
7
+ before(:each) do
8
+ if defined?(Rails)
9
+ Object.send(:remove_const, :Rails)
10
+ end
11
+ end
12
+
7
13
  after(:each) do
8
14
  if defined?(Rails)
9
15
  Object.send(:remove_const, :Rails)
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ApiResource::Associations::AssociationScope do
3
+ describe ApiResource::Associations::AssociationProxy do
4
4
 
5
5
  before(:all) do
6
6
  TestResource.reload_resource_definition
@@ -81,6 +81,13 @@ describe "Associations" do
81
81
  TestResource.association_class_name(:strange_name).should eql("BelongsToObject")
82
82
  end
83
83
 
84
+ it "should be able to return the name of the foreign key field field for the association" do
85
+ TestResource.belongs_to :belongs_to_object
86
+ TestResource.has_many :has_many_objects
87
+ TestResource.association_foreign_key_field(:belongs_to_object).should eql(:belongs_to_object_id)
88
+ TestResource.association_foreign_key_field(:has_many_objects).should eql(:has_many_object_ids)
89
+ end
90
+
84
91
  it "should only define relationships for the given class - they should not cascade" do
85
92
  TestResource.belongs_to :belongs_to_object
86
93
  AnotherTestResource.association?(:belongs_to_object).should_not be_true
@@ -338,38 +345,6 @@ describe "Associations" do
338
345
  end
339
346
  end
340
347
 
341
- context "Defining scopes" do
342
-
343
- it "should identify known scopes based on the scopes defined on
344
- the object it is a proxy to" do
345
-
346
- TestResource.scope :class_scope, "class_scope" => "true"
347
-
348
- ap = Associations::MultiObjectProxy.new(
349
- "TestResource",
350
- BelongsToObject.new,
351
- [{:service_uri => "/route"}]
352
- )
353
- ap.scope?(:class_scope).should be_true
354
- end
355
-
356
- it "scopes in the response should shadow class defined scopes" do
357
- TestResource.scope(:scope1, "scope1" => "true")
358
- ap = Associations::MultiObjectProxy.new(
359
- "TestResource",
360
- BelongsToObject.new,
361
- [
362
- {
363
- :service_uri => "/route",
364
- :scope1 => {"scope1" => true},
365
- :scope2 => {"scope2" => true}
366
- }
367
- ]
368
- )
369
- ap.scopes[:scope1].should eql({"scope1" => true})
370
- end
371
- end
372
-
373
348
  end
374
349
 
375
350
  describe "Selecting scopes" do
@@ -421,6 +396,12 @@ describe "Associations" do
421
396
 
422
397
  describe "Loading and Caching loaded data" do
423
398
 
399
+
400
+ before(:each) do
401
+ # Clear the cache to prevent any funny business
402
+ ApiResource.cache(true)
403
+ end
404
+
424
405
  context "Single Object" do
425
406
 
426
407
  before(:all) do
@@ -460,9 +441,8 @@ describe "Associations" do
460
441
  ap.active.expires_in(30).internal_object
461
442
 
462
443
  # should only be called once
463
- TestResource.connection.expects(:get).never
444
+ TestResource.connection.expects(:request).never
464
445
  ap.active.expires_in(30).internal_object
465
- ap.should be_loaded
466
446
  end
467
447
 
468
448
  it "should check that ttl matches the expiration parameter" do
@@ -545,19 +525,6 @@ describe "Associations" do
545
525
  ap.first.name.should eql old_name
546
526
  end
547
527
 
548
- it "should propagate the scopes from the associated class" do
549
-
550
- ap = Associations::MultiObjectProxy.new(
551
- "TestResource",
552
- BelongsToObject.new, {
553
- :service_uri => '/multi_object_association'
554
- }
555
- )
556
- ap.scopes.should eql(TestResource.scopes)
557
- true
558
- end
559
-
560
-
561
528
  context "Multi Object" do
562
529
 
563
530
  it "should be able to load 'all'" do
@@ -642,13 +609,13 @@ describe "Associations" do
642
609
  end
643
610
  end
644
611
 
645
- it "should return a ResourceScope when calling any scope on a class" do
646
- TestResource.send(TestResource.scopes.first.first.to_sym).should be_a Associations::ResourceScope
612
+ it "should return a ScopeCondition when calling any scope on a class" do
613
+ TestResource.send(TestResource.scopes.first.first.to_sym).should be_a Conditions::ScopeCondition
647
614
  end
648
615
 
649
616
  it "should be able to chain scopes" do
650
617
  scp = TestResource.active.paginate(20, 1)
651
- scp.should be_a Associations::Scope
618
+ scp.should be_a Conditions::ScopeCondition
652
619
  scp.to_query.should eql(
653
620
  "active=true&paginate[current_page]=1&paginate[per_page]=20"
654
621
  )
@@ -38,6 +38,27 @@ describe "Base" do
38
38
 
39
39
  end
40
40
 
41
+ context ".load_resource_definition" do
42
+
43
+ it "should not inherit from unrelated objects" do
44
+
45
+ ErrorResource.new
46
+ orig_public_attr_names = ErrorResource.public_attribute_names
47
+ orig_protected_attr_names = ErrorResource.protected_attribute_names
48
+
49
+ TestResource.new
50
+
51
+ ErrorResource.public_attribute_names.should eql(
52
+ orig_public_attr_names
53
+ )
54
+ ErrorResource.protected_attribute_names.should eql(
55
+ orig_protected_attr_names
56
+ )
57
+ true
58
+ end
59
+
60
+ end
61
+
41
62
  context "Comparison" do
42
63
 
43
64
  context "&group_by" do
@@ -516,6 +537,7 @@ describe "Base" do
516
537
  context "Updating old records" do
517
538
  before(:all) do
518
539
  TestResource.reload_resource_definition
540
+ HasOneObject.reload_resource_definition
519
541
  TestResource.has_many :has_many_objects
520
542
  RestClient::Payload.stubs(:has_file? => false)
521
543
  end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Conditions" do
4
+
5
+ before(:each) do
6
+ TestResource.reload_resource_definition
7
+ end
8
+
9
+ it "should chain scopes onto the base class" do
10
+
11
+ obj = TestResource.active
12
+ obj.should be_a ApiResource::Conditions::ScopeCondition
13
+
14
+ obj2 = TestResource.paginate
15
+
16
+ TestResource.expects(:paginate).returns(obj2)
17
+
18
+ obj3 = obj.paginate
19
+
20
+ obj3.to_query.should eql("active=true&paginate=true")
21
+ obj3.should_not be_eager_load
22
+ obj3.should_not be_blank_conditions
23
+ # Make sure that it clones
24
+
25
+ obj3.object_id.should_not eql(obj.object_id)
26
+ obj3.object_id.should_not eql(obj2.object_id)
27
+ end
28
+
29
+ it "should properly deal with calling includes" do
30
+ obj = TestResource.includes(:has_many_objects).active
31
+
32
+ obj.should be_eager_load
33
+ obj.should_not be_blank_conditions
34
+ obj.association.should be_nil
35
+ obj.to_query.should eql("active=true")
36
+ obj.included_objects.should eql([:has_many_objects])
37
+ end
38
+
39
+ it "should be able to chain includes and scopes" do
40
+ obj = TestResource.includes(:has_many_objects).active.includes(:belongs_to_object)
41
+
42
+ obj.should be_eager_load
43
+ obj.should_not be_blank_conditions
44
+ obj.included_objects.should eql([:has_many_objects, :belongs_to_object])
45
+ end
46
+
47
+ it "should be able to include multiple includes in the same call" do
48
+ obj = TestResource.includes(:has_many_objects, :belongs_to_object)
49
+
50
+ obj.should be_eager_load
51
+ obj.should be_blank_conditions
52
+ obj.included_objects.should eql([:has_many_objects, :belongs_to_object])
53
+ end
54
+
55
+ it "should raise an error if given an include that isn't a valid association" do
56
+ lambda {
57
+ TestResource.includes(:fake_assoc)
58
+ }.should raise_error
59
+ end
60
+
61
+ it "should create a resource finder when forced to load, and cache the result" do
62
+ obj = TestResource.includes(:has_many_objects)
63
+
64
+ ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:find => [1]))
65
+ obj.internal_object.should eql([1])
66
+ obj.all.should eql([1])
67
+ obj.first.should eql(1)
68
+ end
69
+
70
+ it "should proxy calls to enumerable and array methods to the loaded object" do
71
+ obj = TestResource.includes(:has_many_objects)
72
+
73
+ ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:find => [1,2]))
74
+
75
+ obj.collect{|o| o * 2}.should eql([2,4])
76
+ end
77
+
78
+ end