active_remote 1.3.3 → 1.4.0

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.
@@ -38,10 +38,10 @@ module ActiveRemote
38
38
  # end
39
39
  #
40
40
  def belongs_to(belongs_to_klass, options={})
41
- perform_association( belongs_to_klass, options ) do |klass, obj|
41
+ perform_association(belongs_to_klass, options) do |klass, object|
42
42
  foreign_key = options.fetch(:foreign_key) { :"#{belongs_to_klass}_guid" }
43
- association_guid = obj.read_attribute(foreign_key)
44
- klass.search(:guid => association_guid).first
43
+ association_guid = object.read_attribute(foreign_key)
44
+ klass.search(:guid => association_guid).first if association_guid
45
45
  end
46
46
  end
47
47
 
@@ -76,9 +76,9 @@ module ActiveRemote
76
76
  # end
77
77
  #
78
78
  def has_many(has_many_class, options={})
79
- perform_association( has_many_class, options ) do |klass, obj|
80
- foreign_key = options.fetch(:foreign_key) { :"#{obj.class.name.demodulize.underscore}_guid" }
81
- klass.search(foreign_key => obj.guid)
79
+ perform_association( has_many_class, options ) do |klass, object|
80
+ foreign_key = options.fetch(:foreign_key) { :"#{object.class.name.demodulize.underscore}_guid" }
81
+ object.guid ? klass.search(foreign_key => object.guid) : []
82
82
  end
83
83
  end
84
84
 
@@ -112,9 +112,9 @@ module ActiveRemote
112
112
  # end
113
113
  #
114
114
  def has_one(has_one_klass, options={})
115
- perform_association( has_one_klass, options ) do |klass, obj|
116
- foreign_key = options.fetch(:foreign_key) { :"#{obj.class.name.demodulize.underscore}_guid" }
117
- klass.search(foreign_key => obj.guid).first
115
+ perform_association(has_one_klass, options) do |klass, object|
116
+ foreign_key = options.fetch(:foreign_key) { :"#{object.class.name.demodulize.underscore}_guid" }
117
+ klass.search(foreign_key => object.guid).first if object.guid
118
118
  end
119
119
  end
120
120
 
@@ -51,6 +51,15 @@ module ActiveRemote
51
51
  end
52
52
  end
53
53
 
54
+ # Override #write_attribute (along with #[]=) so we can provide support for
55
+ # ActiveModel::Dirty.
56
+ #
57
+ def write_attribute(name, value)
58
+ __send__("#{name}_will_change!") unless value == self[name]
59
+ super
60
+ end
61
+ alias_method :[]=, :write_attribute
62
+
54
63
  private
55
64
 
56
65
  # Override ActiveAttr's attribute= method so we can provide support for
@@ -1,3 +1,3 @@
1
1
  module ActiveRemote
2
- VERSION = "1.3.3"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -1,144 +1,168 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe ActiveRemote::Association do
4
4
  let(:record) { double(:record) }
5
5
  let(:records) { [ record ] }
6
6
 
7
- describe '.belongs_to' do
8
-
9
- context 'simple association' do
10
- let(:author_guid) { 'AUT-123' }
7
+ describe ".belongs_to" do
8
+ context "simple association" do
9
+ let(:author_guid) { "AUT-123" }
11
10
 
12
11
  subject { Post.new(:author_guid => author_guid) }
12
+
13
13
  it { should respond_to(:author) }
14
14
 
15
- it 'searches the associated model for a single record' do
15
+ it "searches the associated model for a single record" do
16
16
  Author.should_receive(:search).with(:guid => subject.author_guid).and_return(records)
17
17
  subject.author.should eq record
18
18
  end
19
19
 
20
- it 'memoizes the result record' do
20
+ it "memoizes the result record" do
21
21
  Author.should_receive(:search).once.with(:guid => subject.author_guid).and_return(records)
22
22
  3.times { subject.author.should eq record }
23
23
  end
24
24
 
25
- context 'when the search is empty' do
26
- it 'returns a nil' do
25
+ context "when guid is nil" do
26
+ subject { Post.new }
27
+
28
+ it "returns nil" do
29
+ subject.author.should be_nil
30
+ end
31
+ end
32
+
33
+ context "when the search is empty" do
34
+ it "returns a nil" do
27
35
  Author.should_receive(:search).with(:guid => subject.author_guid).and_return([])
28
36
  subject.author.should be_nil
29
37
  end
30
38
  end
31
39
  end
32
40
 
33
- context 'specific association with class name' do
34
- let(:author_guid) { 'AUT-456' }
41
+ context "specific association with class name" do
42
+ let(:author_guid) { "AUT-456" }
35
43
 
36
44
  subject { Post.new(:author_guid => author_guid) }
37
45
  it { should respond_to(:coauthor) }
38
46
 
39
- it 'searches the associated model for a single record' do
47
+ it "searches the associated model for a single record" do
40
48
  Author.should_receive(:search).with(:guid => subject.author_guid).and_return(records)
41
49
  subject.author.should eq record
42
50
  end
43
51
  end
44
52
 
45
- context 'specific association with class name and foreign_key' do
46
- let(:author_guid) { 'AUT-456' }
53
+ context "specific association with class name and foreign_key" do
54
+ let(:author_guid) { "AUT-456" }
47
55
 
48
56
  subject { Post.new(:author_guid => author_guid) }
49
57
  it { should respond_to(:bestseller) }
50
58
 
51
- it 'searches the associated model for a single record' do
59
+ it "searches the associated model for a single record" do
52
60
  Author.should_receive(:search).with(:guid => subject.bestseller_guid).and_return(records)
53
61
  subject.author.should eq record
54
62
  end
55
63
  end
56
-
57
64
  end
58
65
 
59
- describe '.has_many' do
66
+ describe ".has_many" do
60
67
  let(:records) { [ record, record, record ] }
61
- let(:guid) { 'AUT-123' }
68
+ let(:guid) { "AUT-123" }
62
69
 
63
70
  subject { Author.new(:guid => guid) }
71
+
64
72
  it { should respond_to(:posts) }
65
73
 
66
- it 'searches the associated model for all associated records' do
74
+ it "searches the associated model for all associated records" do
67
75
  Post.should_receive(:search).with(:author_guid => subject.guid).and_return(records)
68
76
  subject.posts.should eq records
69
77
  end
70
78
 
71
- it 'memoizes the result record' do
79
+ it "memoizes the result record" do
72
80
  Post.should_receive(:search).once.with(:author_guid => subject.guid).and_return(records)
73
81
  3.times { subject.posts.should eq records }
74
82
  end
75
83
 
76
- context 'when the search is empty' do
77
- it 'returns the empty set' do
84
+ context "when guid is nil" do
85
+ subject { Author.new }
86
+
87
+ it "returns []" do
88
+ subject.posts.should eq []
89
+ end
90
+ end
91
+
92
+ context "when the search is empty" do
93
+ it "returns the empty set" do
78
94
  Post.should_receive(:search).with(:author_guid => subject.guid).and_return([])
79
95
  subject.posts.should be_empty
80
96
  end
81
97
  end
82
98
 
83
- context 'specific association with class name' do
99
+ context "specific association with class name" do
84
100
  it { should respond_to(:flagged_posts) }
85
101
 
86
- it 'searches the associated model for a single record' do
102
+ it "searches the associated model for a single record" do
87
103
  Post.should_receive(:search).with(:author_guid => subject.guid).and_return([])
88
104
  subject.flagged_posts.should be_empty
89
105
  end
90
106
  end
91
107
 
92
- context 'specific association with class name and foreign_key' do
108
+ context "specific association with class name and foreign_key" do
93
109
  it { should respond_to(:bestseller_posts) }
94
110
 
95
- it 'searches the associated model for multiple record' do
111
+ it "searches the associated model for multiple record" do
96
112
  Post.should_receive(:search).with(:bestseller_guid => subject.guid).and_return(records)
97
113
  subject.bestseller_posts.should eq(records)
98
114
  end
99
115
  end
100
116
  end
101
117
 
102
- describe '.has_one' do
103
- let(:guid) { 'PST-123' }
118
+ describe ".has_one" do
119
+ let(:guid) { "PST-123" }
104
120
 
105
121
  subject { Post.new(:guid => guid) }
122
+
106
123
  it { should respond_to(:category) }
107
124
 
108
- it 'searches the associated model for all associated records' do
125
+ it "searches the associated model for all associated records" do
109
126
  Category.should_receive(:search).with(:post_guid => subject.guid).and_return(records)
110
127
  subject.category.should eq record
111
128
  end
112
129
 
113
- it 'memoizes the result record' do
130
+ it "memoizes the result record" do
114
131
  Category.should_receive(:search).once.with(:post_guid => subject.guid).and_return(records)
115
132
  3.times { subject.category.should eq record }
116
133
  end
117
134
 
118
- context 'when the search is empty' do
119
- it 'returns a nil value' do
135
+ context "when guid is nil" do
136
+ subject { Post.new }
137
+
138
+ it "returns nil" do
139
+ subject.category.should be_nil
140
+ end
141
+ end
142
+
143
+ context "when the search is empty" do
144
+ it "returns a nil value" do
120
145
  Category.should_receive(:search).with(:post_guid => subject.guid).and_return([])
121
146
  subject.category.should be_nil
122
147
  end
123
148
  end
124
149
 
125
- context 'specific association with class name' do
150
+ context "specific association with class name" do
126
151
  it { should respond_to(:main_category) }
127
152
 
128
- it 'searches the associated model for a single record' do
153
+ it "searches the associated model for a single record" do
129
154
  Category.should_receive(:search).with(:post_guid => subject.guid).and_return(records)
130
155
  subject.main_category.should eq record
131
156
  end
132
157
  end
133
158
 
134
- context 'specific association with class name and foreign_key' do
159
+ context "specific association with class name and foreign_key" do
135
160
  it { should respond_to(:default_category) }
136
161
 
137
- it 'searches the associated model for a single record' do
162
+ it "searches the associated model for a single record" do
138
163
  Category.should_receive(:search).with(:template_post_guid => subject.guid).and_return(records)
139
164
  subject.default_category.should eq record
140
165
  end
141
166
  end
142
167
  end
143
-
144
168
  end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::Dirty do
4
+ context "when writing attributes through the setter" do
5
+ subject { Post.new(:name => 'foo') }
6
+
7
+ before {
8
+ subject.previous_changes.try(:clear)
9
+ subject.changed_attributes.try(:clear)
10
+ }
11
+
12
+ context "when the value changes" do
13
+ before { subject.name = 'bar' }
14
+
15
+ its(:name_changed?) { should be_true }
16
+ end
17
+
18
+ context "when the value doesn't change" do
19
+ before { subject.name = 'foo' }
20
+
21
+ its(:name_changed?) { should be_false }
22
+ end
23
+ end
24
+
25
+ context "when writing attributes directly" do
26
+ subject { Post.new(:name => 'foo') }
27
+
28
+ before {
29
+ subject.previous_changes.try(:clear)
30
+ subject.changed_attributes.try(:clear)
31
+ }
32
+
33
+ context "when the value changes" do
34
+ before { subject[:name] = 'bar' }
35
+
36
+ its(:name_changed?) { should be_true }
37
+ end
38
+
39
+ context "when the value doesn't change" do
40
+ before { subject[:name] = 'foo' }
41
+
42
+ its(:name_changed?) { should be_false }
43
+ end
44
+ end
45
+
46
+ describe "#reload" do
47
+ subject { Post.new(:name => 'foo') }
48
+
49
+ before {
50
+ subject.stub(:last_response).and_return({})
51
+ subject.stub(:execute)
52
+ subject.reload
53
+ }
54
+
55
+ its(:changes) { should be_empty }
56
+ end
57
+
58
+ describe "#save" do
59
+ let!(:changes) { subject.changes }
60
+
61
+ subject { Post.new(:name => 'foo') }
62
+
63
+ before {
64
+ subject.stub(:create_or_update).and_return(true)
65
+ subject.save
66
+ }
67
+
68
+ its(:previous_changes) { should eq changes }
69
+ its(:changes) { should be_empty }
70
+ end
71
+
72
+ describe "#save!" do
73
+ let!(:changes) { subject.changes }
74
+
75
+ subject { Post.new(:name => 'foo') }
76
+
77
+ before {
78
+ subject.stub(:save).and_return(true)
79
+ subject.save!
80
+ }
81
+
82
+ its(:previous_changes) { should eq changes }
83
+ its(:changes) { should be_empty }
84
+ end
85
+
86
+ describe "#serialize_records" do
87
+ let(:post) { Post.new }
88
+ let(:record) { ::Generic::Remote::Post.new(:name => 'foo') }
89
+ let(:response) { double(:response, :records => [ record ]) }
90
+
91
+ before {
92
+ post.stub(:last_response).and_return(response)
93
+ }
94
+
95
+ it "clears previous changes" do
96
+ records = post.serialize_records
97
+ records.first.previous_changes.should be_nil
98
+ end
99
+
100
+ it "clears changes" do
101
+ records = post.serialize_records
102
+ records.first.changes.should be_empty
103
+ end
104
+ end
105
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-27 00:00:00.000000000 Z
12
+ date: 2013-02-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: active_attr
@@ -178,6 +178,7 @@ files:
178
178
  - spec/lib/active_remote/association_spec.rb
179
179
  - spec/lib/active_remote/base_spec.rb
180
180
  - spec/lib/active_remote/bulk_spec.rb
181
+ - spec/lib/active_remote/dirty_spec.rb
181
182
  - spec/lib/active_remote/dsl_spec.rb
182
183
  - spec/lib/active_remote/persistence_spec.rb
183
184
  - spec/lib/active_remote/rpc_spec.rb
@@ -218,7 +219,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
219
  version: '0'
219
220
  segments:
220
221
  - 0
221
- hash: 432433655534443133
222
+ hash: -2137387569376097013
222
223
  required_rubygems_version: !ruby/object:Gem::Requirement
223
224
  none: false
224
225
  requirements:
@@ -227,7 +228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
228
  version: '0'
228
229
  segments:
229
230
  - 0
230
- hash: 432433655534443133
231
+ hash: -2137387569376097013
231
232
  requirements: []
232
233
  rubyforge_project:
233
234
  rubygems_version: 1.8.24
@@ -239,6 +240,7 @@ test_files:
239
240
  - spec/lib/active_remote/association_spec.rb
240
241
  - spec/lib/active_remote/base_spec.rb
241
242
  - spec/lib/active_remote/bulk_spec.rb
243
+ - spec/lib/active_remote/dirty_spec.rb
242
244
  - spec/lib/active_remote/dsl_spec.rb
243
245
  - spec/lib/active_remote/persistence_spec.rb
244
246
  - spec/lib/active_remote/rpc_spec.rb