active_remote 1.2.1

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. data/.gitignore +10 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +22 -0
  6. data/README.md +86 -0
  7. data/Rakefile +21 -0
  8. data/active_remote.gemspec +35 -0
  9. data/lib/active_remote.rb +15 -0
  10. data/lib/active_remote/association.rb +152 -0
  11. data/lib/active_remote/attributes.rb +29 -0
  12. data/lib/active_remote/base.rb +49 -0
  13. data/lib/active_remote/bulk.rb +143 -0
  14. data/lib/active_remote/dirty.rb +70 -0
  15. data/lib/active_remote/dsl.rb +141 -0
  16. data/lib/active_remote/errors.rb +24 -0
  17. data/lib/active_remote/persistence.rb +226 -0
  18. data/lib/active_remote/rpc.rb +71 -0
  19. data/lib/active_remote/search.rb +131 -0
  20. data/lib/active_remote/serialization.rb +40 -0
  21. data/lib/active_remote/serializers/json.rb +18 -0
  22. data/lib/active_remote/serializers/protobuf.rb +100 -0
  23. data/lib/active_remote/version.rb +3 -0
  24. data/lib/core_ext/date.rb +7 -0
  25. data/lib/core_ext/date_time.rb +7 -0
  26. data/lib/core_ext/integer.rb +19 -0
  27. data/lib/protobuf_extensions/base_field.rb +18 -0
  28. data/spec/core_ext/date_time_spec.rb +10 -0
  29. data/spec/lib/active_remote/association_spec.rb +80 -0
  30. data/spec/lib/active_remote/base_spec.rb +10 -0
  31. data/spec/lib/active_remote/bulk_spec.rb +74 -0
  32. data/spec/lib/active_remote/dsl_spec.rb +73 -0
  33. data/spec/lib/active_remote/persistence_spec.rb +266 -0
  34. data/spec/lib/active_remote/rpc_spec.rb +94 -0
  35. data/spec/lib/active_remote/search_spec.rb +98 -0
  36. data/spec/lib/active_remote/serialization_spec.rb +57 -0
  37. data/spec/lib/active_remote/serializers/json_spec.rb +32 -0
  38. data/spec/lib/active_remote/serializers/protobuf_spec.rb +95 -0
  39. data/spec/spec_helper.rb +17 -0
  40. data/spec/support/definitions/author.proto +29 -0
  41. data/spec/support/definitions/post.proto +33 -0
  42. data/spec/support/definitions/support/protobuf/category.proto +29 -0
  43. data/spec/support/definitions/support/protobuf/error.proto +6 -0
  44. data/spec/support/definitions/tag.proto +29 -0
  45. data/spec/support/helpers.rb +37 -0
  46. data/spec/support/models.rb +5 -0
  47. data/spec/support/models/author.rb +14 -0
  48. data/spec/support/models/category.rb +14 -0
  49. data/spec/support/models/message_with_options.rb +11 -0
  50. data/spec/support/models/post.rb +16 -0
  51. data/spec/support/models/tag.rb +12 -0
  52. data/spec/support/protobuf.rb +4 -0
  53. data/spec/support/protobuf/author.pb.rb +54 -0
  54. data/spec/support/protobuf/category.pb.rb +54 -0
  55. data/spec/support/protobuf/error.pb.rb +21 -0
  56. data/spec/support/protobuf/post.pb.rb +58 -0
  57. data/spec/support/protobuf/tag.pb.rb +54 -0
  58. metadata +284 -0
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::Base do
4
+ describe "#initialize" do
5
+ it "runs callbacks" do
6
+ described_class.any_instance.should_receive(:run_callbacks).with(:initialize)
7
+ described_class.new
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::Bulk do
4
+ let(:records) { double(:records, :to_hash => {}) }
5
+ let(:serialized_records) { double(:serialized_records) }
6
+
7
+ describe ".create_all" do
8
+ before {
9
+ Tag.stub(:parse_records).and_return(records)
10
+ Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
11
+ }
12
+
13
+ it "creates remote records" do
14
+ Tag.any_instance.should_receive(:execute).with(:create_all, records)
15
+ Tag.create_all(records)
16
+ end
17
+ end
18
+
19
+ describe ".delete_all" do
20
+ before {
21
+ Tag.stub(:parse_records).and_return(records)
22
+ Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
23
+ }
24
+
25
+ it "deletes remote records" do
26
+ Tag.any_instance.should_receive(:execute).with(:delete_all, records)
27
+ Tag.delete_all(records)
28
+ end
29
+ end
30
+
31
+ describe ".destroy_all" do
32
+ before {
33
+ Tag.stub(:parse_records).and_return(records)
34
+ Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
35
+ }
36
+
37
+ it "destroys remote records" do
38
+ Tag.any_instance.should_receive(:execute).with(:destroy_all, records)
39
+ Tag.destroy_all(records)
40
+ end
41
+ end
42
+
43
+ describe ".parse_records" do
44
+ let(:records) { [ Hash.new ] }
45
+
46
+ it "preps records to be built into a bulk request" do
47
+ parsed_records = { :records => records }
48
+ Tag.parse_records(records).should eq parsed_records
49
+ end
50
+
51
+ context "when given a bulk message" do
52
+ let(:records) { [ tag.to_hash ] }
53
+ let(:tag) { Generic::Remote::Tag.new }
54
+ let(:tags) { Generic::Remote::Tags.new(:records => [ tag ]) }
55
+
56
+ it "preps records to be built into a bulk request" do
57
+ parsed_records = { :records => records }
58
+ Tag.parse_records(tags).should eq parsed_records
59
+ end
60
+ end
61
+ end
62
+
63
+ describe ".update_all" do
64
+ before {
65
+ Tag.stub(:parse_records).and_return(records)
66
+ Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
67
+ }
68
+
69
+ it "updates remote records" do
70
+ Tag.any_instance.should_receive(:execute).with(:update_all, records)
71
+ Tag.update_all(records)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ # For testing the DSL methods
4
+ module Another
5
+ class TagService < Protobuf::Rpc::Service
6
+ end
7
+ end
8
+
9
+ describe ActiveRemote::DSL do
10
+ before { reset_dsl_variables(Tag) }
11
+ after { Tag.service_class Generic::Remote::TagService }
12
+
13
+ describe ".attr_publishable" do
14
+ after { reset_publishable_attributes(Tag) }
15
+
16
+ it "appends given attributes to @publishable_attributes" do
17
+ Tag.attr_publishable :guid
18
+ Tag.attr_publishable :name
19
+
20
+ Tag.publishable_attributes.should =~ [ :guid, :name ]
21
+ end
22
+ end
23
+
24
+ describe ".auto_paging_size" do
25
+ context "when given a value" do
26
+ it "sets @auto_paging_size to the value" do
27
+ Tag.auto_paging_size 100
28
+ Tag.auto_paging_size.should eq 100
29
+ end
30
+ end
31
+ end
32
+
33
+ describe ".namespace" do
34
+ context "when given a value" do
35
+ it "sets @namespace to the value" do
36
+ Tag.namespace :foo
37
+ Tag.namespace.should eq :foo
38
+ end
39
+ end
40
+ end
41
+
42
+ describe ".service_class" do
43
+ context "when nil" do
44
+ it "determines the service class" do
45
+ Tag.namespace :another
46
+
47
+ Tag.service_class.should eq Another::TagService
48
+ end
49
+ end
50
+
51
+ context "when given a value" do
52
+ it "sets @service_class to the value" do
53
+ Tag.service_class Generic::Remote::TagService
54
+ Tag.service_class.should eq Generic::Remote::TagService
55
+ end
56
+ end
57
+ end
58
+
59
+ describe ".service_name" do
60
+ context "when nil" do
61
+ it "determines the service name" do
62
+ Tag.service_name.should eq :tag_service
63
+ end
64
+ end
65
+
66
+ context "when given a value" do
67
+ it "sets @service_name to the value" do
68
+ Tag.service_name :foo
69
+ Tag.service_name.should eq :foo
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,266 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::Persistence do
4
+ subject { Tag.new }
5
+
6
+ before { Tag.any_instance.stub(:last_response).and_return(HashWithIndifferentAccess.new) }
7
+
8
+ describe ".create" do
9
+ before { Tag.any_instance.stub(:execute) }
10
+ after { Tag.any_instance.unstub(:execute) }
11
+
12
+ it "initializes and saves a new record" do
13
+ Tag.any_instance.should_receive(:save)
14
+ Tag.create(:name => 'foo')
15
+ end
16
+
17
+ it "returns a new record" do
18
+ value = Tag.create(:name => 'foo')
19
+ value.should be_a(Tag)
20
+ end
21
+ end
22
+
23
+ describe ".create!" do
24
+ before { Tag.any_instance.stub(:execute) }
25
+ after { Tag.any_instance.unstub(:execute) }
26
+
27
+ it "initializes and saves a new record" do
28
+ Tag.any_instance.should_receive(:save!)
29
+ Tag.create!(:name => 'foo')
30
+ end
31
+
32
+ context "when the record has errors" do
33
+ before { Tag.any_instance.stub(:save!).and_raise(ActiveRemote::ActiveRemoteError) }
34
+
35
+ it "raises an exception" do
36
+ expect { Tag.create!(:name => 'foo') }.to raise_error(ActiveRemote::ActiveRemoteError)
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#delete" do
42
+ before { subject.stub(:execute) }
43
+ after { subject.unstub(:execute) }
44
+
45
+ it "deletes a remote record" do
46
+ subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
47
+ subject.delete
48
+ end
49
+
50
+ context "when the record doesn't have errors" do
51
+ it "freezes the record" do
52
+ subject.delete
53
+ subject.frozen?.should be_true
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#delete!" do
59
+ before { subject.stub(:execute) }
60
+ after { subject.unstub(:execute) }
61
+
62
+ it "deletes a remote record" do
63
+ subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
64
+ subject.delete!
65
+ end
66
+
67
+ context "when an error occurs" do
68
+ before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
69
+
70
+ it "raises an exception" do
71
+ expect { subject.delete! }.to raise_error(ActiveRemote::ActiveRemoteError)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "#destroy" do
77
+ before { subject.stub(:execute) }
78
+ after { subject.unstub(:execute) }
79
+
80
+ it "destroys a remote record" do
81
+ subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
82
+ subject.destroy
83
+ end
84
+
85
+ context "when the record doesn't have errors" do
86
+ it "freezes the record" do
87
+ subject.destroy
88
+ subject.frozen?.should be_true
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#destroy!" do
94
+ before { subject.stub(:execute) }
95
+ after { subject.unstub(:execute) }
96
+
97
+ it "destroys a remote record" do
98
+ subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
99
+ subject.destroy!
100
+ end
101
+
102
+ context "when an error occurs" do
103
+ before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
104
+
105
+ it "raises an exception" do
106
+ expect { subject.destroy! }.to raise_error(ActiveRemote::ActiveRemoteError)
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "#has_errors?" do
112
+ context "when errors are not present" do
113
+ before { subject.errors.clear }
114
+
115
+ its(:has_errors?) { should be_false }
116
+ end
117
+
118
+ context "when errors are present" do
119
+ before { subject.errors[:base] << "Boom!" }
120
+
121
+ its(:has_errors?) { should be_true }
122
+ end
123
+ end
124
+
125
+ describe "#new_record?" do
126
+ context "when the record is persisted" do
127
+ subject { Tag.new(:guid => 'foo') }
128
+
129
+ its(:new_record?) { should be_false }
130
+ end
131
+
132
+ context "when the record is not persisted" do
133
+ subject { Tag.new }
134
+
135
+ its(:new_record?) { should be_true }
136
+ end
137
+ end
138
+
139
+ describe "#persisted?" do
140
+ context "when the record has a guid" do
141
+ subject { Tag.new(:guid => 'foo') }
142
+
143
+ its(:persisted?) { should be_true }
144
+ end
145
+
146
+ context "when the record does not have a guid" do
147
+ subject { Tag.new }
148
+
149
+ its(:persisted?) { should be_false }
150
+ end
151
+ end
152
+
153
+ describe "#save" do
154
+ before { subject.stub(:execute) }
155
+ after { subject.unstub(:execute) }
156
+
157
+ it "runs callbacks" do
158
+ subject.should_receive(:run_callbacks).with(:save)
159
+ subject.save
160
+ end
161
+
162
+ context "when the record is new" do
163
+ subject { Tag.new }
164
+
165
+ it "creates the record" do
166
+ expected_attributes = subject.attributes.reject { |key, value| key == "guid" }
167
+ subject.should_receive(:execute).with(:create, expected_attributes)
168
+ subject.save
169
+ end
170
+ end
171
+
172
+ context "when the record is not new" do
173
+ let(:attributes) { { 'guid' => 'foo' } }
174
+
175
+ subject { Tag.new(attributes) }
176
+
177
+ it "updates the record" do
178
+ subject.should_receive(:execute).with(:update, attributes)
179
+ subject.save
180
+ end
181
+ end
182
+
183
+ context "when the record is saved" do
184
+ before { subject.errors.clear }
185
+
186
+ it "returns true" do
187
+ subject.save.should be_true
188
+ end
189
+ end
190
+
191
+ context "when the record is not saved" do
192
+ before { subject.errors[:base] << "Boom!" }
193
+
194
+ it "returns false" do
195
+ subject.save.should be_false
196
+ end
197
+ end
198
+ end
199
+
200
+ describe "#save!" do
201
+ before { subject.stub(:execute) }
202
+ after { subject.unstub(:execute) }
203
+
204
+ context "when the record is saved" do
205
+ it "returns true" do
206
+ subject.stub(:save).and_return(true)
207
+ subject.save!.should be_true
208
+ end
209
+ end
210
+
211
+ context "when the record is not saved" do
212
+ it "raises an exception" do
213
+ subject.stub(:save).and_return(false)
214
+ expect { subject.save! }.to raise_error(ActiveRemote::RemoteRecordNotSaved)
215
+ end
216
+ end
217
+ end
218
+
219
+ describe "#success?" do
220
+ context "when errors are present" do
221
+ before { subject.errors[:base] << "Boom!" }
222
+
223
+ its(:success?) { should be_false }
224
+ end
225
+
226
+ context "when errors are not present" do
227
+ before { subject.errors.clear }
228
+
229
+ its(:success?) { should be_true }
230
+ end
231
+ end
232
+
233
+ describe "#update_attributes" do
234
+ let(:attributes) { HashWithIndifferentAccess.new(:name => 'bar') }
235
+
236
+ before { subject.stub(:save) }
237
+ after { subject.unstub(:save) }
238
+
239
+ it "assigns new attributes" do
240
+ subject.should_receive(:assign_attributes).with(attributes)
241
+ subject.update_attributes(attributes)
242
+ end
243
+
244
+ it "saves the record" do
245
+ subject.should_receive(:save)
246
+ subject.update_attributes(attributes)
247
+ end
248
+ end
249
+
250
+ describe "#update_attributes!" do
251
+ let(:attributes) { HashWithIndifferentAccess.new(:name => 'bar') }
252
+
253
+ before { subject.stub(:save!) }
254
+ after { subject.unstub(:save!) }
255
+
256
+ it "assigns new attributes" do
257
+ subject.should_receive(:assign_attributes).with(attributes)
258
+ subject.update_attributes!(attributes)
259
+ end
260
+
261
+ it "saves! the record" do
262
+ subject.should_receive(:save!)
263
+ subject.update_attributes!(attributes)
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::RPC do
4
+ subject { Tag.new }
5
+
6
+ describe ".remote_call" do
7
+ let(:args) { double(:args) }
8
+ let(:response) { double(:response) }
9
+
10
+ before { Tag.any_instance.stub(:execute) }
11
+
12
+ it "calls the given RPC method" do
13
+ Tag.any_instance.should_receive(:execute).with(:remote_method, args)
14
+ Tag.remote_call(:remote_method, args)
15
+ end
16
+
17
+ it "returns the response" do
18
+ Tag.any_instance.stub(:last_response).and_return(response)
19
+ Tag.remote_call(:remote_method, args).should eq response
20
+ end
21
+ end
22
+
23
+ describe ".request" do
24
+ let(:attributes) { Hash.new }
25
+ let(:message) { double(:message) }
26
+
27
+ it "builds an RPC request" do
28
+ Tag.should_receive(:build_message).with(Generic::Remote::Tag, attributes)
29
+ Tag.request(:create, attributes)
30
+ end
31
+ end
32
+
33
+ describe ".request_type" do
34
+ it "fetches the request type for the given RPC method" do
35
+ Tag.request_type(:search).should eq Generic::Remote::TagRequest
36
+ end
37
+ end
38
+
39
+ describe "#execute" do
40
+ let(:request) { double(:request) }
41
+
42
+ it "calls the given RPC method" do
43
+ mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
44
+ subject.execute(:create, request)
45
+ end
46
+
47
+ it "sets the last request" do
48
+ mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
49
+
50
+ subject.execute(:create, request)
51
+ subject.last_request.should eq(request)
52
+ end
53
+
54
+ context "when request args is a hash" do
55
+ let(:args){ Hash.new }
56
+ let(:request) { double(:request) }
57
+
58
+ before {
59
+ subject.stub(:request).and_return(request)
60
+ mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
61
+ }
62
+
63
+ it "creates a request" do
64
+ subject.should_receive(:request).with(:create, args)
65
+ subject.execute(:create, args)
66
+ end
67
+ end
68
+
69
+ context "when a request succeeds" do
70
+ let(:success_response) { double(:status => 'success', :awesome_town => true, :to_hash => {}) }
71
+
72
+ before {
73
+ mock_remote_service(Tag.service_class, :create, :response => success_response)
74
+ }
75
+
76
+ it "sets the last response" do
77
+ subject.execute(:create, request)
78
+ subject.last_response.should eq(success_response)
79
+ end
80
+ end
81
+
82
+ context "when a request fails" do
83
+ let(:error_response) { double(:error, :message => "Boom goes the dynamite!") }
84
+
85
+ before {
86
+ mock_remote_service(Tag.service_class, :create, :error => error_response)
87
+ }
88
+
89
+ it "raises an exception" do
90
+ expect { subject.execute(:create, request) }.to raise_error(ActiveRemote::ActiveRemoteError)
91
+ end
92
+ end
93
+ end
94
+ end