api_resource 0.6.21 → 0.6.22

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/Gemfile.lock +1 -1
  4. data/LICENSE.txt +22 -0
  5. data/README.md +16 -9
  6. data/docs/Attributes.md +64 -0
  7. data/docs/Caching.md +45 -0
  8. data/docs/GettingStarted.md +149 -0
  9. data/docs/Relationships.md +136 -0
  10. data/docs/ResourceDefinition.md +80 -0
  11. data/docs/Retrieval.md +279 -0
  12. data/docs/Serialization.md +56 -0
  13. data/lib/api_resource/associations/has_many_remote_object_proxy.rb +2 -2
  14. data/lib/api_resource/attributes.rb +16 -4
  15. data/lib/api_resource/base.rb +98 -19
  16. data/lib/api_resource/conditions/abstract_condition.rb +241 -129
  17. data/lib/api_resource/conditions/include_condition.rb +7 -1
  18. data/lib/api_resource/conditions/pagination_condition.rb +37 -0
  19. data/lib/api_resource/conditions/where_condition.rb +19 -0
  20. data/lib/api_resource/conditions.rb +18 -2
  21. data/lib/api_resource/connection.rb +27 -13
  22. data/lib/api_resource/exceptions.rb +11 -11
  23. data/lib/api_resource/finders/abstract_finder.rb +176 -95
  24. data/lib/api_resource/finders/multi_object_association_finder.rb +10 -9
  25. data/lib/api_resource/finders/resource_finder.rb +59 -49
  26. data/lib/api_resource/finders/single_finder.rb +5 -6
  27. data/lib/api_resource/finders/single_object_association_finder.rb +52 -51
  28. data/lib/api_resource/finders.rb +1 -1
  29. data/lib/api_resource/formats/file_upload_format.rb +75 -0
  30. data/lib/api_resource/formats.rb +4 -1
  31. data/lib/api_resource/response.rb +108 -0
  32. data/lib/api_resource/scopes.rb +62 -5
  33. data/lib/api_resource/serializer.rb +1 -1
  34. data/lib/api_resource/typecasters/boolean_typecaster.rb +1 -0
  35. data/lib/api_resource/typecasters/integer_typecaster.rb +1 -0
  36. data/lib/api_resource/typecasters/time_typecaster.rb +12 -4
  37. data/lib/api_resource/version.rb +1 -1
  38. data/lib/api_resource.rb +1 -0
  39. data/spec/lib/associations/has_one_remote_object_proxy_spec.rb +4 -4
  40. data/spec/lib/associations_spec.rb +3 -3
  41. data/spec/lib/attributes_spec.rb +16 -1
  42. data/spec/lib/base_spec.rb +121 -39
  43. data/spec/lib/conditions/{abstract_conditions_spec.rb → abstract_condition_spec.rb} +23 -11
  44. data/spec/lib/conditions/pagination_condition_spec.rb +88 -0
  45. data/spec/lib/finders/multi_object_association_finder_spec.rb +55 -27
  46. data/spec/lib/finders/resource_finder_spec.rb +26 -2
  47. data/spec/lib/finders/single_object_association_finder_spec.rb +14 -6
  48. data/spec/lib/finders_spec.rb +81 -81
  49. data/spec/lib/observing_spec.rb +3 -4
  50. data/spec/lib/response_spec.rb +18 -0
  51. data/spec/lib/scopes_spec.rb +25 -1
  52. data/spec/lib/typecasters/boolean_typecaster_spec.rb +1 -1
  53. data/spec/lib/typecasters/integer_typecaster_spec.rb +1 -1
  54. data/spec/lib/typecasters/time_typecaster_spec.rb +6 -0
  55. data/spec/support/files/bg-awesome.jpg +0 -0
  56. data/spec/support/mocks/test_resource_mocks.rb +26 -16
  57. data/spec/support/requests/test_resource_requests.rb +27 -23
  58. metadata +24 -4
@@ -0,0 +1,108 @@
1
+ module ApiResource
2
+ class Response
3
+
4
+ attr_accessor :body
5
+ attr_reader :headers
6
+
7
+ # explicit delegate for things we define
8
+ delegate(
9
+ :as_json,
10
+ :blank?,
11
+ :inspect,
12
+ :to_s,
13
+ to: :body
14
+ )
15
+
16
+ #
17
+ # Constructor
18
+ #
19
+ # @param response [HttpClient::Response]
20
+ # @param format [ApiResource::Format] Decoder
21
+ #
22
+ def initialize(response)
23
+ @body = self.parse_body(response)
24
+ @headers = response.try(:headers) || {}
25
+ end
26
+
27
+ #
28
+ # We typically treat the response as just a wrapper for an
29
+ # Array or a Hash and use is_a? to determine what kind of response
30
+ # we have. So to keep that consistent, #is_a? returns true if the
31
+ # body is a descendant of the class as well
32
+ #
33
+ # @param klass [Class]
34
+ #
35
+ # @return [Boolean]
36
+ def is_a?(klass)
37
+ super || @body.is_a?(klass)
38
+ end
39
+
40
+ #
41
+ # Implementation of marshal_dump
42
+ #
43
+ # @return [Array<Hash>] The data to dump
44
+ def marshal_dump
45
+ [@body, @headers]
46
+ end
47
+
48
+ #
49
+ # Implementation of marshal load
50
+ # @param args [Array] Array of dumped data
51
+ #
52
+ # @return [Response] New instance
53
+ def marshal_load(args)
54
+ @body, @headers = args
55
+ self
56
+ end
57
+
58
+
59
+ #
60
+ # Return ourself cloned with the body wrapped as an array
61
+ #
62
+ # @example
63
+ # resp = ApiResource::Response.new(response, format)
64
+ # resp.body # => {'a' => 'b'}
65
+ #
66
+ # array = Array.wrap(resp)
67
+ # array.body # => [{'a' => 'b'}]
68
+ #
69
+ # array.response == resp.response # true!
70
+ #
71
+ # @return [ApiResource::Response]
72
+ def to_ary
73
+ klone = self.dup
74
+ klone.body = Array.wrap(self.body)
75
+ klone
76
+ end
77
+
78
+ protected
79
+
80
+ #
81
+ # Proxy method missing to the body
82
+ #
83
+ # @param meth [Symbol] Method called
84
+ # @param *args [Array<Mixed>] Args passed
85
+ # @param &block [Proc] Block passed
86
+ #
87
+ # @return [Mixed]
88
+ def method_missing(meth, *args, &block)
89
+ @body.__send__(meth, *args, &block)
90
+ end
91
+
92
+ #
93
+ # Handle parsing of the body. Returns a blank Hash if
94
+ # no body is present
95
+ #
96
+ # @param response [HttpClient::Response]
97
+ #
98
+ # @return [Hash, Array<Hash>] Parsed response
99
+ def parse_body(response)
100
+ if response.try(:body).present?
101
+ return ApiResource.format.decode(response.body)
102
+ else
103
+ return {}
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -6,6 +6,7 @@ module ApiResource
6
6
  module ClassMethods
7
7
  # TODO: calling these methods should force loading of the resource definition
8
8
  def scopes
9
+ self.reload_resource_definition
9
10
  return self.related_objects[:scopes]
10
11
  end
11
12
 
@@ -68,7 +69,7 @@ module ApiResource
68
69
  end
69
70
  end
70
71
 
71
- #
72
+ #
72
73
  # Apply scopes from params based on our resource
73
74
  # definition
74
75
  #
@@ -90,20 +91,53 @@ module ApiResource
90
91
  return base
91
92
  end
92
93
 
94
+ #
95
+ # Add our dynamic scopes based on a set of params
96
+ #
97
+ # @param params [Hash] User-supplied params
98
+ # @param base [ApiResource::Conditions::AbstractCondition, Class] Base
99
+ # Scope
100
+ #
101
+ # @return [ApiResource::Conditions::AbstractCondition] [description]
93
102
  def add_dynamic_scopes(params, base)
94
103
  self.dynamic_scopes.each_pair do |name, args|
95
- next if params[name].blank?
104
+ # make sure we have all required arguments
105
+ next unless self.check_required_scope_args(args, params[name])
106
+
107
+ # the args we will apply
96
108
  caller_args = []
97
- args.each_pair do |subkey, type|
98
- if type == :req || params[name][subkey].present?
99
- caller_args << params[name][subkey]
109
+
110
+ # iterate through our args and add them to an array to send to our
111
+ # scope
112
+ args.keys.each do |subkey|
113
+ # we only apply things that are present or explicitly false
114
+ if val = self.get_scope_arg_value(subkey, params[name][subkey])
115
+ caller_args << val
100
116
  end
101
117
  end
118
+ # call our scope with the supplied args
102
119
  base = base.send(name, *caller_args)
103
120
  end
104
121
  return base
105
122
  end
106
123
 
124
+ #
125
+ # Check if we have supplied all of the necessary
126
+ # @param scope [Hash] [Scope Definition
127
+ # @param params [Hash] [Supplied params]
128
+ #
129
+ # @return [Boolean] Validity
130
+ def check_required_scope_args(scope, params)
131
+ # make sure we have a hash and it has values
132
+ return false unless params.is_a?(Hash) && params.present?
133
+ # find required values
134
+ required = scope.select{ |k,v| v.to_sym == :req }.keys
135
+ # make sure we have all of the required values, we allow false
136
+ required.all? { |key|
137
+ params[key].present? || params[key] == false
138
+ }
139
+ end
140
+
107
141
  #
108
142
  # Wrapper method to define all scopes from the resource definition
109
143
  #
@@ -117,10 +151,33 @@ module ApiResource
117
151
  true
118
152
  end
119
153
 
154
+ #
155
+ # Scopes that require arguments
156
+ #
157
+ # @return [Hash]
120
158
  def dynamic_scopes
121
159
  self.scopes.select { |name, args| args.present? }
122
160
  end
123
161
 
162
+ #
163
+ # Get the parsed/formatted arguments to send to the server
164
+ #
165
+ # @param key [String, Symbol] Key name for the scope value
166
+ # @param value [String, Integer, Symbol] Value for the scope
167
+ #
168
+ # @return [String, Integer, Symbol, Date] Parsed/formatted value
169
+ def get_scope_arg_value(key, value)
170
+ # cast to string to avoid incorred blank? behavior for us
171
+ return "false" if value == false
172
+ # if we havea date field, try to parse, falling back to the original
173
+ # value
174
+ if key.to_s =~ /date/
175
+ value = Date.parse(value) rescue value
176
+ end
177
+ # return the final value
178
+ value
179
+ end
180
+
124
181
  def static_scopes
125
182
  self.scopes.select { |name, args| args.blank? }.keys
126
183
  end
@@ -151,7 +151,7 @@ module ApiResource
151
151
  # or if the attribute has changed to nil
152
152
  return true if self.record.changes[key].present?
153
153
  # make sure our value isn't blank
154
- return val.present?
154
+ return !val.nil?
155
155
  end
156
156
 
157
157
  #
@@ -8,6 +8,7 @@ module ApiResource
8
8
  module BooleanTypecaster
9
9
 
10
10
  def self.from_api(value)
11
+ return nil if value.nil?
11
12
  TRUE_VALUES.include?(value)
12
13
  end
13
14
 
@@ -7,6 +7,7 @@ module ApiResource
7
7
  def self.from_api(value)
8
8
  return 0 if value == false
9
9
  return 1 if value == true
10
+ return nil if value.nil?
10
11
  return nil if value.is_a?(String) && value.blank?
11
12
  return value.to_i if value.respond_to?(:to_i)
12
13
  return value.to_s.to_i
@@ -15,13 +15,17 @@ module ApiResource
15
15
 
16
16
  if value =~ ApiResource::Typecast::ISO_DATETIME
17
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)
18
+ return self.new_time(false, $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, micro)
19
19
  end
20
20
 
21
21
  time_info = Date._parse(value)
22
22
  time_info[:micro] = ((time_info[:sec_fraction].to_f % 1) * 1_000_000).to_i
23
23
 
24
- new_time(*time_info.values_at(:year, :mon, :mday, :hour, :min, :sec, :micro))
24
+ if time_info[:zone].present?
25
+ new_time(true, *time_info.values_at(:year, :mon, :mday, :hour, :min, :sec, :zone))
26
+ else
27
+ new_time(false, *time_info.values_at(:year, :mon, :mday, :hour, :min, :sec, :micro))
28
+ end
25
29
 
26
30
  end
27
31
 
@@ -31,10 +35,14 @@ module ApiResource
31
35
 
32
36
  protected
33
37
 
34
- def self.new_time(*args)
38
+ def self.new_time(use_zone, *args)
35
39
  year = args.first
36
40
  return nil if year.nil? || year == 0
37
- Time.utc(*args) rescue nil
41
+ if use_zone
42
+ Time.new(*args).utc rescue nil
43
+ else
44
+ Time.utc(*args) rescue nil
45
+ end
38
46
  end
39
47
 
40
48
  end
@@ -1,3 +1,3 @@
1
1
  module ApiResource
2
- VERSION = "0.6.21"
2
+ VERSION = "0.6.22"
3
3
  end
data/lib/api_resource.rb CHANGED
@@ -33,6 +33,7 @@ module ApiResource
33
33
  autoload :Mocks
34
34
  autoload :ModelErrors
35
35
  autoload :Observing
36
+ autoload :Response
36
37
  autoload :Scopes
37
38
  autoload :Serializer
38
39
  autoload :Typecast
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module ApiResource
4
4
  module Associations
5
-
5
+
6
6
  describe HasOneRemoteObjectProxy do
7
7
 
8
8
  before(:all) do
@@ -10,12 +10,12 @@ module ApiResource
10
10
  end
11
11
 
12
12
  context "#load" do
13
-
13
+
14
14
  it "correctly loads data from an endpoint that returns
15
15
  a single record" do
16
-
16
+
17
17
  tr = TestResource.new(
18
- :has_one_object => {:service_uri => "/has_one_objects/1.json"}
18
+ :has_one_object => {:service_uri => "/has_one_objects/1.json"}
19
19
  )
20
20
  tr.has_one_object.internal_object.should be_instance_of(
21
21
  HasOneObject
@@ -604,10 +604,10 @@ describe "Associations" do
604
604
  end
605
605
 
606
606
  it "should be able to chain scopes" do
607
- scp = TestResource.active.paginate(20, 1)
607
+ scp = TestResource.active.boolean(20, 1)
608
608
  scp.should be_a Conditions::ScopeCondition
609
609
  scp.to_query.should eql(
610
- "active=true&paginate[current_page]=1&paginate[per_page]=20"
610
+ "active=true&boolean[a]=20&boolean[b]=1"
611
611
  )
612
612
  end
613
613
 
@@ -789,7 +789,7 @@ describe "Associations" do
789
789
  end
790
790
  end
791
791
  context "Belongs To" do
792
- before(:all) do
792
+ before(:all) do
793
793
  TestAR.class_eval do
794
794
  belongs_to_remote :test_resource
795
795
  end
@@ -70,7 +70,7 @@ describe "Attributes" do
70
70
 
71
71
  it "should be able to determine scopes when the class loads" do
72
72
  tst = TestResource.new
73
- tst.scope?(:paginate).should be_true
73
+ tst.scope?(:boolean).should be_true
74
74
  tst.scope?(:active).should be_true
75
75
  end
76
76
 
@@ -104,6 +104,21 @@ describe "Attributes" do
104
104
 
105
105
  tst.attr5.should eql("attr5")
106
106
  end
107
+
108
+ context '#password' do
109
+
110
+ it 'is able to define password even though it is a
111
+ class attribute' do
112
+
113
+ TestResource.define_attributes :password
114
+
115
+ resource = TestResource.new(password: '123456')
116
+ expect(resource.password).to eql('123456')
117
+
118
+ end
119
+
120
+ end
121
+
107
122
  end
108
123
 
109
124
  it "should define methods for testing for reading and writing known attributes" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require 'spec_helper'
2
2
  require 'json'
3
3
 
4
4
  include ApiResource
@@ -93,6 +93,8 @@ describe "Base" do
93
93
  self.prefix = "/path/to/nested/:id/"
94
94
  end
95
95
 
96
+ ChildResource = Class.new(PrefixResource)
97
+
96
98
  end
97
99
 
98
100
 
@@ -108,6 +110,43 @@ describe "Base" do
108
110
  )
109
111
  end
110
112
 
113
+ it "appends its type in the query string if it is not a direct
114
+ descendant of ApiResource::Base" do
115
+
116
+ expect(ChildResource.new_element_path).to eql(
117
+ "/path/to/project/prefix_resources/new.json?type=ChildResource"
118
+ )
119
+
120
+ end
121
+
122
+ end
123
+
124
+ context "#id" do
125
+
126
+ it 'should have a blank id on initialize' do
127
+ expect(TestResource.new.id).to be_nil
128
+ end
129
+
130
+ end
131
+
132
+ context '#new_record?' do
133
+
134
+ it 'is a new record on initialize' do
135
+ expect(TestResource.new).to be_new_record
136
+ end
137
+
138
+ end
139
+
140
+ context '#to_key' do
141
+
142
+ it 'is the primary key of the record' do
143
+ expect(TestResource.find(3).to_key).to eq([3])
144
+ end
145
+
146
+ it 'is nil if the record is not persisted' do
147
+ expect(TestResource.new.to_key).to be_nil
148
+ end
149
+
111
150
  end
112
151
 
113
152
  context "Prefixes" do
@@ -127,11 +166,9 @@ describe "Base" do
127
166
 
128
167
  TestResource.connection.expects(:post).with(
129
168
  "/belongs_to_objects/22/test_resources.json",
130
- {
131
- test_resource: {
132
- 'name' => 'Dan'
133
- }
134
- },
169
+ has_entries({
170
+ test_resource: is_a(Hash)
171
+ }),
135
172
  TestResource.headers
136
173
  )
137
174
 
@@ -172,6 +209,53 @@ describe "Base" do
172
209
 
173
210
  end
174
211
 
212
+ context "Saving with file upload" do
213
+
214
+ before(:all) do
215
+ TestResource.reload_resource_definition
216
+ end
217
+
218
+ after(:all) do
219
+ TestResource.reload_resource_definition
220
+ end
221
+
222
+ let(:uploaded_file){
223
+ ActionDispatch::Http::UploadedFile.new(
224
+ tempfile: File.new(
225
+ File.expand_path("../../support/files/bg-awesome.jpg", __FILE__)
226
+ )
227
+ )
228
+ }
229
+
230
+ context "#save" do
231
+
232
+ it 'sends the file to HTTPClient' do
233
+
234
+ TestResource.define_attributes :image_file
235
+
236
+ TestResource.connection.expects(:request)
237
+ .with(
238
+ :post,
239
+ instance_of(String),
240
+ has_entries(
241
+ test_resource: has_entries(
242
+ 'image_file' => instance_of(File)
243
+ )
244
+ ),
245
+ instance_of(Hash)
246
+ )
247
+
248
+ test_resource = TestResource.new(
249
+ image_file: uploaded_file
250
+ )
251
+ test_resource.save
252
+
253
+ end
254
+
255
+ end
256
+
257
+ end
258
+
175
259
 
176
260
  describe "Loading data from a hash" do
177
261
 
@@ -445,19 +529,23 @@ describe "Base" do
445
529
  context("Override create to return the json") do
446
530
 
447
531
 
448
- it "should be able to include associations when saving if they are specified" do
532
+ it "should be able to include associations when saving if
533
+ they are specified" do
449
534
  ApiResource::Connection.any_instance.expects(:post).with(
450
535
  "/test_resources.json",
451
- {
452
- test_resource: {
453
- 'name' => 'Ethan',
454
- 'age' => 20
455
- }
456
- },
536
+ has_entries({
537
+ test_resource: has_entries({
538
+ 'has_many_objects' => [{}]
539
+ })
540
+ }),
457
541
  TestResource.headers
458
542
  )
459
543
 
460
- tr = TestResource.build(name: "Ethan", age: 20)
544
+ tr = TestResource.build(
545
+ name: "Ethan",
546
+ age: 20,
547
+ has_many_objects: [HasManyObject.new]
548
+ )
461
549
  tr.save
462
550
  end
463
551
 
@@ -467,7 +555,8 @@ describe "Base" do
467
555
  "/test_resources.json",
468
556
  {
469
557
  test_resource: {
470
- 'name' => 'Ethan'
558
+ 'name' => 'Ethan',
559
+ 'roles' => []
471
560
  }
472
561
  },
473
562
  TestResource.headers
@@ -477,13 +566,15 @@ describe "Base" do
477
566
  tr.save
478
567
  end
479
568
 
480
- it "should include false attributes when creating by default" do
569
+ it "should include false and empty attributes when creating
570
+ by default" do
481
571
  ApiResource::Connection.any_instance.expects(:post).with(
482
572
  "/test_resources.json",
483
573
  {
484
574
  test_resource: {
485
575
  'name' => 'Ethan',
486
- 'is_active' => false
576
+ 'is_active' => false,
577
+ 'roles' => []
487
578
  }
488
579
  },
489
580
  TestResource.headers
@@ -500,6 +591,7 @@ describe "Base" do
500
591
  {
501
592
  test_resource: {
502
593
  'name' => 'Ethan',
594
+ 'roles' => [],
503
595
  'has_one_object' => {
504
596
  'size' => 'large'
505
597
  }
@@ -514,15 +606,15 @@ describe "Base" do
514
606
  end
515
607
 
516
608
 
517
- it "should include nil attributes if they are passed in through the include_extras" do
609
+ it "should include nil attributes if they are passed in through
610
+ the include_extras" do
518
611
  ApiResource::Connection.any_instance.expects(:post).with(
519
612
  "/test_resources.json",
520
- {
521
- test_resource: {
522
- 'name' => 'Ethan',
613
+ has_entries({
614
+ test_resource: has_entries({
523
615
  'age' => nil
524
- }
525
- },
616
+ })
617
+ }),
526
618
  TestResource.headers
527
619
  )
528
620
 
@@ -904,7 +996,7 @@ describe "Base" do
904
996
 
905
997
  begin
906
998
  initial = ApiResource::Base.ttl
907
- ApiResource::Base.ttl = 1
999
+ ApiResource::Base.ttl = 50
908
1000
  if defined?(Rails)
909
1001
  Object.send(:remove_const, :Rails)
910
1002
  end
@@ -914,23 +1006,13 @@ describe "Base" do
914
1006
  end
915
1007
 
916
1008
  end
917
-
918
- it "should implement caching using the ttl setting" do
919
- cache = mock(fetch: {id: 123, name: "Dan"})
920
- ApiResource.stubs(cache: cache)
921
- TestResource.find(123)
1009
+ # @todo This doesn't exactly test the cache, but stubbing is really
1010
+ # difficult when everything uses the cache
1011
+ it 'should work with the real cache' do
1012
+ tr = TestResource.find(1, expires_in: 200)
1013
+ expect(tr).to eql(TestResource.find(1, expires_in: 200))
922
1014
  end
923
1015
 
924
- it "should find with expires_in and cache" do
925
- ApiResource.cache.expects(:fetch)
926
- .with(anything, expires_in: 10.0)
927
- .returns({id: 2, name: "d"})
928
-
929
- res = TestResource.find("adfa", expires_in: 10)
930
-
931
- ApiResource::Base.ttl.should eql(1)
932
- res.id.to_i.should eql(2)
933
- end
934
1016
  end
935
1017
 
936
1018
  end
@@ -17,7 +17,7 @@ describe "Conditions" do
17
17
 
18
18
  obj3 = obj.paginate
19
19
 
20
- obj3.to_query.should eql("active=true&paginate=true")
20
+ obj3.to_query.should eql("active=true&page=1&per_page=10")
21
21
  obj3.should_not be_eager_load
22
22
  obj3.should_not be_blank_conditions
23
23
  # Make sure that it clones
@@ -61,25 +61,37 @@ 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(:load => [1]))
65
- obj.internal_object.should eql([1])
66
- obj.all.should eql([1])
64
+ resource_finder_mock = mock(load: [1], first: 1)
65
+
66
+ ApiResource::Finders::ResourceFinder.expects(:new)
67
+ .with(TestResource, obj)
68
+ .returns(resource_finder_mock)
69
+
70
+ obj.internal_object.should eql(resource_finder_mock)
71
+ obj.all.should eql(resource_finder_mock)
67
72
  obj.first.should eql(1)
68
73
  end
69
74
 
70
- it "should proxy calls to enumerable and array methods to the loaded object" do
75
+ it "should proxy calls to enumerable and array methods to the loaded
76
+ object" do
77
+
71
78
  obj = TestResource.includes(:has_many_objects)
72
79
 
73
- ApiResource::Finders::ResourceFinder.expects(:new).with(TestResource, obj).returns(mock(:load => [1,2]))
80
+ # this just needs to call each
81
+ resource_finder_mock = mock(load: true, each: true)
82
+
83
+ ApiResource::Finders::ResourceFinder.expects(:new)
84
+ .with(TestResource, obj)
85
+ .returns(resource_finder_mock)
74
86
 
75
- obj.collect{|o| o * 2}.should eql([2,4])
87
+ obj.collect{|o| o * 2}.should eql([])
76
88
  end
77
89
 
78
90
  it "should not typecast nil and false to true when creating condition hashes" do
79
- obj = TestResource.paginate(false, nil)
80
- hsh = obj.to_hash["paginate"]
81
- hsh["per_page"].should eql(false)
82
- hsh.should be_key(:current_page)
91
+ obj = TestResource.boolean(false, nil)
92
+ hsh = obj.to_hash["boolean"]
93
+ hsh["a"].should eql(false)
94
+ hsh.should be_key(:b)
83
95
  end
84
96
 
85
97
  end