toystore 0.10.1 → 0.10.2

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.
data/Changelog.md CHANGED
@@ -1,5 +1,11 @@
1
1
  I will do my best to keep this up to date with significant changes here, starting in 0.8.3.
2
2
 
3
+ * 0.10.2
4
+ * [Allow changing list attribute type](https://github.com/jnunemaker/toystore/commit/a5b1a944622509c32688d2e56088a7d7aa6fc0b3)
5
+ * [No longer include id in `persisted_attributes`](https://github.com/jnunemaker/toystore/commit/9f713311ebf174e314db700392e27af86ca00662)
6
+ * [Allow overriding `persist` safely](https://github.com/jnunemaker/toystore/commit/304e50c7e4ac11a365ae00f5d4caed722de31909)
7
+ * [Choose accessor over `write_attribute` for `attributes=`](https://github.com/jnunemaker/toystore/commit/65a8f81d933f0ebe1f13c9b1ff776f9e20333cb3)
8
+
3
9
  * 0.10.0
4
10
  * [Reference proxy api changes](https://github.com/jnunemaker/toystore/pull/5) thanks to jakehow
5
11
  * [Support for inheritance](https://github.com/jnunemaker/toystore/pull/4)
data/lib/toy.rb CHANGED
@@ -83,7 +83,6 @@ module Toy
83
83
  autoload 'Timestamps', 'toy/timestamps'
84
84
  autoload 'Validations', 'toy/validations'
85
85
 
86
- autoload 'Collection', 'toy/collection'
87
86
  autoload 'List', 'toy/list'
88
87
  autoload 'Lists', 'toy/lists'
89
88
  autoload 'Reference', 'toy/reference'
@@ -27,7 +27,7 @@ module Toy
27
27
  end
28
28
 
29
29
  def initialize(attrs={})
30
- initialize_attributes_with_defaults
30
+ initialize_attributes
31
31
  self.attributes = attrs
32
32
  write_attribute :id, self.class.next_key(self) unless id?
33
33
  end
@@ -42,7 +42,7 @@ module Toy
42
42
 
43
43
  def persisted_attributes
44
44
  {}.tap do |attrs|
45
- self.class.attributes.each do |name, attribute|
45
+ self.class.attributes.except('id').each do |name, attribute|
46
46
  next if attribute.virtual?
47
47
  attrs[attribute.persisted_name] = attribute.to_store(read_attribute(attribute.name))
48
48
  end
@@ -52,10 +52,10 @@ module Toy
52
52
  def attributes=(attrs, *)
53
53
  return if attrs.nil?
54
54
  attrs.each do |key, value|
55
- if attribute_method?(key)
56
- write_attribute(key, value)
57
- elsif respond_to?("#{key}=")
55
+ if respond_to?("#{key}=")
58
56
  send("#{key}=", value)
57
+ elsif attribute_method?(key)
58
+ write_attribute(key, value)
59
59
  end
60
60
  end
61
61
  end
@@ -71,16 +71,15 @@ module Toy
71
71
  private
72
72
 
73
73
  def read_attribute(key)
74
- @attributes ||= {}
75
74
  @attributes[key.to_s]
76
75
  end
77
76
 
78
77
  def write_attribute(key, value)
79
- @attributes[key.to_s] = attribute_definition(key).try(:from_store, value)
80
- end
81
-
82
- def attribute_definition(key)
83
- self.class.attributes[key.to_s]
78
+ key = key.to_s
79
+ attribute = self.class.attributes.fetch(key) {
80
+ raise AttributeNotDefined, "#{self.class} does not have attribute #{key}"
81
+ }
82
+ @attributes[key.to_s] = attribute.from_store(value)
84
83
  end
85
84
 
86
85
  def attribute_method?(key)
@@ -99,11 +98,11 @@ module Toy
99
98
  read_attribute(key).present?
100
99
  end
101
100
 
102
- def initialize_attributes_with_defaults
101
+ def initialize_attributes
103
102
  @attributes ||= {}
104
103
  self.class.defaulted_attributes.each do |attribute|
105
104
  @attributes[attribute.name.to_s] = attribute.default
106
105
  end
107
106
  end
108
107
  end
109
- end
108
+ end
data/lib/toy/dirty.rb CHANGED
@@ -19,10 +19,11 @@ module Toy
19
19
  end
20
20
 
21
21
  def write_attribute(name, value)
22
+ @attributes ||= {}
22
23
  name = name.to_s
23
24
  current = read_attribute(name)
24
25
  attribute_will_change!(name) if current != value
25
26
  super
26
27
  end
27
28
  end
28
- end
29
+ end
@@ -1,6 +1,8 @@
1
1
  module Toy
2
2
  class Error < StandardError; end
3
3
 
4
+ class AttributeNotDefined < Error; end
5
+
4
6
  class RecordInvalid < Error
5
7
  attr_reader :record
6
8
  def initialize(record)
@@ -26,4 +28,4 @@ module Toy
26
28
  super("Key may not be nil")
27
29
  end
28
30
  end
29
- end
31
+ end
data/lib/toy/list.rb CHANGED
@@ -2,19 +2,61 @@ require 'toy/proxies/list'
2
2
 
3
3
  module Toy
4
4
  class List
5
- include Toy::Collection
5
+ attr_accessor :model, :name, :options
6
6
 
7
- def after_initialize
8
- model.attribute(key, Array)
7
+ def initialize(model, name, *args, &block)
8
+ @model = model
9
+ @name = name.to_sym
10
+ @options = args.extract_options!
11
+ @type = args.shift
12
+
13
+ model.send(list_method)[name] = self
14
+
15
+ options[:extensions] = modularized_extensions(block, options[:extensions])
16
+
17
+ model.attribute(key, options.fetch(:attribute_type) { Array })
9
18
  create_accessors
10
19
  end
11
20
 
21
+ def type
22
+ @type ||= name.to_s.classify.constantize
23
+ end
24
+
12
25
  def key
13
26
  @key ||= :"#{name.to_s.singularize}_ids"
14
27
  end
15
28
 
29
+ def instance_variable
30
+ @instance_variable ||= :"@_#{name}"
31
+ end
32
+
33
+ def new_proxy(owner)
34
+ proxy_class.new(self, owner)
35
+ end
36
+
37
+ def extensions
38
+ options[:extensions]
39
+ end
40
+
41
+ def eql?(other)
42
+ self.class.eql?(other.class) &&
43
+ model == other.model &&
44
+ name == other.name
45
+ end
46
+ alias :== :eql?
47
+
16
48
  private
17
49
 
50
+ def proxy_class
51
+ raise('Not Implemented')
52
+ end
53
+
54
+ def modularized_extensions(*extensions)
55
+ extensions.flatten.compact.map do |extension|
56
+ Proc === extension ? Module.new(&extension) : extension
57
+ end
58
+ end
59
+
18
60
  def proxy_class
19
61
  Toy::Proxies::List
20
62
  end
@@ -44,4 +86,4 @@ module Toy
44
86
  end
45
87
  end
46
88
  end
47
- end
89
+ end
@@ -43,7 +43,7 @@ module Toy
43
43
 
44
44
  def initialize_from_database(attrs={})
45
45
  @_new_record = false
46
- initialize_attributes_with_defaults
46
+ initialize_attributes
47
47
  send("attributes=", attrs, false)
48
48
  self
49
49
  end
@@ -87,23 +87,18 @@ module Toy
87
87
  private
88
88
 
89
89
  def create
90
- persist!
90
+ persist
91
+ @_new_record = false
92
+ true
91
93
  end
92
94
 
93
95
  def update
94
- persist!
96
+ persist
97
+ true
95
98
  end
96
99
 
97
100
  def persist
98
- @_new_record = false
99
- end
100
-
101
- def persist!
102
- attrs = persisted_attributes
103
- attrs.delete('id') # no need to persist id as that is key
104
- adapter.write(id, attrs)
105
- persist
106
- true
101
+ adapter.write(id, persisted_attributes)
107
102
  end
108
103
  end
109
- end
104
+ end
@@ -4,7 +4,7 @@ module Toy
4
4
  if attrs = adapter.read(id)
5
5
  attrs['id'] = id
6
6
  instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
7
- initialize_attributes_with_defaults
7
+ initialize_attributes
8
8
  send(:attributes=, attrs, new_record?)
9
9
  self.class.lists.each_key { |name| send(name).reset }
10
10
  self.class.references.each_key { |name| send("reset_#{name}") }
data/lib/toy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Toy
2
- VERSION = "0.10.1"
2
+ VERSION = "0.10.2"
3
3
  end
@@ -156,6 +156,28 @@ describe Toy::Attributes do
156
156
  it "ignores keys that are not attributes and do not have accessors defined" do
157
157
  lambda { User.new(:taco => 'bell') }.should_not raise_error
158
158
  end
159
+
160
+ it "uses accessor over writing attribute" do
161
+ User.attribute :age, Integer
162
+
163
+ User.class_eval do
164
+ def age=(value)
165
+ write_attribute :age, value + 10
166
+ end
167
+ end
168
+
169
+ record = User.new
170
+ record.attributes = {:age => 15}
171
+ record.age.should be(25)
172
+ end
173
+
174
+ it "uses write_attribute if accessor not present" do
175
+ User.attribute :age, Integer
176
+ record = User.new
177
+ record.should_receive(:respond_to?).with("age=") { false }
178
+ record.attributes = {:age => 10}
179
+ record.age.should be(10)
180
+ end
159
181
  end
160
182
 
161
183
  describe "reading an attribute" do
@@ -169,6 +191,42 @@ describe Toy::Attributes do
169
191
  end
170
192
  end
171
193
 
194
+ describe "writing an attribute" do
195
+ before do
196
+ User.attribute :name, String
197
+
198
+ User.class_eval do
199
+ def alternate_name=(value)
200
+ write_attribute :name, value
201
+ end
202
+ end
203
+ end
204
+
205
+ it "assigns attribute value" do
206
+ user = User.new
207
+ user.alternate_name = 'Joe'
208
+ user.name.should eq('Joe')
209
+ end
210
+
211
+ context "when attribute not defined" do
212
+ before do
213
+ User.class_eval do
214
+ def pirate=(value)
215
+ write_attribute :pirate, value
216
+ end
217
+ end
218
+
219
+ @user = User.new
220
+ end
221
+
222
+ it "raises error" do
223
+ expect {
224
+ @user.pirate = 'arrrrrr'
225
+ }.to raise_error(Toy::AttributeNotDefined, "User does not have attribute pirate")
226
+ end
227
+ end
228
+ end
229
+
172
230
  describe "declaring an attribute" do
173
231
  before do
174
232
  User.attribute :name, String
@@ -271,25 +329,4 @@ describe Toy::Attributes do
271
329
  User.new.skills.should == []
272
330
  end
273
331
  end
274
-
275
- # https://github.com/newtoy/toystore/issues/13
276
- describe "Overriding initialize and setting an attribute before calling super" do
277
- before do
278
- User.attribute(:name, String)
279
- User.class_eval do
280
- def initialize(*)
281
- self.name = 'John'
282
- super
283
- end
284
- end
285
- end
286
-
287
- it "does not throw error" do
288
- lambda { User.new }.should_not raise_error
289
- end
290
-
291
- it "sets value" do
292
- User.new.name.should == 'John'
293
- end
294
- end
295
- end
332
+ end
@@ -64,4 +64,25 @@ describe Toy::Dirty do
64
64
  User.new.clone.should_not be_changed
65
65
  end
66
66
  end
67
- end
67
+
68
+ # https://github.com/newtoy/toystore/issues/13
69
+ describe "Overriding initialize and setting an attribute before calling super" do
70
+ before do
71
+ User.attribute(:name, String)
72
+ User.class_eval do
73
+ def initialize(*)
74
+ self.name = 'John'
75
+ super
76
+ end
77
+ end
78
+ end
79
+
80
+ it "does not throw error" do
81
+ lambda { User.new }.should_not raise_error
82
+ end
83
+
84
+ it "sets value" do
85
+ User.new.name.should == 'John'
86
+ end
87
+ end
88
+ end
@@ -63,26 +63,6 @@ describe Toy::List do
63
63
  end
64
64
  end
65
65
 
66
- describe "dependent" do
67
- before do
68
- User.list :games, :dependent => true
69
- @game = Game.create
70
- @user = User.create(:game_ids => [@game.id])
71
- end
72
-
73
- it "should create a method to destroy games" do
74
- User.new.should respond_to(:destroy_games)
75
- end
76
-
77
- it "should remove the games" do
78
- user_id = @user.id
79
- game_id = @game.id
80
- @user.destroy
81
- User.get(user_id).should be_nil
82
- Game.get(game_id).should be_nil
83
- end
84
- end
85
-
86
66
  describe "setting list type" do
87
67
  before do
88
68
  @list = User.list(:active_games, Game)
@@ -498,6 +478,37 @@ describe Toy::List do
498
478
  end
499
479
  end
500
480
 
481
+ describe "list with :dependent option" do
482
+ before do
483
+ User.list :games, :dependent => true
484
+ @game = Game.create
485
+ @user = User.create(:game_ids => [@game.id])
486
+ end
487
+
488
+ it "should create a method to destroy games" do
489
+ User.new.should respond_to(:destroy_games)
490
+ end
491
+
492
+ it "should remove the games" do
493
+ user_id = @user.id
494
+ game_id = @game.id
495
+ @user.destroy
496
+ User.get(user_id).should be_nil
497
+ Game.get(game_id).should be_nil
498
+ end
499
+ end
500
+
501
+ describe "list with :attribute_type option" do
502
+ before do
503
+ @type = stub
504
+ User.list :games, :attribute_type => @type
505
+ end
506
+
507
+ it "uses correct type" do
508
+ User.attributes['game_ids'].type.should eq(@type)
509
+ end
510
+ end
511
+
501
512
  describe "list extension with :extensions option" do
502
513
  before do
503
514
  old_module = Module.new do
@@ -572,4 +583,4 @@ describe Toy::List do
572
583
  @user.games.get!(@game.id).should == @game
573
584
  end
574
585
  end
575
- end
586
+ end
@@ -199,16 +199,44 @@ describe Toy::Persistence do
199
199
  context "with new record" do
200
200
  before do
201
201
  @doc = User.new(:name => 'John', :age => 28, :accepted_terms => true)
202
- @doc.save
203
202
  end
204
203
 
205
204
  it "saves to key" do
205
+ @doc.save
206
206
  User.key?(@doc.id)
207
207
  end
208
208
 
209
209
  it "does not persist virtual attributes" do
210
+ @doc.save
210
211
  @doc.adapter.read(@doc.id).should_not include('accepted_terms')
211
212
  end
213
+
214
+ it "is persisted" do
215
+ @doc.save
216
+ @doc.persisted?.should be_true
217
+ end
218
+
219
+ it "returns true" do
220
+ @doc.save.should be_true
221
+ end
222
+
223
+ context "with #persist overridden" do
224
+ before do
225
+ @doc.class_eval do
226
+ def persist
227
+ end
228
+ end
229
+ end
230
+
231
+ it "is persisted" do
232
+ @doc.save
233
+ @doc.persisted?.should be_true
234
+ end
235
+
236
+ it "returns true" do
237
+ @doc.save.should be_true
238
+ end
239
+ end
212
240
  end
213
241
 
214
242
  context "with existing record" do
@@ -218,25 +246,55 @@ describe Toy::Persistence do
218
246
  @value = User.adapter.read(@doc.id)
219
247
  @doc.name = 'Bill'
220
248
  @doc.accepted_terms = false
221
- @doc.save
222
249
  end
223
250
  let(:doc) { @doc }
224
251
 
225
252
  it "does not change primary key" do
253
+ @doc.save
226
254
  doc.id.should == @key
227
255
  end
228
256
 
229
257
  it "updates value in adapter" do
258
+ @doc.save
230
259
  User.adapter.read(doc.id).should_not == @value
231
260
  end
232
261
 
233
262
  it "does not persist virtual attributes" do
263
+ @doc.save
234
264
  @doc.adapter.read(@doc.id).should_not include('accepted_terms')
235
265
  end
236
266
 
237
267
  it "updates the attributes in the instance" do
268
+ @doc.save
238
269
  doc.name.should == 'Bill'
239
270
  end
271
+
272
+ it "is persisted" do
273
+ @doc.save
274
+ @doc.persisted?.should be_true
275
+ end
276
+
277
+ it "returns true" do
278
+ @doc.save.should be_true
279
+ end
280
+
281
+ context "with #persist overridden" do
282
+ before do
283
+ @doc.class_eval do
284
+ def persist
285
+ end
286
+ end
287
+ end
288
+
289
+ it "is persisted" do
290
+ @doc.save
291
+ doc.persisted?.should be_true
292
+ end
293
+
294
+ it "returns true" do
295
+ @doc.save.should be_true
296
+ end
297
+ end
240
298
  end
241
299
  end
242
300
 
@@ -296,4 +354,4 @@ describe Toy::Persistence do
296
354
  user.clone.should_not be_destroyed
297
355
  end
298
356
  end
299
- end
357
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toystore
3
3
  version: !ruby/object:Gem::Version
4
- hash: 53
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 10
9
- - 1
10
- version: 0.10.1
9
+ - 2
10
+ version: 0.10.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Geoffrey Dagley
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2012-04-22 00:00:00 Z
19
+ date: 2012-05-19 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  type: :runtime
@@ -131,7 +131,6 @@ files:
131
131
  - lib/toy/caching.rb
132
132
  - lib/toy/callbacks.rb
133
133
  - lib/toy/cloneable.rb
134
- - lib/toy/collection.rb
135
134
  - lib/toy/dirty.rb
136
135
  - lib/toy/dirty_store.rb
137
136
  - lib/toy/equality.rb
@@ -1,56 +0,0 @@
1
- module Toy
2
- module Collection
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- attr_accessor :model, :name, :options
7
- end
8
-
9
- def initialize(model, name, *args, &block)
10
- @model = model
11
- @name = name.to_sym
12
- @options = args.extract_options!
13
- @type = args.shift
14
-
15
- model.send(list_method)[name] = self
16
-
17
- options[:extensions] = modularized_extensions(block, options[:extensions])
18
- after_initialize
19
- end
20
-
21
- def type
22
- @type ||= name.to_s.classify.constantize
23
- end
24
-
25
- def instance_variable
26
- @instance_variable ||= :"@_#{name}"
27
- end
28
-
29
- def new_proxy(owner)
30
- proxy_class.new(self, owner)
31
- end
32
-
33
- def extensions
34
- options[:extensions]
35
- end
36
-
37
- def eql?(other)
38
- self.class.eql?(other.class) &&
39
- model == other.model &&
40
- name == other.name
41
- end
42
- alias :== :eql?
43
-
44
- private
45
-
46
- def proxy_class
47
- raise('Not Implemented')
48
- end
49
-
50
- def modularized_extensions(*extensions)
51
- extensions.flatten.compact.map do |extension|
52
- Proc === extension ? Module.new(&extension) : extension
53
- end
54
- end
55
- end
56
- end