active_remote 2.4.0 → 3.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -0
  3. data/CHANGES.md +22 -0
  4. data/README.md +2 -0
  5. data/active_remote.gemspec +2 -2
  6. data/bin/console +10 -0
  7. data/lib/active_remote/association.rb +4 -0
  8. data/lib/active_remote/attribute_assignment.rb +53 -0
  9. data/lib/active_remote/attribute_definition.rb +106 -0
  10. data/lib/active_remote/attributes.rb +165 -8
  11. data/lib/active_remote/base.rb +41 -36
  12. data/lib/active_remote/dirty.rb +0 -9
  13. data/lib/active_remote/errors.rb +6 -0
  14. data/lib/active_remote/persistence.rb +10 -19
  15. data/lib/active_remote/query_attributes.rb +45 -0
  16. data/lib/active_remote/rpc.rb +17 -67
  17. data/lib/active_remote/search.rb +0 -20
  18. data/lib/active_remote/serialization.rb +1 -32
  19. data/lib/active_remote/typecasting.rb +3 -12
  20. data/lib/active_remote/version.rb +1 -1
  21. data/lib/active_remote.rb +0 -2
  22. data/spec/lib/active_remote/association_spec.rb +11 -2
  23. data/spec/lib/active_remote/attributes_spec.rb +177 -0
  24. data/spec/lib/active_remote/persistence_spec.rb +7 -16
  25. data/spec/lib/active_remote/query_attribute_spec.rb +171 -0
  26. data/spec/lib/active_remote/rpc_spec.rb +33 -75
  27. data/spec/lib/active_remote/search_spec.rb +0 -21
  28. data/spec/lib/active_remote/serialization_spec.rb +0 -23
  29. data/spec/support/models/no_attributes.rb +2 -0
  30. data/spec/support/models.rb +1 -0
  31. metadata +21 -66
  32. data/lib/active_remote/attribute_defaults.rb +0 -100
  33. data/lib/active_remote/bulk.rb +0 -168
  34. data/lib/active_remote/core_ext/date.rb +0 -7
  35. data/lib/active_remote/core_ext/date_time.rb +0 -7
  36. data/lib/active_remote/core_ext/integer.rb +0 -19
  37. data/lib/active_remote/core_ext.rb +0 -3
  38. data/lib/active_remote/publication.rb +0 -54
  39. data/lib/active_remote/serializers/json.rb +0 -16
  40. data/spec/core_ext/date_time_spec.rb +0 -9
  41. data/spec/lib/active_remote/attribute_defaults_spec.rb +0 -26
  42. data/spec/lib/active_remote/bulk_spec.rb +0 -83
  43. data/spec/lib/active_remote/publication_spec.rb +0 -18
  44. data/spec/lib/active_remote/serializers/json_spec.rb +0 -78
@@ -0,0 +1,171 @@
1
+ require "spec_helper"
2
+
3
+ describe ::ActiveRemote::QueryAttributes do
4
+ subject { ::Author.new }
5
+
6
+ describe "#query_attribute" do
7
+ it "raises when getting an undefined attribute" do
8
+ expect { subject.query_attribute(:foobar) }.to raise_error(::ActiveRemote::UnknownAttributeError)
9
+ end
10
+
11
+ it "is false when the attribute is false" do
12
+ subject.name = false
13
+ expect(subject.name?).to eq false
14
+ end
15
+
16
+ it "is true when the attribute is true" do
17
+ subject.name = true
18
+ expect(subject.name?).to eq true
19
+ end
20
+
21
+ it "is false when the attribute is nil" do
22
+ subject.name = nil
23
+ expect(subject.name?).to eq false
24
+ end
25
+
26
+ it "is true when the attribute is an Object" do
27
+ subject.name = Object.new
28
+ expect(subject.name?).to eq true
29
+ end
30
+
31
+ it "is false when the attribute is an empty string" do
32
+ subject.name = ""
33
+ expect(subject.name?).to eq false
34
+ end
35
+
36
+ it "is true when the attribute is a non-empty string" do
37
+ subject.name = "Chris"
38
+ expect(subject.name?).to eq true
39
+ end
40
+
41
+ it "is false when the attribute is 0" do
42
+ subject.name = 0
43
+ expect(subject.name?).to eq false
44
+ end
45
+
46
+ it "is true when the attribute is 1" do
47
+ subject.name = 1
48
+ expect(subject.name?).to eq true
49
+ end
50
+
51
+ it "is false when the attribute is 0.0" do
52
+ subject.name = 0.0
53
+ expect(subject.name?).to eq false
54
+ end
55
+
56
+ it "is true when the attribute is 0.1" do
57
+ subject.name = 0.1
58
+ expect(subject.name?).to eq true
59
+ end
60
+
61
+ it "is false when the attribute is a zero BigDecimal" do
62
+ subject.name = BigDecimal.new("0.0")
63
+ expect(subject.name?).to eq false
64
+ end
65
+
66
+ it "is true when the attribute is a non-zero BigDecimal" do
67
+ subject.name = BigDecimal.new("0.1")
68
+ expect(subject.name?).to eq true
69
+ end
70
+
71
+ it "is true when the attribute is -1" do
72
+ subject.name = -1
73
+ expect(subject.name?).to eq true
74
+ end
75
+
76
+ it "is false when the attribute is -0.0" do
77
+ subject.name = -0.0
78
+ expect(subject.name?).to eq false
79
+ end
80
+
81
+ it "is true when the attribute is -0.1" do
82
+ subject.name = -0.1
83
+ expect(subject.name?).to eq true
84
+ end
85
+
86
+ it "is false when the attribute is a negative zero BigDecimal" do
87
+ subject.name = BigDecimal.new("-0.0")
88
+ expect(subject.name?).to eq false
89
+ end
90
+
91
+ it "is true when the attribute is a negative BigDecimal" do
92
+ subject.name = BigDecimal.new("-0.1")
93
+ expect(subject.name?).to eq true
94
+ end
95
+
96
+ it "is false when the attribute is '0'" do
97
+ subject.name = "0"
98
+ expect(subject.name?).to eq false
99
+ end
100
+
101
+ it "is true when the attribute is '1'" do
102
+ subject.name = "1"
103
+ expect(subject.name?).to eq true
104
+ end
105
+
106
+ it "is false when the attribute is '0.0'" do
107
+ subject.name = "0.0"
108
+ expect(subject.name?).to eq false
109
+ end
110
+
111
+ it "is true when the attribute is '0.1'" do
112
+ subject.name = "0.1"
113
+ expect(subject.name?).to eq true
114
+ end
115
+
116
+ it "is true when the attribute is '-1'" do
117
+ subject.name = "-1"
118
+ expect(subject.name?).to eq true
119
+ end
120
+
121
+ it "is false when the attribute is '-0.0'" do
122
+ subject.name = "-0.0"
123
+ expect(subject.name?).to eq false
124
+ end
125
+
126
+ it "is true when the attribute is '-0.1'" do
127
+ subject.name = "-0.1"
128
+ expect(subject.name?).to eq true
129
+ end
130
+
131
+ it "is true when the attribute is 'true'" do
132
+ subject.name = "true"
133
+ expect(subject.name?).to eq true
134
+ end
135
+
136
+ it "is false when the attribute is 'false'" do
137
+ subject.name = "false"
138
+ expect(subject.name?).to eq false
139
+ end
140
+
141
+ it "is true when the attribute is 't'" do
142
+ subject.name = "t"
143
+ expect(subject.name?).to eq true
144
+ end
145
+
146
+ it "is false when the attribute is 'f'" do
147
+ subject.name = "f"
148
+ expect(subject.name?).to eq false
149
+ end
150
+
151
+ it "is true when the attribute is 'T'" do
152
+ subject.name = "T"
153
+ expect(subject.name?).to eq true
154
+ end
155
+
156
+ it "is false when the attribute is 'F'" do
157
+ subject.name = "F"
158
+ expect(subject.name?).to eq false
159
+ end
160
+
161
+ it "is true when the attribute is 'TRUE'" do
162
+ subject.name = "TRUE"
163
+ expect(subject.name?).to eq true
164
+ end
165
+
166
+ it "is false when the attribute is 'FALSE" do
167
+ subject.name = "FALSE"
168
+ expect(subject.name?).to eq false
169
+ end
170
+ end
171
+ end
@@ -1,95 +1,53 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ActiveRemote::RPC do
4
- subject { Tag.new }
3
+ describe ::ActiveRemote::RPC do
4
+ subject { ::Tag.new }
5
5
 
6
- describe ".remote_call" do
7
- let(:args) { double(:args) }
8
- let(:response) { double(:response) }
9
-
10
- let(:rpc) { ::ActiveRemote::RPCAdapters::ProtobufAdapter.new(::Tag.service_class) }
11
-
12
- before { allow(rpc).to receive(:execute).and_return(response) }
13
- before { allow(::Tag).to receive(:rpc).and_return(rpc) }
14
-
15
- it "calls the given RPC method" do
16
- expect(Tag.rpc).to receive(:execute).with(:remote_method, args)
17
- Tag.remote_call(:remote_method, args)
18
- end
6
+ describe ".build_from_rpc" do
7
+ let(:new_attributes) { { :name => "test" } }
19
8
 
20
- it "returns the response" do
21
- allow(Tag.rpc).to receive(:execute).and_return(response)
22
- expect(Tag.remote_call(:remote_method, args)).to eq response
23
- end
24
- end
25
-
26
- describe ".request" do
27
- let(:attributes) { Hash.new }
28
-
29
- it "builds an RPC request" do
30
- expect(Tag.request(:create, attributes)).to eq Generic::Remote::Tag.new(attributes)
31
- end
32
- end
33
-
34
- describe ".request_type" do
35
- it "fetches the request type for the given RPC method" do
36
- expect(Tag.request_type(:search)).to eq Generic::Remote::TagRequest
37
- end
38
- end
39
-
40
- describe "#execute" do
41
- let(:request) { double(:request) }
42
-
43
- it "calls the given RPC method" do
44
- mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
45
- subject.execute(:create, request)
9
+ context "missing attributes from rpc" do
10
+ it "initializes to nil" do
11
+ expect(::Tag.build_from_rpc(new_attributes)).to include("guid" => nil)
12
+ end
46
13
  end
47
14
 
48
- it "sets the last request" do
49
- mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
15
+ context "extra attributes from rpc" do
16
+ let(:new_attributes) { { :foobar => "test" } }
50
17
 
51
- subject.execute(:create, request)
52
- expect(subject.last_request).to eq(request)
18
+ it "ignores unknown attributes" do
19
+ expect(::Tag.build_from_rpc(new_attributes)).to_not include("foobar" => "test")
20
+ end
53
21
  end
54
22
 
55
- context "when request args is a hash" do
56
- let(:args){ Hash.new }
57
- let(:request) { double(:request) }
23
+ context "typecasted attributes" do
24
+ let(:new_attributes) { { :birthday => "2017-01-01" } }
58
25
 
59
- before {
60
- allow(subject).to receive(:request).and_return(request)
61
- mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
62
- }
63
-
64
- it "creates a request" do
65
- expect(subject).to receive(:request).with(:create, args)
66
- subject.execute(:create, args)
26
+ it "calls the typecasters" do
27
+ expect(
28
+ ::TypecastedAuthor.build_from_rpc(new_attributes)
29
+ ).to include("birthday" => "2017-01-01".to_datetime)
67
30
  end
68
31
  end
32
+ end
69
33
 
70
- context "when a request succeeds" do
71
- let(:success_response) { double(:status => 'success', :awesome_town => true, :to_hash => {}) }
72
-
73
- before {
74
- mock_remote_service(Tag.service_class, :create, :response => success_response)
75
- }
34
+ describe ".remote_call" do
35
+ let(:args) { double(:args) }
36
+ let(:response) { double(:response) }
76
37
 
77
- it "sets the last response" do
78
- subject.execute(:create, request)
79
- expect(subject.last_response).to eq(success_response)
80
- end
81
- end
38
+ let(:rpc) { ::ActiveRemote::RPCAdapters::ProtobufAdapter.new(::Tag.service_class) }
82
39
 
83
- context "when a request fails" do
84
- let(:error_response) { double(:error, :message => "Boom goes the dynamite!") }
40
+ before { allow(rpc).to receive(:execute).and_return(response) }
41
+ before { allow(::Tag).to receive(:rpc).and_return(rpc) }
85
42
 
86
- before {
87
- mock_remote_service(Tag.service_class, :create, :error => error_response)
88
- }
43
+ it "calls the given RPC method" do
44
+ expect(::Tag.rpc).to receive(:execute).with(:remote_method, args)
45
+ ::Tag.remote_call(:remote_method, args)
46
+ end
89
47
 
90
- it "raises an exception" do
91
- expect { subject.execute(:create, request) }.to raise_error(ActiveRemote::ActiveRemoteError)
92
- end
48
+ it "returns the response" do
49
+ allow(::Tag.rpc).to receive(:execute).and_return(response)
50
+ expect(::Tag.remote_call(:remote_method, args)).to eq response
93
51
  end
94
52
  end
95
53
  end
@@ -65,27 +65,6 @@ describe ActiveRemote::Search do
65
65
  end
66
66
  end
67
67
 
68
- describe "#_active_remote_search" do
69
- let(:args) { Hash.new }
70
-
71
- subject { Tag.new }
72
-
73
- before {
74
- allow(rpc).to receive(:execute).and_return(response)
75
- allow(Tag).to receive(:rpc).and_return(rpc)
76
- }
77
-
78
- it "runs callbacks" do
79
- expect(subject).to receive(:run_callbacks).with(:search)
80
- subject._active_remote_search(args)
81
- end
82
-
83
- it "executes the search" do
84
- expect(rpc).to receive(:execute).with(:search, args)
85
- subject._active_remote_search(args)
86
- end
87
- end
88
-
89
68
  describe "#reload" do
90
69
  let(:args) { attributes.slice('guid', 'user_guid') }
91
70
  let(:attributes) { HashWithIndifferentAccess.new(:guid => 'foo', :name => 'bar', :updated_at => nil, :user_guid => 'baz') }
@@ -30,27 +30,4 @@ describe ActiveRemote::Serialization do
30
30
  end
31
31
  end
32
32
  end
33
-
34
- describe "#add_errors_from_response" do
35
- subject { Tag.new }
36
-
37
- context "when the response responds to :errors" do
38
- let(:error) { Generic::Error.new(:field => 'name', :message => 'Boom!') }
39
- let(:response) { Generic::Remote::Tag.new(:errors => [ error ]) }
40
-
41
- it "adds errors to the active remote object" do
42
- expect(subject).to receive(:add_errors).with(response.errors)
43
- subject.add_errors_from_response(response)
44
- end
45
- end
46
-
47
- context "when the response does not respond to :errors" do
48
- let(:response_without_errors) { double(:response_without_errors) }
49
-
50
- it "does not add errors" do
51
- expect(subject).to_not receive(:add_errors)
52
- subject.add_errors_from_response(response_without_errors)
53
- end
54
- end
55
- end
56
33
  end
@@ -0,0 +1,2 @@
1
+ class NoAttributes < ::ActiveRemote::Base
2
+ end
@@ -2,6 +2,7 @@ require 'support/models/message_with_options'
2
2
  require 'support/models/author'
3
3
  require 'support/models/default_author'
4
4
  require 'support/models/category'
5
+ require 'support/models/no_attributes'
5
6
  require 'support/models/post'
6
7
  require 'support/models/tag'
7
8
  require 'support/models/typecasted_author'
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 3.0.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Hutchison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-20 00:00:00.000000000 Z
11
+ date: 2017-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: active_attr
14
+ name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.8'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0.8'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3.2'
33
+ version: '4.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3.2'
40
+ version: '4.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: protobuf
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -155,42 +155,41 @@ description: Active Remote provides Active Record-like object-relational mapping
155
155
  to use any RPC data format.
156
156
  email:
157
157
  - liveh2o@gmail.com
158
- executables: []
158
+ executables:
159
+ - console
159
160
  extensions: []
160
161
  extra_rdoc_files: []
161
162
  files:
162
163
  - ".gitignore"
163
164
  - ".rspec"
165
+ - ".travis.yml"
166
+ - CHANGES.md
164
167
  - Gemfile
165
168
  - LICENSE
166
169
  - README.md
167
170
  - Rakefile
168
171
  - active_remote.gemspec
172
+ - bin/console
169
173
  - lib/active_remote.rb
170
174
  - lib/active_remote/association.rb
171
- - lib/active_remote/attribute_defaults.rb
175
+ - lib/active_remote/attribute_assignment.rb
176
+ - lib/active_remote/attribute_definition.rb
172
177
  - lib/active_remote/attributes.rb
173
178
  - lib/active_remote/base.rb
174
- - lib/active_remote/bulk.rb
175
179
  - lib/active_remote/config.rb
176
- - lib/active_remote/core_ext.rb
177
- - lib/active_remote/core_ext/date.rb
178
- - lib/active_remote/core_ext/date_time.rb
179
- - lib/active_remote/core_ext/integer.rb
180
180
  - lib/active_remote/dirty.rb
181
181
  - lib/active_remote/dsl.rb
182
182
  - lib/active_remote/errors.rb
183
183
  - lib/active_remote/integration.rb
184
184
  - lib/active_remote/persistence.rb
185
185
  - lib/active_remote/primary_key.rb
186
- - lib/active_remote/publication.rb
186
+ - lib/active_remote/query_attributes.rb
187
187
  - lib/active_remote/railtie.rb
188
188
  - lib/active_remote/rpc.rb
189
189
  - lib/active_remote/rpc_adapters/protobuf_adapter.rb
190
190
  - lib/active_remote/scope_keys.rb
191
191
  - lib/active_remote/search.rb
192
192
  - lib/active_remote/serialization.rb
193
- - lib/active_remote/serializers/json.rb
194
193
  - lib/active_remote/serializers/protobuf.rb
195
194
  - lib/active_remote/typecasting.rb
196
195
  - lib/active_remote/typecasting/big_decimal_typecaster.rb
@@ -204,22 +203,19 @@ files:
204
203
  - lib/active_remote/typecasting/string_typecaster.rb
205
204
  - lib/active_remote/validations.rb
206
205
  - lib/active_remote/version.rb
207
- - spec/core_ext/date_time_spec.rb
208
206
  - spec/lib/active_remote/association_spec.rb
209
- - spec/lib/active_remote/attribute_defaults_spec.rb
207
+ - spec/lib/active_remote/attributes_spec.rb
210
208
  - spec/lib/active_remote/base_spec.rb
211
- - spec/lib/active_remote/bulk_spec.rb
212
209
  - spec/lib/active_remote/dirty_spec.rb
213
210
  - spec/lib/active_remote/dsl_spec.rb
214
211
  - spec/lib/active_remote/integration_spec.rb
215
212
  - spec/lib/active_remote/persistence_spec.rb
216
213
  - spec/lib/active_remote/primary_key_spec.rb
217
- - spec/lib/active_remote/publication_spec.rb
214
+ - spec/lib/active_remote/query_attribute_spec.rb
218
215
  - spec/lib/active_remote/rpc_spec.rb
219
216
  - spec/lib/active_remote/scope_keys_spec.rb
220
217
  - spec/lib/active_remote/search_spec.rb
221
218
  - spec/lib/active_remote/serialization_spec.rb
222
- - spec/lib/active_remote/serializers/json_spec.rb
223
219
  - spec/lib/active_remote/serializers/protobuf_spec.rb
224
220
  - spec/lib/active_remote/typecasting_spec.rb
225
221
  - spec/lib/active_remote/validations_spec.rb
@@ -236,6 +232,7 @@ files:
236
232
  - spec/support/models/category.rb
237
233
  - spec/support/models/default_author.rb
238
234
  - spec/support/models/message_with_options.rb
235
+ - spec/support/models/no_attributes.rb
239
236
  - spec/support/models/post.rb
240
237
  - spec/support/models/tag.rb
241
238
  - spec/support/models/typecasted_author.rb
@@ -260,55 +257,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
260
257
  version: '0'
261
258
  required_rubygems_version: !ruby/object:Gem::Requirement
262
259
  requirements:
263
- - - ">="
260
+ - - ">"
264
261
  - !ruby/object:Gem::Version
265
- version: '0'
262
+ version: 1.3.1
266
263
  requirements: []
267
264
  rubyforge_project:
268
265
  rubygems_version: 2.6.10
269
266
  signing_key:
270
267
  specification_version: 4
271
268
  summary: Active Record for your platform
272
- test_files:
273
- - spec/core_ext/date_time_spec.rb
274
- - spec/lib/active_remote/association_spec.rb
275
- - spec/lib/active_remote/attribute_defaults_spec.rb
276
- - spec/lib/active_remote/base_spec.rb
277
- - spec/lib/active_remote/bulk_spec.rb
278
- - spec/lib/active_remote/dirty_spec.rb
279
- - spec/lib/active_remote/dsl_spec.rb
280
- - spec/lib/active_remote/integration_spec.rb
281
- - spec/lib/active_remote/persistence_spec.rb
282
- - spec/lib/active_remote/primary_key_spec.rb
283
- - spec/lib/active_remote/publication_spec.rb
284
- - spec/lib/active_remote/rpc_spec.rb
285
- - spec/lib/active_remote/scope_keys_spec.rb
286
- - spec/lib/active_remote/search_spec.rb
287
- - spec/lib/active_remote/serialization_spec.rb
288
- - spec/lib/active_remote/serializers/json_spec.rb
289
- - spec/lib/active_remote/serializers/protobuf_spec.rb
290
- - spec/lib/active_remote/typecasting_spec.rb
291
- - spec/lib/active_remote/validations_spec.rb
292
- - spec/spec_helper.rb
293
- - spec/support/definitions/author.proto
294
- - spec/support/definitions/category.proto
295
- - spec/support/definitions/error.proto
296
- - spec/support/definitions/post.proto
297
- - spec/support/definitions/serializer.proto
298
- - spec/support/definitions/tag.proto
299
- - spec/support/helpers.rb
300
- - spec/support/models.rb
301
- - spec/support/models/author.rb
302
- - spec/support/models/category.rb
303
- - spec/support/models/default_author.rb
304
- - spec/support/models/message_with_options.rb
305
- - spec/support/models/post.rb
306
- - spec/support/models/tag.rb
307
- - spec/support/models/typecasted_author.rb
308
- - spec/support/protobuf.rb
309
- - spec/support/protobuf/author.pb.rb
310
- - spec/support/protobuf/category.pb.rb
311
- - spec/support/protobuf/error.pb.rb
312
- - spec/support/protobuf/post.pb.rb
313
- - spec/support/protobuf/serializer.pb.rb
314
- - spec/support/protobuf/tag.pb.rb
269
+ test_files: []
@@ -1,100 +0,0 @@
1
- require "active_support/concern"
2
- require "active_support/core_ext/object/duplicable"
3
-
4
- module ActiveRemote
5
- # AttributeDefaults allows defaults to be declared for your attributes
6
- #
7
- # Defaults are declared by passing the :default option to the attribute
8
- # class method. If you need the default to be dynamic, pass a lambda, Proc,
9
- # or any object that responds to #call as the value to the :default option
10
- # and the result will calculated on initialization. These dynamic defaults
11
- # can depend on the values of other attributes when those attributes are
12
- # assigned using MassAssignment or BlockInitialization.
13
- #
14
- # @example Usage
15
- # class Person
16
- # include ActiveRemote::AttributeDefaults
17
- #
18
- # attribute :first_name, :default => "John"
19
- # attribute :last_name, :default => "Doe"
20
- # end
21
- #
22
- # person = Person.new
23
- # person.first_name #=> "John"
24
- # person.last_name #=> "Doe"
25
- #
26
- # @example Dynamic Default
27
- # class Event
28
- # include ActiveAttr::MassAssignment
29
- # include ActiveRemote::AttributeDefaults
30
- #
31
- # attribute :start_date
32
- # attribute :end_date, :default => lambda { start_date }
33
- # end
34
- #
35
- # event = Event.new(:start_date => Date.parse("2012-01-01"))
36
- # event.end_date.to_s #=> "2012-01-01"
37
- #
38
- module AttributeDefaults
39
- extend ActiveSupport::Concern
40
-
41
- # Applies the attribute defaults
42
- #
43
- # Applies all the default values to any attributes not yet set, avoiding
44
- # any attribute setter logic, such as dirty tracking.
45
- #
46
- # @example Usage
47
- # class Person
48
- # include ActiveRemote::AttributeDefaults
49
- #
50
- # attribute :first_name, :default => "John"
51
- # end
52
- #
53
- # person = Person.new
54
- # person.first_name #=> "John"
55
- #
56
- def apply_defaults(defaults=attribute_defaults)
57
- @attributes ||= {}
58
- defaults.each do |name, value|
59
- # instance variable is used here to avoid any dirty tracking in attribute setter methods
60
- @attributes[name] = value if @attributes[name].nil?
61
- end
62
- end
63
-
64
- # Calculates the attribute defaults from the attribute definitions
65
- #
66
- # @example Usage
67
- # class Person
68
- # include ActiveAttr::AttributeDefaults
69
- #
70
- # attribute :first_name, :default => "John"
71
- # end
72
- #
73
- # Person.new.attribute_defaults #=> {"first_name"=>"John"}
74
- #
75
- def attribute_defaults
76
- attributes_map { |name| _attribute_default name }
77
- end
78
-
79
- # Applies attribute default values
80
- #
81
- def initialize(*)
82
- super
83
- apply_defaults
84
- end
85
-
86
- private
87
-
88
- # Calculates an attribute default
89
- #
90
- def _attribute_default(attribute_name)
91
- default = self.class.attributes[attribute_name][:default]
92
-
93
- case
94
- when default.respond_to?(:call) then instance_exec(&default)
95
- when default.duplicable? then default.dup
96
- else default
97
- end
98
- end
99
- end
100
- end