active_remote 5.0.0.pre → 5.0.0.rc1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20c9373eff2820fdfaeb4eefd815a1d4cfb752e9fd388e8fd0e2d4ef2c0c5f7f
4
- data.tar.gz: 5f66d51af2723950bad69d3870fc83685e253f5fcfd894d6ae19dd6a78c27516
3
+ metadata.gz: 24ecc4009b9bb7ab623c2f80961e2e15263a249ac412be97c39f86cde123fdaa
4
+ data.tar.gz: ac0215aad0dce875952b9e2583e8c3fe8ce114d33de15978a7393482e7fa65dc
5
5
  SHA512:
6
- metadata.gz: 07d671953169e1eefc9db8b26d2de3af40a39302e1423fdd7beeb212df913c46db1017aeb2dbc2d02c21cf72f0ae35639732d6af86694f0ecd7be894ae03db04
7
- data.tar.gz: 98ee4213dcd636baab1def67ba1848469ff8592aff9334b720348830e4fd797f65e2935450fe399fafdc84261a64f2a07197323d38b743c616d4b70475f7890f
6
+ metadata.gz: c8cd4c36b5dc8840206dc32bbe4ccc3e591f631691e156d1ebcf537877442bf5be00c70506f8d2e890f2340f34b805e6cde7e1f80103c07bd1fcc4799b1829d7
7
+ data.tar.gz: ff8a9f380a3eba79fcd0cb41e4856e02c20ede68044bab07fe80b3996f88962e49e95f6db59308e4cdd7ff51468ff0b280f36307c21fdd5bf5f0cdd8c4bc393e
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2
4
+ - 2.3
5
5
  - jruby
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- $LOAD_PATH.push File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.push File.expand_path("lib", __dir__)
4
4
  require "active_remote/version"
5
5
 
6
6
  Gem::Specification.new do |s|
@@ -28,6 +28,7 @@ module ActiveRemote
28
28
  def <=>(other)
29
29
  return nil unless other.instance_of? self.class
30
30
  return nil if name == other.name && options != other.options
31
+
31
32
  self.name.to_s <=> other.name.to_s
32
33
  end
33
34
 
@@ -57,6 +58,7 @@ module ActiveRemote
57
58
  # @since 0.2.0
58
59
  def initialize(name, type = :value, **options)
59
60
  raise TypeError, "can't convert #{name.class} into Symbol" unless name.respond_to? :to_sym
61
+
60
62
  @name = name.to_sym
61
63
  @type = ::ActiveModel::Type.lookup(type)
62
64
  @options = options
@@ -14,6 +14,7 @@ module ActiveRemote
14
14
  #
15
15
  def ==(other)
16
16
  return false unless other.instance_of?(self.class)
17
+
17
18
  attributes == other.attributes
18
19
  end
19
20
 
@@ -29,6 +29,14 @@ module ActiveRemote
29
29
  end
30
30
  end
31
31
 
32
+ # Override #remote to provide dirty tracking.
33
+ #
34
+ def remote(*)
35
+ super.tap do
36
+ clear_changes_information
37
+ end
38
+ end
39
+
32
40
  # Override #save to store changes as previous changes then clear them.
33
41
  #
34
42
  def save(*)
@@ -41,11 +41,11 @@ module ActiveRemote
41
41
 
42
42
  def endpoints(endpoints_hash = nil)
43
43
  @endpoints ||= {
44
- :create => :create,
45
- :delete => :delete,
44
+ :create => :create,
45
+ :delete => :delete,
46
46
  :destroy => :destroy,
47
- :search => :search,
48
- :update => :update
47
+ :search => :search,
48
+ :update => :update
49
49
  }
50
50
  @endpoints.merge!(endpoints_hash) if endpoints_hash.present?
51
51
  @endpoints
@@ -24,7 +24,7 @@ module ActiveRemote
24
24
  # user.to_param # => "GUID-1"
25
25
  #
26
26
  def to_param
27
- self[:guid] && self[:guid].to_s
27
+ self[:guid]&.to_s
28
28
  end
29
29
 
30
30
  ##
@@ -76,6 +76,7 @@ module ActiveRemote
76
76
  #
77
77
  def delete
78
78
  raise ReadOnlyRemoteRecord if readonly?
79
+
79
80
  response = remote_call(:delete, scope_key_hash)
80
81
 
81
82
  add_errors(response.errors) if response.respond_to?(:errors)
@@ -101,6 +102,7 @@ module ActiveRemote
101
102
  #
102
103
  def destroy
103
104
  raise ReadOnlyRemoteRecord if readonly?
105
+
104
106
  response = remote_call(:destroy, scope_key_hash)
105
107
 
106
108
  add_errors(response.errors) if response.respond_to?(:errors)
@@ -156,6 +158,19 @@ module ActiveRemote
156
158
  self.class.readonly? || @readonly
157
159
  end
158
160
 
161
+ # Executes a remote call on the current object and serializes it's attributes and
162
+ # errors from the response.
163
+ #
164
+ # Defaults request args to the scope key hash (e.g., { guid: 'ABC-123' }) when none are given.
165
+ # Returns false if the response contained errors; otherwise, returns true.
166
+ #
167
+ def remote(endpoint, request_args = scope_key_hash)
168
+ response = remote_call(endpoint, request_args)
169
+ assign_attributes_from_rpc(response)
170
+
171
+ success?
172
+ end
173
+
159
174
  # Saves the remote record.
160
175
  #
161
176
  # If it is a new record, it will be created through the service, otherwise
@@ -203,6 +218,7 @@ module ActiveRemote
203
218
  # attribute is marked as readonly.
204
219
  def update_attribute(name, value)
205
220
  raise ReadOnlyRemoteRecord if readonly?
221
+
206
222
  name = name.to_s
207
223
  send("#{name}=", value)
208
224
  save(:validate => false)
@@ -235,13 +251,7 @@ module ActiveRemote
235
251
  #
236
252
  def remote_create
237
253
  run_callbacks :create do
238
- # Use the getter here so we get the type casting.
239
- new_attributes = attributes
240
-
241
- response = remote_call(:create, new_attributes)
242
-
243
- instantiate(response.to_hash)
244
- add_errors(response.errors) if response.respond_to?(:errors)
254
+ remote(:create, attributes)
245
255
 
246
256
  @new_record = has_errors?
247
257
  success?
@@ -254,6 +264,7 @@ module ActiveRemote
254
264
  #
255
265
  def create_or_update(*args)
256
266
  raise ReadOnlyRemoteRecord if readonly?
267
+
257
268
  new_record? ? remote_create : remote_update(*args)
258
269
  end
259
270
 
@@ -268,12 +279,7 @@ module ActiveRemote
268
279
  updated_attributes.slice!(*attribute_names)
269
280
  updated_attributes.merge!(scope_key_hash)
270
281
 
271
- response = remote_call(:update, updated_attributes)
272
-
273
- instantiate(response.to_hash)
274
- add_errors(response.errors) if response.respond_to?(:errors)
275
-
276
- success?
282
+ remote(:update, updated_attributes)
277
283
  end
278
284
  end
279
285
  end
@@ -28,11 +28,7 @@ module ActiveRemote
28
28
  when true then true
29
29
  when false, nil then false
30
30
  else
31
- if value.respond_to?(:zero?)
32
- !value.zero?
33
- else
34
- value.present?
35
- end
31
+ value.present?
36
32
  end
37
33
  end
38
34
 
@@ -52,6 +52,12 @@ module ActiveRemote
52
52
  end
53
53
  end
54
54
 
55
+ def assign_attributes_from_rpc(response)
56
+ new_attributes = self.class.build_from_rpc(response.to_hash)
57
+ @attributes.update(new_attributes)
58
+ add_errors(response.errors) if response.respond_to?(:errors)
59
+ end
60
+
55
61
  def remote_call(rpc_method, request_args)
56
62
  self.class.remote_call(rpc_method, request_args)
57
63
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRemote
2
- VERSION = "5.0.0.pre"
2
+ VERSION = "5.0.0.rc1"
3
3
  end
@@ -54,6 +54,15 @@ describe ActiveRemote::Dirty do
54
54
  its(:changes) { should be_empty }
55
55
  end
56
56
 
57
+ describe "#remote" do
58
+ let(:post) { Post.new(:name => "foo") }
59
+
60
+ it "clears changes information" do
61
+ allow(post).to receive(:remote_call).and_return(::Generic::Remote::Post.new(:name => "foo"))
62
+ expect { post.remote(:reload) }.to change { post.changed? }.to(false)
63
+ end
64
+ end
65
+
57
66
  describe "#save" do
58
67
  let!(:changes) { subject.changes }
59
68
 
@@ -140,15 +140,6 @@ describe ::ActiveRemote::Persistence do
140
140
  end
141
141
  end
142
142
 
143
- describe "#readonly?" do
144
- context "when the record is created through instantiate with options[:readonly]" do
145
- subject { Tag.instantiate({ :guid => "foo" }, :readonly => true) }
146
-
147
- its(:new_record?) { should be_falsey }
148
- its(:readonly?) { should be_truthy }
149
- end
150
- end
151
-
152
143
  describe "#has_errors?" do
153
144
  context "when errors are not present" do
154
145
  before { subject.errors.clear }
@@ -197,6 +188,70 @@ describe ::ActiveRemote::Persistence do
197
188
  end
198
189
  end
199
190
 
191
+ describe "#readonly?" do
192
+ context "when the record is created through instantiate with options[:readonly]" do
193
+ subject { Tag.instantiate({ :guid => "foo" }, :readonly => true) }
194
+
195
+ its(:new_record?) { should be_falsey }
196
+ its(:readonly?) { should be_truthy }
197
+ end
198
+ end
199
+
200
+ describe "#remote" do
201
+ let(:response) { ::Generic::Remote::Tag.new(:guid => tag.guid, :name => "bar") }
202
+ let(:rpc) { ::ActiveRemote::RPCAdapters::ProtobufAdapter.new(::Tag.service_class, ::Tag.endpoints) }
203
+ let(:tag) { ::Tag.new(:guid => SecureRandom.uuid) }
204
+
205
+ subject { tag }
206
+
207
+ before do
208
+ allow(::Tag).to receive(:rpc).and_return(rpc)
209
+ allow(rpc).to receive(:execute).and_return(response)
210
+ end
211
+
212
+ it "calls the given RPC method with default args" do
213
+ expect(::Tag.rpc).to receive(:execute).with(:remote_method, tag.scope_key_hash)
214
+ tag.remote(:remote_method)
215
+ end
216
+
217
+ it "updates the attributes from the response" do
218
+ expect { tag.remote(:remote_method) }.to change { tag.name }.to(response.name)
219
+ end
220
+
221
+ it "returns true" do
222
+ expect(tag.remote(:remote_method)).to be(true)
223
+ end
224
+
225
+ context "when request args are given" do
226
+ it "calls the given RPC method with default args" do
227
+ attributes = { :guid => tag.guid, :name => "foo" }
228
+ expect(::Tag.rpc).to receive(:execute).with(:remote_method, attributes)
229
+ tag.remote(:remote_method, attributes)
230
+ end
231
+ end
232
+
233
+ context "when response does not respond to errors" do
234
+ it "returns true" do
235
+ allow(rpc).to receive(:execute).and_return(double(:response, :to_hash => ::Hash.new))
236
+ expect(tag.remote(:remote_method)).to be(true)
237
+ end
238
+ end
239
+
240
+ context "when errors are returned" do
241
+ let(:response) {
242
+ ::Generic::Remote::Tag.new(:guid => tag.guid, :name => "bar", :errors => [{ :field => "name", :message => "message" }])
243
+ }
244
+
245
+ it "adds errors from the response" do
246
+ expect { tag.remote(:remote_method) }.to change { tag.has_errors? }.to(true)
247
+ end
248
+
249
+ it "returns false" do
250
+ expect(tag.remote(:remote_method)).to be(false)
251
+ end
252
+ end
253
+ end
254
+
200
255
  describe "#save" do
201
256
  it "runs save callbacks" do
202
257
  allow(subject).to receive(:run_callbacks).with(:validation).and_return(true)
@@ -313,12 +368,12 @@ describe ::ActiveRemote::Persistence do
313
368
 
314
369
  it "runs update callbacks" do
315
370
  expect(tag).to receive(:after_update_callback)
316
- tag.update_attributes({})
371
+ tag.update({})
317
372
  end
318
373
 
319
374
  it "updates a remote record" do
320
375
  expect(rpc).to receive(:execute).with(:update, tag.scope_key_hash)
321
- tag.update_attributes({})
376
+ tag.update({})
322
377
  end
323
378
 
324
379
  before { allow(subject).to receive(:save) }
@@ -326,12 +381,12 @@ describe ::ActiveRemote::Persistence do
326
381
 
327
382
  it "assigns new attributes" do
328
383
  expect(subject).to receive(:assign_attributes).with(attributes)
329
- subject.update_attributes(attributes)
384
+ subject.update(attributes)
330
385
  end
331
386
 
332
387
  it "saves the record" do
333
388
  expect(subject).to receive(:save)
334
- subject.update_attributes(attributes)
389
+ subject.update(attributes)
335
390
  end
336
391
  end
337
392
 
@@ -343,12 +398,12 @@ describe ::ActiveRemote::Persistence do
343
398
 
344
399
  it "assigns new attributes" do
345
400
  expect(subject).to receive(:assign_attributes).with(attributes)
346
- subject.update_attributes!(attributes)
401
+ subject.update!(attributes)
347
402
  end
348
403
 
349
404
  it "saves! the record" do
350
405
  expect(subject).to receive(:save!)
351
- subject.update_attributes!(attributes)
406
+ subject.update!(attributes)
352
407
  end
353
408
  end
354
409
  end
@@ -38,9 +38,10 @@ describe ::ActiveRemote::QueryAttributes do
38
38
  expect(subject.name?).to eq true
39
39
  end
40
40
 
41
- it "is false when the attribute is 0" do
41
+ # This behavior varies from ActiveRecord, so we test it explicitly
42
+ it "is true when the attribute is 0" do
42
43
  subject.name = 0
43
- expect(subject.name?).to eq false
44
+ expect(subject.name?).to eq true
44
45
  end
45
46
 
46
47
  it "is true when the attribute is 1" do
@@ -50,4 +50,35 @@ describe ::ActiveRemote::RPC do
50
50
  expect(::Tag.remote_call(:remote_method, args)).to eq response
51
51
  end
52
52
  end
53
+
54
+ describe "#assign_attributes_from_rpc" do
55
+ let(:response) { ::Generic::Remote::Tag.new(:guid => tag.guid, :name => "bar") }
56
+ let(:tag) { ::Tag.new(:guid => SecureRandom.uuid) }
57
+
58
+ it "updates the attributes from the response" do
59
+ expect { tag.assign_attributes_from_rpc(response) }.to change { tag.name }.to(response.name)
60
+ end
61
+
62
+ context "when response does not respond to errors" do
63
+ let(:response) { double(:response, :to_hash => ::Hash.new) }
64
+
65
+ it "does not add errors from the response" do
66
+ expect { tag.assign_attributes_from_rpc(response) }.to_not change { tag.has_errors? }
67
+ end
68
+ end
69
+
70
+ context "when errors are returned" do
71
+ let(:response) {
72
+ ::Generic::Remote::Tag.new(
73
+ :guid => tag.guid,
74
+ :name => "bar",
75
+ :errors => [{ :field => "name", :message => "message" }]
76
+ )
77
+ }
78
+
79
+ it "adds errors from the response" do
80
+ expect { tag.assign_attributes_from_rpc(response) }.to change { tag.has_errors? }.to(true)
81
+ end
82
+ end
83
+ end
53
84
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.pre
4
+ version: 5.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hutchison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-10 00:00:00.000000000 Z
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel