api_resource 0.6.18 → 0.6.19

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.
@@ -15,7 +15,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
15
15
  before_create :bc_cb; after_create :ac_cb
16
16
  before_update :bu_cb; after_update :au_cb
17
17
  before_destroy :bd_cb; after_destroy :ad_cb
18
-
18
+
19
19
  def bs_cb
20
20
  @s_val = 1
21
21
  end
@@ -42,7 +42,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
42
42
  end
43
43
  EOE
44
44
  end
45
-
45
+
46
46
  it "should fire save and create callbacks when saving a new record" do
47
47
  tr = TestResource.new(:name => "Ethan", :age => 20)
48
48
  tr.save.should be_true
@@ -50,7 +50,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
50
50
  tr.c_val.should eql(2)
51
51
  tr.u_val.should be_nil
52
52
  end
53
-
53
+
54
54
  it "should fire save and update callbacks when updating a record" do
55
55
  tr = TestResource.new(:name => "Ethan", :age => 20)
56
56
  tr.stubs(:id => 1)
@@ -61,13 +61,13 @@ describe "Should put callbacks around save, create, update, and destroy by defau
61
61
  tr.c_val.should be_nil
62
62
  tr.u_val.should eql(2)
63
63
  end
64
-
64
+
65
65
  it "should only fire destroy callbacks when destroying a record" do
66
66
  tr = TestResource.new(:name => "Ethan", :age => 20)
67
67
  tr.stubs(:id => 1)
68
68
  tr.destroy.should be_true
69
69
  tr.d_val.should eql(2)
70
- tr.s_val.should be_nil
70
+ tr.s_val.should be_nil
71
71
  end
72
-
72
+
73
73
  end
@@ -3,21 +3,21 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  include ApiResource
4
4
 
5
5
  describe Connection do
6
-
6
+
7
7
  it "should be able to set the token directly on ApiResource" do
8
8
  ApiResource.token = "123"
9
9
  ApiResource::Base.token.should eql "123"
10
10
  end
11
-
11
+
12
12
  it "should be able to set a default token value, which is passed through each request" do
13
- ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {"Accept"=>"application/json", "Lifebooker-Token" => "abc"}).returns(ApiResource::Mocks::MockResponse.new({}))
13
+ ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {}, {"Accept"=>"application/json", "Lifebooker-Token" => "abc"}).returns(ApiResource::Mocks::MockResponse.new({}))
14
14
  ApiResource::Base.token = "abc"
15
15
  TestResource.find(1)
16
16
  end
17
17
 
18
18
  it "should set the Lifebooker-Token if one is present for GET requests" do
19
19
  token = Kernel.rand(100000).to_s
20
- ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {"Accept"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
20
+ ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {}, {"Accept"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
21
21
 
22
22
  ApiResource::Base.token = token
23
23
 
@@ -44,7 +44,7 @@ describe Connection do
44
44
 
45
45
  it "should set the Lifebooker-Token if one is present for POST requests" do
46
46
  token = Kernel.rand(100000).to_s
47
- ApiResource::Mocks::Connection.expects(:post).with("/test_resources/1.json", {}, {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
47
+ ApiResource::Mocks::Connection.expects(:post).with("/test_resources/1.json", '{}', {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
48
48
 
49
49
  ApiResource::Base.token = token
50
50
 
@@ -53,7 +53,7 @@ describe Connection do
53
53
 
54
54
  it "should set the Lifebooker-Token if one is present for PUT requests" do
55
55
  token = Kernel.rand(100000).to_s
56
- ApiResource::Mocks::Connection.expects(:put).with("/test_resources/1.json", {}, {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
56
+ ApiResource::Mocks::Connection.expects(:put).with("/test_resources/1.json", '{}', {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
57
57
 
58
58
  ApiResource::Base.token = token
59
59
 
@@ -75,7 +75,7 @@ describe Connection do
75
75
  TestResource.connection.headers.include?("Lifebooker-Token").should eql true
76
76
  TestResource.connection.headers["Lifebooker-Token"] = token
77
77
  end
78
-
78
+
79
79
  it "should be able to set a token for a given block" do
80
80
  ApiResource::Base.token = "123456"
81
81
  begin
@@ -88,14 +88,14 @@ describe Connection do
88
88
  end
89
89
  ApiResource::Base.token.should eql "123456"
90
90
  end
91
-
91
+
92
92
  it "should provider a method to regenerate its connection" do
93
93
  conn = ApiResource::Base.connection
94
94
  conn.should be ApiResource::Base.connection
95
95
  ApiResource.reset_connection
96
96
  conn.should_not be ApiResource::Base.connection
97
97
  end
98
-
98
+
99
99
  context "No Mocks" do
100
100
  before(:all) do
101
101
  ApiResource::Mocks.remove
@@ -111,25 +111,25 @@ describe Connection do
111
111
  ApiResource.open_timeout = 1
112
112
  ApiResource.open_timeout.should eql 1
113
113
 
114
- ApiResource::Base.connection.send(:http, "/test").options[:timeout].should eql 1
115
- ApiResource::Base.connection.send(:http, "/test").options[:open_timeout].should eql 1
116
-
114
+ ApiResource::Base.connection.send(:http).receive_timeout.should eql 1
115
+ ApiResource::Base.connection.send(:http).connect_timeout.should eql 1
116
+
117
117
  ApiResource.timeout = 100
118
- ApiResource::Base.connection.send(:http, "/test").options[:timeout].should eql 100
118
+ ApiResource::Base.connection.send(:http).receive_timeout.should eql 100
119
119
 
120
120
  end
121
-
122
- it "should time out if RestClient takes too long" do
123
-
121
+
122
+ it "should time out if HttpClient takes too long" do
123
+
124
124
  # hopefully google won't actually respond this fast :)
125
125
  ApiResource.timeout = 0.001
126
126
  ApiResource::Base.site = "http://www.google.com"
127
127
  lambda{
128
128
  ApiResource::Base.connection.get("/")
129
129
  }.should raise_error(ApiResource::RequestTimeout)
130
-
130
+
131
131
  end
132
-
132
+
133
133
  end
134
134
 
135
135
  context "headers" do
@@ -150,7 +150,7 @@ describe Connection do
150
150
  end
151
151
 
152
152
  end
153
-
154
153
 
155
-
154
+
155
+
156
156
  end
@@ -79,6 +79,20 @@ describe ApiResource::Finders do
79
79
  TestResource.includes(:has_many_objects).find(1)
80
80
  end
81
81
 
82
+ it "should be able to chain find on top of an includes call and a scope" do
83
+ TestResource.connection.expects(:get).with("/test_resources.json?birthday%5Bdate%5D=5&find%5Bids%5D=1").returns({"id" => 1, "has_many_object_ids" => [1,2]})
84
+ HasManyObject.connection.expects(:get).with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2").returns([])
85
+
86
+ TestResource.includes(:has_many_objects).birthday(5).find(1)
87
+ end
88
+
89
+ it "should disregard condition order" do
90
+ TestResource.connection.expects(:get).with("/test_resources.json?birthday%5Bdate%5D=5&find%5Bids%5D=1").returns({"id" => 1, "has_many_object_ids" => [1,2]})
91
+ HasManyObject.connection.expects(:get).with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2").returns([])
92
+
93
+ TestResource.birthday(5).includes(:has_many_objects).find(1)
94
+ end
95
+
82
96
  it "should be able to use a scope with arguments" do
83
97
  TestResource.connection.expects(:get)
84
98
  .with("/test_resources.json?active=true&birthday%5Bdate%5D=5").returns([{"id" => 10}])
@@ -4,7 +4,7 @@ require 'json'
4
4
  include ApiResource
5
5
 
6
6
  describe Mocks do
7
-
7
+
8
8
  # we set up the mocks in spec helper, so we can just assert this
9
9
  it "should hijack the connection" do
10
10
  ApiResource::Mocks::Interface.any_instance.expects(:get).once.returns(
@@ -12,29 +12,29 @@ describe Mocks do
12
12
  )
13
13
  TestResource.reload_class_attributes
14
14
  end
15
-
15
+
16
16
  it "should allow the user to raise errors for invalid responsed" do
17
- old_err_status = ApiResource.raise_missing_definition_error
17
+ old_err_status = ApiResource.raise_missing_definition_error
18
18
  ApiResource::Base.raise_missing_definition_error = true
19
-
19
+
20
20
  lambda {
21
21
  class MyNewInvalidResource < ApiResource::Base; end
22
- MyNewInvalidResource.new
22
+ MyNewInvalidResource.new
23
23
  }.should raise_error(ApiResource::ResourceNotFound)
24
-
24
+
25
25
  ApiResource.raise_missing_definition_error = old_err_status
26
26
  end
27
27
 
28
28
  it "should merge params for a request" do
29
29
  resp = ApiResource::Base.connection.get(
30
- "/mock_with_block/1?#{{:test => "abc"}.to_query}"
30
+ "/mock_with_block/1.json?#{{:test => "abc"}.to_query}"
31
31
  )
32
32
  resp["id"].should eql "1"
33
33
  resp["test"].should eql "abc"
34
34
  end
35
35
 
36
36
  context "Mock Request" do
37
- context "Initialize" do
37
+ context "Initialize" do
38
38
  it "should correctly assign blank params" do
39
39
  request = ApiResource::Mocks::MockRequest.new(:get, "/authenticate.json?token=")
40
40
  request.params.should eql({"token" => ""})
@@ -70,5 +70,5 @@ describe Mocks do
70
70
 
71
71
  end
72
72
  end
73
-
73
+
74
74
  end
@@ -36,8 +36,8 @@ describe "With Prefixes" do
36
36
  it "should use the prefix to create a new record" do
37
37
  prefix_model.send(:connection).expects(:post)
38
38
  .with(
39
- "/foreign/123/prefix_models.json",
40
- {"prefix_model" => {"name" => "test"}}.to_json,
39
+ "/foreign/123/prefix_models.json",
40
+ has_entry(:prefix_model, has_entry('name', 'test')),
41
41
  instance_of(Hash)
42
42
  )
43
43
  prefix_model.save
@@ -90,9 +90,8 @@ describe "With Prefixes" do
90
90
  prefix_model.name = "changed name"
91
91
  prefix_model.send(:connection).expects(:put)
92
92
  .with(
93
-
94
- "/foreign/123/prefix_models/456.json",
95
- {"prefix_model" => {"name" => "changed name"}}.to_json,
93
+ "/foreign/123/prefix_models/456.json",
94
+ has_entry(:prefix_model, has_entry('name', 'changed name')),
96
95
  instance_of(Hash)
97
96
  )
98
97
  prefix_model.save
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiResource::Scopes do
4
+
5
+ before(:all) do
6
+ ScopeResource.class_eval do
7
+ scope :no_arg, {}
8
+ scope :one_arg, {id: :req}
9
+ scope :one_array_arg, {ids: :req}
10
+ scope :two_args, {page: :req, per_page: :req}
11
+ scope :opt_args, {arg1: :opt}
12
+ scope :req_and_opt_args, {arg1: :req, arg2: :opt}
13
+ scope :var_args, {ids: :rest}
14
+ scope :mix_args, {id: :req, vararg: :rest}
15
+ end
16
+ end
17
+
18
+ context "Constructing arguments" do
19
+
20
+ it "should be able to query scopes on the current model" do
21
+ ScopeResource.no_arg.to_query.should eql(
22
+ "no_arg=true"
23
+ )
24
+ ScopeResource.one_arg(5).to_query.should eql(
25
+ "one_arg[id]=5"
26
+ )
27
+ ScopeResource.one_array_arg([3, 5]).to_query.should eql(
28
+ "one_array_arg[ids][]=3&one_array_arg[ids][]=5"
29
+ )
30
+ ScopeResource.two_args(1, 20).to_query.should eql(
31
+ "two_args[page]=1&two_args[per_page]=20"
32
+ )
33
+ $DEB = true
34
+ ScopeResource.opt_args.to_query.should eql(
35
+ "opt_args=true"
36
+ )
37
+ ScopeResource.opt_args(3).to_query.should eql(
38
+ "opt_args[arg1]=3"
39
+ )
40
+ ScopeResource.var_args(1, 2).to_query.should eql(
41
+ "var_args[ids][]=1&var_args[ids][]=2"
42
+ )
43
+ args = ["a", {opt1: 1}, {opt2: 2}]
44
+ ScopeResource.mix_args(*args).to_query.should eql(
45
+ "mix_args[id]=a&mix_args[vararg][][opt1]=1&mix_args[vararg][][opt2]=2"
46
+ )
47
+ end
48
+ end
49
+
50
+ context '#add_scopes' do
51
+
52
+ it 'applies static scopes' do
53
+ ScopeResource.expects(:no_arg).returns(ScopeResource)
54
+ ScopeResource.add_scopes(no_arg: 1)
55
+ end
56
+
57
+ it 'applies scopes with one argument' do
58
+ ScopeResource.expects(:one_arg).with(5).returns(ScopeResource)
59
+ ScopeResource.add_scopes(one_arg: {id: 5})
60
+ end
61
+
62
+ it 'applies scopes with an array argument' do
63
+ ScopeResource.expects(:one_array_arg).with([5]).returns(ScopeResource)
64
+ ScopeResource.add_scopes(one_array_arg: {ids: [5]})
65
+ end
66
+
67
+ it 'applies scopes with two arguments' do
68
+ ScopeResource.expects(:two_args).with(7,9).returns(ScopeResource)
69
+ ScopeResource.add_scopes(two_args: {page: 7, per_page: 9})
70
+ end
71
+
72
+ it 'applies scopes with optional arguments when those arguments are supplied' do
73
+ ScopeResource.expects(:opt_args).with(5).returns(ScopeResource)
74
+ ScopeResource.add_scopes(opt_args: {arg1: 5})
75
+ end
76
+
77
+ it "doesn't apply scopes with only optional arguments when there are no supplied args" do
78
+ ScopeResource.expects(:opt_args).never
79
+ ScopeResource.add_scopes(opt_args: {})
80
+ end
81
+
82
+ it "applies scopes that have both optional and required args with only the required args if the optional args are not passed in" do
83
+ ScopeResource.expects(:req_and_opt_args).with(5).returns(ScopeResource)
84
+ ScopeResource.add_scopes(req_and_opt_args: {arg1: 5})
85
+ end
86
+
87
+ it "applies scopes with variable arg lists" do
88
+ ScopeResource.expects(:var_args).with([5,6,7]).returns(ScopeResource)
89
+ ScopeResource.add_scopes(var_args: {ids: [5,6,7]})
90
+ end
91
+
92
+ it "applies scopes with mixed arg lists" do
93
+ ScopeResource.expects(:mix_args).with(4,[5,6,7]).returns(ScopeResource)
94
+ ScopeResource.add_scopes(mix_args: {id: 4, vararg: [5,6,7]})
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ module ApiResource
4
+
5
+ describe Serializer do
6
+
7
+ before(:each) do
8
+ TestResource.reload_resource_definition
9
+ TestResource.has_many :has_many_objects
10
+ TestResource.define_attributes :attr1, :attr2
11
+ TestResource.include_root_in_json = false
12
+ end
13
+
14
+ after(:all) do
15
+ TestResource.include_root_in_json = true
16
+ end
17
+
18
+ subject {
19
+ Serializer.new(instance)
20
+ }
21
+
22
+ let(:instance){
23
+ TestResource.new({
24
+ attr1: "attr1",
25
+ attr2: "attr2",
26
+ has_many_objects: []
27
+ })
28
+ }
29
+
30
+ context "#to_hash" do
31
+
32
+ it 'includes attributes' do
33
+
34
+ subject.to_hash["attr1"].should_not be_nil
35
+
36
+ end
37
+
38
+ it "should not include associations by default if
39
+ they have not changed" do
40
+
41
+ subject.to_hash["has_many_objects"].should be_nil
42
+ end
43
+
44
+ it "should include associations passed given in the include_associations array" do
45
+
46
+ subject = Serializer.new(
47
+ instance,
48
+ include_associations: [:has_many_objects]
49
+ )
50
+
51
+ subject.to_hash["has_many_objects"].should_not be_nil
52
+ end
53
+
54
+ it "should include associations by default if they have changed" do
55
+ instance.has_many_objects = [{name: "test"}]
56
+ hash = subject.to_hash
57
+ hash["has_many_objects"].should_not be_nil
58
+ end
59
+
60
+ it "should not include unknown attributes unless they
61
+ are passed in via the include_extras array" do
62
+
63
+ TestResource.class_eval do
64
+ define_attributes :attr3, access_level: :protected
65
+ end
66
+
67
+ instance = TestResource.instantiate_record({
68
+ attr1: "attr1",
69
+ attr2: "attr2",
70
+ attr3: "attr3"
71
+ })
72
+
73
+ subject = Serializer.new(instance)
74
+ subject.to_hash["attr3"].should be_nil
75
+
76
+ subject = Serializer.new(instance, include_extras: [:attr3])
77
+ subject.to_hash["attr3"].should_not be_nil
78
+ end
79
+
80
+ it "should ignore fields set under the except option" do
81
+ tst = TestResource.new({
82
+ attr1: "attr1",
83
+ attr2: "attr2"
84
+ })
85
+ hash = JSON.parse(tst.to_json(except: [:attr1]))
86
+ hash["attr1"].should be_nil
87
+ hash["attr2"].should be_present
88
+ end
89
+
90
+ context "Nested Objects" do
91
+
92
+ before(:all) do
93
+ TestResource.has_many(:has_many_objects)
94
+ end
95
+
96
+ after(:all) do
97
+ TestResource.reload_resource_definition
98
+ end
99
+
100
+ it "should include the id of nested objects in the serialization" do
101
+ instance.has_many_objects = [
102
+ {name: "123", id: "1"}
103
+ ]
104
+ subject = Serializer.new(
105
+ instance,
106
+ include_associations: [:has_many_objects]
107
+ )
108
+ subject.to_hash["has_many_objects"].first["id"].should_not be_nil
109
+ end
110
+
111
+ it "should exclude include the id of new nested objects in the
112
+ serialization" do
113
+ instance.has_many_objects = [
114
+ {name: "123"}
115
+ ]
116
+ subject = Serializer.new(
117
+ instance,
118
+ include_associations: [:has_many_objects]
119
+ )
120
+ object_hash = subject.to_hash["has_many_objects"].first
121
+ object_hash.keys.should_not include "id"
122
+ end
123
+
124
+ end
125
+
126
+ context 'Foreign keys' do
127
+
128
+ context 'Prefixed' do
129
+
130
+ before(:all) do
131
+ TestResource.prefix =
132
+ "/belongs_to_objects/:belongs_to_object_id/"
133
+ end
134
+
135
+ after(:all) do
136
+ TestResource.prefix = "/"
137
+ end
138
+
139
+ it 'excludes the foreign key when it is nested in the prefix' do
140
+ instance.belongs_to_object_id = 123
141
+ subject.to_hash["belongs_to_object_id"].should be_blank
142
+ end
143
+
144
+ end
145
+
146
+ it "should include the foreign_key_id when saving" do
147
+ instance.stubs(:id => 123)
148
+ instance.has_many_object_ids = [4]
149
+ subject.to_hash[:has_many_object_ids].should eql([4])
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+ end
156
+ end