active_remote 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f3b021e02d82dd94367950f76e8601d35dd47c28
4
- data.tar.gz: 23885a9b4e9a3166c7096fc983b6ede7c692f874
3
+ metadata.gz: ad233ac94027246310c94addc5e595b1cb6d25fb
4
+ data.tar.gz: 0a1985fd4e52f98fb757fccdb04ccd097ee4abd4
5
5
  SHA512:
6
- metadata.gz: 755211aa1e0e8db43d1eaf5c590f625edac7b56b73d2a91267b6473453774d2ddac17822c17f8456f90d3df549704f8995e5955bc63f135add6ade14bab1a49e
7
- data.tar.gz: f0c44e8adb7043d79b172b9745b0d089a1824ed0ff4a8f3d94d24fde9e3740208db5805e5817158ed81c7f3a3133908cd97359bc44460ecaf28ad652f8987a32
6
+ metadata.gz: 7dabce988979749626a43fa3ddcfbaa2df930f8c70e57c172e6a89c7390d9ab11e47def151c2b7773cf486572b719affcb41e329e0aca7e40a00a16389c6172c
7
+ data.tar.gz: 9c57148a75afc5dd51f5ec5a6d31e96c446888153099c38cc970a2d04a57431a194022fcd88a21d057c319e11f5d20d6e6563b4b5f87cf8b4fef2af1a72202ca
@@ -29,8 +29,9 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency "better_receive"
30
30
  s.add_development_dependency "rake"
31
31
  s.add_development_dependency "rspec"
32
+ s.add_development_dependency "rspec-its"
32
33
  s.add_development_dependency "rspec-pride"
33
- s.add_development_dependency "pry-nav"
34
+ s.add_development_dependency "pry"
34
35
  s.add_development_dependency "protobuf-rspec", ">= 1.0"
35
36
  s.add_development_dependency "simplecov"
36
37
  end
@@ -15,6 +15,7 @@ require 'active_remote/rpc'
15
15
  require 'active_remote/scope_keys'
16
16
  require 'active_remote/search'
17
17
  require 'active_remote/serialization'
18
+ require 'active_remote/validations'
18
19
 
19
20
  module ActiveRemote
20
21
  class Base
@@ -39,6 +40,10 @@ module ActiveRemote
39
40
  # so it needs to be included last.
40
41
  include Dirty
41
42
 
43
+ # Overrides persistence methods, so it must included after
44
+ include Validations
45
+ include ActiveModel::Validations::Callbacks
46
+
42
47
  attr_reader :last_request, :last_response
43
48
 
44
49
  define_model_callbacks :initialize, :only => :after
@@ -9,6 +9,17 @@ module ActiveRemote
9
9
  class ReadOnlyRemoteRecord < ActiveRemoteError
10
10
  end
11
11
 
12
+ # Raised by ActiveRemote::Validations when save is called on an invalid record.
13
+ class RemoteRecordInvalid < ActiveRemoteError
14
+ attr_reader :record
15
+
16
+ def initialize(record)
17
+ @record = record
18
+ errors = @record.errors.full_messages.join(', ')
19
+ super(errors)
20
+ end
21
+ end
22
+
12
23
  # Raised by ActiveRemove::Base.find when remote record is not found when
13
24
  # searching with the given arguments.
14
25
  class RemoteRecordNotFound < ActiveRemoteError
@@ -176,9 +176,9 @@ module ActiveRemote
176
176
  #
177
177
  # Also runs any before/after save callbacks that are defined.
178
178
  #
179
- def save
179
+ def save(*args)
180
180
  run_callbacks :save do
181
- create_or_update
181
+ create_or_update(*args)
182
182
  end
183
183
  end
184
184
 
@@ -192,8 +192,8 @@ module ActiveRemote
192
192
  #
193
193
  # Also runs any before/after save callbacks that are defined.
194
194
  #
195
- def save!
196
- save || raise(RemoteRecordNotSaved)
195
+ def save!(*args)
196
+ save(*args) || raise(RemoteRecordNotSaved)
197
197
  end
198
198
 
199
199
  # Returns true if the record doesn't have errors; otherwise, returns false.
@@ -245,9 +245,9 @@ module ActiveRemote
245
245
  # are created, existing records are updated. If the record is marked as
246
246
  # readonly, an ActiveRemote::ReadOnlyRemoteRecord is raised.
247
247
  #
248
- def create_or_update
248
+ def create_or_update(*args)
249
249
  raise ReadOnlyRemoteRecord if readonly?
250
- new_record? ? create : update
250
+ new_record? ? create : update(*args)
251
251
  end
252
252
 
253
253
  # Handles updating a remote object and serializing it's attributes and
@@ -0,0 +1,64 @@
1
+ module ActiveRemote
2
+ module Validations
3
+ extend ActiveSupport::Concern
4
+
5
+ # Attempts to save the record like Persistence, but will run
6
+ # validations and return false if the record is invalid
7
+ #
8
+ # Validations can be skipped by passing :validate => false
9
+ #
10
+ # example Save a record
11
+ # post.save
12
+ #
13
+ # example Save a record, skip validations
14
+ # post.save(:validate => false)
15
+ #
16
+ def save(options = {})
17
+ perform_validations(options) ? super : false
18
+ end
19
+
20
+ # Attempts to save the record like Persistence, but will raise
21
+ # ActiveRemote::RemoteRecordInvalid if the record is not valid
22
+ #
23
+ # Validations can be skipped by passing :validate => false
24
+ #
25
+ # example Save a record, raise and error if invalid
26
+ # post.save!
27
+ #
28
+ # example Save a record, skip validations
29
+ # post.save!(:validate => false)
30
+ #
31
+ def save!(options = {})
32
+ perform_validations(options) ? super : raise_validation_error
33
+ end
34
+
35
+ # Runs all the validations within the specified context. Returns true if
36
+ # no errors are found, false otherwise.
37
+ #
38
+ # Aliased as validate.
39
+ #
40
+ # example Is the record valid?
41
+ # post.valid?
42
+ #
43
+ # example Is the record valid for creation?
44
+ # post.valid?(:create)
45
+ #
46
+ def valid?(context = nil)
47
+ context ||= (new_record? ? :create : :update)
48
+ output = super(context)
49
+ errors.empty? && output
50
+ end
51
+
52
+ alias_method :validate, :valid?
53
+
54
+ protected
55
+
56
+ def raise_validation_error
57
+ fail(::ActiveRemote::RemoteRecordInvalid.new(self))
58
+ end
59
+
60
+ def perform_validations(options = {})
61
+ options[:validate] == false || valid?(options[:context])
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveRemote
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2.0"
3
3
  end
@@ -11,43 +11,43 @@ describe ActiveRemote::Association do
11
11
  let(:default_category_guid) { "CAT-123" }
12
12
  subject { Post.new(:author_guid => author_guid, :user_guid => user_guid) }
13
13
 
14
- it { should respond_to(:author) }
14
+ it { is_expected.to respond_to(:author) }
15
15
 
16
16
  it "searches the associated model for a single record" do
17
- Author.should_receive(:search).with(:guid => subject.author_guid).and_return(records)
18
- subject.author.should eq record
17
+ expect(Author).to receive(:search).with(:guid => subject.author_guid).and_return(records)
18
+ expect(subject.author).to eq record
19
19
  end
20
20
 
21
21
  it "memoizes the result record" do
22
- Author.should_receive(:search).once.with(:guid => subject.author_guid).and_return(records)
23
- 3.times { subject.author.should eq record }
22
+ expect(Author).to receive(:search).once.with(:guid => subject.author_guid).and_return(records)
23
+ 3.times { expect(subject.author).to eq record }
24
24
  end
25
25
 
26
26
  context "when guid is nil" do
27
27
  subject { Post.new }
28
28
 
29
29
  it "returns nil" do
30
- subject.author.should be_nil
30
+ expect(subject.author).to be_nil
31
31
  end
32
32
  end
33
33
 
34
34
  context "when the search is empty" do
35
35
  it "returns a nil" do
36
- Author.should_receive(:search).with(:guid => subject.author_guid).and_return([])
37
- subject.author.should be_nil
36
+ expect(Author).to receive(:search).with(:guid => subject.author_guid).and_return([])
37
+ expect(subject.author).to be_nil
38
38
  end
39
39
  end
40
40
 
41
41
  context 'scoped field' do
42
- it { should respond_to(:user) }
42
+ it { is_expected.to respond_to(:user) }
43
43
 
44
44
  it "searches the associated model for multiple records" do
45
- Author.should_receive(:search).with(:guid => subject.author_guid, :user_guid => subject.user_guid).and_return(records)
46
- subject.user.should eq(record)
45
+ expect(Author).to receive(:search).with(:guid => subject.author_guid, :user_guid => subject.user_guid).and_return(records)
46
+ expect(subject.user).to eq(record)
47
47
  end
48
48
 
49
49
  context 'when user_guid doesnt exist on model 'do
50
- before { subject.stub(:respond_to?).with("user_guid").and_return(false) }
50
+ before { allow(subject).to receive(:respond_to?).with("user_guid").and_return(false) }
51
51
 
52
52
  it 'raises an error' do
53
53
  expect {subject.user}.to raise_error
@@ -69,11 +69,11 @@ describe ActiveRemote::Association do
69
69
  let(:author_guid) { "AUT-456" }
70
70
 
71
71
  subject { Post.new(:author_guid => author_guid) }
72
- it { should respond_to(:coauthor) }
72
+ it { is_expected.to respond_to(:coauthor) }
73
73
 
74
74
  it "searches the associated model for a single record" do
75
- Author.should_receive(:search).with(:guid => subject.author_guid).and_return(records)
76
- subject.coauthor.should eq record
75
+ expect(Author).to receive(:search).with(:guid => subject.author_guid).and_return(records)
76
+ expect(subject.coauthor).to eq record
77
77
  end
78
78
  end
79
79
 
@@ -81,11 +81,11 @@ describe ActiveRemote::Association do
81
81
  let(:author_guid) { "AUT-456" }
82
82
 
83
83
  subject { Post.new(:bestseller_guid => author_guid) }
84
- it { should respond_to(:bestseller) }
84
+ it { is_expected.to respond_to(:bestseller) }
85
85
 
86
86
  it "searches the associated model for a single record" do
87
- Author.should_receive(:search).with(:guid => subject.bestseller_guid).and_return(records)
88
- subject.bestseller.should eq record
87
+ expect(Author).to receive(:search).with(:guid => subject.bestseller_guid).and_return(records)
88
+ expect(subject.bestseller).to eq record
89
89
  end
90
90
  end
91
91
  end
@@ -97,61 +97,61 @@ describe ActiveRemote::Association do
97
97
 
98
98
  subject { Author.new(:guid => guid, :user_guid => user_guid) }
99
99
 
100
- it { should respond_to(:posts) }
100
+ it { is_expected.to respond_to(:posts) }
101
101
 
102
102
  it "searches the associated model for all associated records" do
103
- Post.should_receive(:search).with(:author_guid => subject.guid).and_return(records)
104
- subject.posts.should eq records
103
+ expect(Post).to receive(:search).with(:author_guid => subject.guid).and_return(records)
104
+ expect(subject.posts).to eq records
105
105
  end
106
106
 
107
107
  it "memoizes the result record" do
108
- Post.should_receive(:search).once.with(:author_guid => subject.guid).and_return(records)
109
- 3.times { subject.posts.should eq records }
108
+ expect(Post).to receive(:search).once.with(:author_guid => subject.guid).and_return(records)
109
+ 3.times { expect(subject.posts).to eq records }
110
110
  end
111
111
 
112
112
  context "when guid is nil" do
113
113
  subject { Author.new }
114
114
 
115
115
  it "returns []" do
116
- subject.posts.should eq []
116
+ expect(subject.posts).to eq []
117
117
  end
118
118
  end
119
119
 
120
120
  context "when the search is empty" do
121
121
  it "returns the empty set" do
122
- Post.should_receive(:search).with(:author_guid => subject.guid).and_return([])
123
- subject.posts.should be_empty
122
+ expect(Post).to receive(:search).with(:author_guid => subject.guid).and_return([])
123
+ expect(subject.posts).to be_empty
124
124
  end
125
125
  end
126
126
 
127
127
  context "specific association with class name" do
128
- it { should respond_to(:flagged_posts) }
128
+ it { is_expected.to respond_to(:flagged_posts) }
129
129
 
130
130
  it "searches the associated model for a single record" do
131
- Post.should_receive(:search).with(:author_guid => subject.guid).and_return([])
132
- subject.flagged_posts.should be_empty
131
+ expect(Post).to receive(:search).with(:author_guid => subject.guid).and_return([])
132
+ expect(subject.flagged_posts).to be_empty
133
133
  end
134
134
  end
135
135
 
136
136
  context "specific association with class name and foreign_key" do
137
- it { should respond_to(:bestseller_posts) }
137
+ it { is_expected.to respond_to(:bestseller_posts) }
138
138
 
139
139
  it "searches the associated model for multiple record" do
140
- Post.should_receive(:search).with(:bestseller_guid => subject.guid).and_return(records)
141
- subject.bestseller_posts.should eq(records)
140
+ expect(Post).to receive(:search).with(:bestseller_guid => subject.guid).and_return(records)
141
+ expect(subject.bestseller_posts).to eq(records)
142
142
  end
143
143
  end
144
144
 
145
145
  context 'scoped field' do
146
- it { should respond_to(:user_posts) }
146
+ it { is_expected.to respond_to(:user_posts) }
147
147
 
148
148
  it "searches the associated model for multiple records" do
149
- Post.should_receive(:search).with(:author_guid => subject.guid, :user_guid => subject.user_guid).and_return(records)
150
- subject.user_posts.should eq(records)
149
+ expect(Post).to receive(:search).with(:author_guid => subject.guid, :user_guid => subject.user_guid).and_return(records)
150
+ expect(subject.user_posts).to eq(records)
151
151
  end
152
152
 
153
153
  context 'when user_guid doesnt exist on model 'do
154
- before { subject.stub(:respond_to?).with("user_guid").and_return(false) }
154
+ before { allow(subject).to receive(:respond_to?).with("user_guid").and_return(false) }
155
155
 
156
156
  it 'raises an error' do
157
157
  expect {subject.user_posts}.to raise_error
@@ -180,61 +180,61 @@ describe ActiveRemote::Association do
180
180
 
181
181
  subject { Category.new(category_attributes) }
182
182
 
183
- it { should respond_to(:author) }
183
+ it { is_expected.to respond_to(:author) }
184
184
 
185
185
  it "searches the associated model for all associated records" do
186
- Author.should_receive(:search).with(:category_guid => subject.guid).and_return(records)
187
- subject.author.should eq record
186
+ expect(Author).to receive(:search).with(:category_guid => subject.guid).and_return(records)
187
+ expect(subject.author).to eq record
188
188
  end
189
189
 
190
190
  it "memoizes the result record" do
191
- Author.should_receive(:search).once.with(:category_guid => subject.guid).and_return(records)
192
- 3.times { subject.author.should eq record }
191
+ expect(Author).to receive(:search).once.with(:category_guid => subject.guid).and_return(records)
192
+ 3.times { expect(subject.author).to eq record }
193
193
  end
194
194
 
195
195
  context "when guid is nil" do
196
196
  subject { Category.new }
197
197
 
198
198
  it "returns nil" do
199
- subject.author.should be_nil
199
+ expect(subject.author).to be_nil
200
200
  end
201
201
  end
202
202
 
203
203
  context "when the search is empty" do
204
204
  it "returns a nil value" do
205
- Author.should_receive(:search).with(:category_guid => subject.guid).and_return([])
206
- subject.author.should be_nil
205
+ expect(Author).to receive(:search).with(:category_guid => subject.guid).and_return([])
206
+ expect(subject.author).to be_nil
207
207
  end
208
208
  end
209
209
 
210
210
  context "specific association with class name" do
211
- it { should respond_to(:senior_author) }
211
+ it { is_expected.to respond_to(:senior_author) }
212
212
 
213
213
  it "searches the associated model for a single record" do
214
- Author.should_receive(:search).with(:category_guid => subject.guid).and_return(records)
215
- subject.senior_author.should eq record
214
+ expect(Author).to receive(:search).with(:category_guid => subject.guid).and_return(records)
215
+ expect(subject.senior_author).to eq record
216
216
  end
217
217
  end
218
218
 
219
219
  context "specific association with class name and foreign_key" do
220
- it { should respond_to(:primary_editor) }
220
+ it { is_expected.to respond_to(:primary_editor) }
221
221
 
222
222
  it "searches the associated model for a single record" do
223
- Author.should_receive(:search).with(:editor_guid => subject.guid).and_return(records)
224
- subject.primary_editor.should eq record
223
+ expect(Author).to receive(:search).with(:editor_guid => subject.guid).and_return(records)
224
+ expect(subject.primary_editor).to eq record
225
225
  end
226
226
  end
227
227
 
228
228
  context 'scoped field' do
229
- it { should respond_to(:chief_editor) }
229
+ it { is_expected.to respond_to(:chief_editor) }
230
230
 
231
231
  it "searches the associated model for multiple records" do
232
- Author.should_receive(:search).with(:chief_editor_guid => subject.guid, :user_guid => subject.user_guid).and_return(records)
233
- subject.chief_editor.should eq(record)
232
+ expect(Author).to receive(:search).with(:chief_editor_guid => subject.guid, :user_guid => subject.user_guid).and_return(records)
233
+ expect(subject.chief_editor).to eq(record)
234
234
  end
235
235
 
236
236
  context 'when user_guid doesnt exist on model 'do
237
- before { subject.stub(:respond_to?).with("user_guid").and_return(false) }
237
+ before { allow(subject).to receive(:respond_to?).with("user_guid").and_return(false) }
238
238
 
239
239
  it 'raises an error' do
240
240
  expect {subject.chief_editor}.to raise_error
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe ActiveRemote::Base do
4
4
  describe "#initialize" do
5
5
  it "runs callbacks" do
6
- described_class.any_instance.should_receive(:run_callbacks).with(:initialize)
6
+ expect_any_instance_of(described_class).to receive(:run_callbacks).with(:initialize)
7
7
  described_class.new
8
8
  end
9
9
  end
@@ -12,13 +12,13 @@ describe ActiveRemote::Dirty do
12
12
  context "when the value changes" do
13
13
  before { subject.name = 'bar' }
14
14
 
15
- its(:name_changed?) { should be_true }
15
+ its(:name_changed?) { should be_truthy }
16
16
  end
17
17
 
18
18
  context "when the value doesn't change" do
19
19
  before { subject.name = 'foo' }
20
20
 
21
- its(:name_changed?) { should be_false }
21
+ its(:name_changed?) { should be_falsey }
22
22
  end
23
23
  end
24
24
 
@@ -33,13 +33,13 @@ describe ActiveRemote::Dirty do
33
33
  context "when the value changes" do
34
34
  before { subject[:name] = 'bar' }
35
35
 
36
- its(:name_changed?) { should be_true }
36
+ its(:name_changed?) { should be_truthy }
37
37
  end
38
38
 
39
39
  context "when the value doesn't change" do
40
40
  before { subject[:name] = 'foo' }
41
41
 
42
- its(:name_changed?) { should be_false }
42
+ its(:name_changed?) { should be_falsey }
43
43
  end
44
44
  end
45
45
 
@@ -47,7 +47,7 @@ describe ActiveRemote::Dirty do
47
47
  subject { Post.new(:name => 'foo') }
48
48
 
49
49
  before {
50
- Post.stub(:find).and_return({})
50
+ allow(Post).to receive(:find).and_return({})
51
51
  subject.reload
52
52
  }
53
53
 
@@ -60,7 +60,7 @@ describe ActiveRemote::Dirty do
60
60
  subject { Post.new(:name => 'foo') }
61
61
 
62
62
  before {
63
- subject.stub(:create_or_update).and_return(true)
63
+ allow(subject).to receive(:create_or_update).and_return(true)
64
64
  subject.save
65
65
  }
66
66
 
@@ -74,7 +74,7 @@ describe ActiveRemote::Dirty do
74
74
  subject { Post.new(:name => 'foo') }
75
75
 
76
76
  before {
77
- subject.stub(:save).and_return(true)
77
+ allow(subject).to receive(:save).and_return(true)
78
78
  subject.save!
79
79
  }
80
80
 
@@ -88,12 +88,12 @@ describe ActiveRemote::Dirty do
88
88
 
89
89
  it "clears previous changes" do
90
90
  new_record = post.instantiate(record.to_hash)
91
- new_record.previous_changes.should be_nil
91
+ expect(new_record.previous_changes).to eq({})
92
92
  end
93
93
 
94
94
  it "clears changes" do
95
95
  new_record = post.instantiate(record.to_hash)
96
- new_record.changes.should be_empty
96
+ expect(new_record.changes).to be_empty
97
97
  end
98
98
  end
99
99
  end