toystore 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
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