appoxy-simple_record 1.0.23 → 1.0.26

Sign up to get free protection for your applications and to get access to all the features.
data/lib/simple_record.rb CHANGED
@@ -44,17 +44,137 @@ module SimpleRecord
44
44
  # :per_thread (one connection per thread)
45
45
  # :pool (uses a connection pool with a maximum number of connections - NOT IMPLEMENTED YET)
46
46
  # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
47
- # :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
48
47
  def self.establish_connection(aws_access_key=nil, aws_secret_key=nil, params={})
49
48
  RightAws::ActiveSdb.establish_connection(aws_access_key, aws_secret_key, params)
50
49
  end
51
50
 
52
51
  def self.close_connection()
53
- RightAws::ActiveSdb.close_connection
52
+ RightAws::ActiveSdb.close_connection
53
+ end
54
+
55
+ module Callbacks
56
+ #this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
57
+ #this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
58
+ #basically, this is how we recreate the callback functions
59
+ @@callbacks=["before_validation", "before_validation_on_create", "before_validation_on_update",
60
+ "after_validation", "after_validation_on_create", "after_validation_on_update",
61
+ "before_save", "before_create", "before_update",
62
+ "after_create", "after_update", "after_save",
63
+ "after_destroy"]
64
+
65
+ def self.included(base)
66
+ #puts 'Callbacks included in ' + base.inspect
67
+
68
+ end
54
69
  end
55
70
 
56
71
  class Base < RightAws::ActiveSdb::Base
57
72
 
73
+ include SimpleRecord::Callbacks
74
+
75
+
76
+ # todo: move into Callbacks module
77
+ #this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
78
+ #this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
79
+ #basically, this is how we recreate the callback functions
80
+ @@callbacks.each do |callback|
81
+ instance_eval <<-endofeval
82
+
83
+ #puts 'doing callback=' + callback + ' for ' + self.inspect
84
+ #we first have to make an initialized array for each of the callbacks, to prevent problems if they are not called
85
+
86
+ def #{callback}(*args)
87
+ #puts 'callback called in ' + self.inspect + ' with ' + args.inspect
88
+
89
+ #make_dirty(arg_s, value)
90
+ #self[arg.to_s]=value
91
+ #puts 'value in callback #{callback}=' + value.to_s
92
+ args.each do |arg|
93
+ cnames = callbacks['#{callback}']
94
+ #puts '\tcnames1=' + cnames.inspect + ' for class ' + self.inspect
95
+ cnames = [] if cnames.nil?
96
+ cnames << arg.to_s if cnames.index(arg.to_s).nil?
97
+ #puts '\tcnames2=' + cnames.inspect
98
+ callbacks['#{callback}'] = cnames
99
+ end
100
+ end
101
+
102
+ endofeval
103
+ end
104
+ #puts 'base methods=' + self.methods.inspect
105
+
106
+
107
+
108
+ def self.inherited(base)
109
+ puts 'SimpleRecord::Base is inherited by ' + base.inspect
110
+ setup_callbacks(base)
111
+
112
+ base.has_dates :created, :updated
113
+ base.before_create :set_created, :set_updated
114
+ base.before_update :set_updated
115
+
116
+ end
117
+
118
+ def self.setup_callbacks(base)
119
+ instance_eval <<-endofeval
120
+
121
+ def callbacks
122
+ @callbacks ||= {}
123
+ @callbacks
124
+ end
125
+
126
+ def self.defined_attributes
127
+ #puts 'class defined_attributes'
128
+ @attributes ||= {}
129
+ @attributes
130
+ end
131
+
132
+ endofeval
133
+
134
+ @@callbacks.each do |callback|
135
+ class_eval <<-endofeval
136
+
137
+ def run_#{callback}
138
+ #puts 'CLASS CALLBACKS for ' + self.inspect + ' = ' + self.class.callbacks.inspect
139
+ return true if self.class.callbacks.nil?
140
+ cnames = self.class.callbacks['#{callback}']
141
+ cnames = [] if cnames.nil?
142
+ #cnames += super.class.callbacks['#{callback}'] unless super.class.callbacks.nil?
143
+ # puts 'cnames XXX = ' + cnames.inspect
144
+ return true if cnames.nil?
145
+ cnames.each { |name|
146
+ #puts 'run_ #{name}'
147
+ unless eval(name)
148
+ return false
149
+ end
150
+ }
151
+ #super.run_#{callback}
152
+ return true
153
+ end
154
+
155
+ endofeval
156
+ end
157
+ end
158
+
159
+
160
+
161
+ # Holds information about an attribute
162
+ class Attribute
163
+ attr_accessor :type, :options
164
+
165
+ def initialize(type)
166
+ @type = type
167
+ end
168
+
169
+ end
170
+
171
+
172
+ def defined_attributes_local
173
+ #puts 'local defined_attributes'
174
+ self.class.defined_attributes
175
+ end
176
+
177
+
58
178
  attr_accessor :errors
59
179
  @@domain_prefix = ''
60
180
  @domain_name_for_class = nil
@@ -103,57 +223,67 @@ module SimpleRecord
103
223
  domain_name_for_class
104
224
  end
105
225
 
106
- #this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
107
- #this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
108
- #basically, this is how we recreate the callback functions
109
- @@callbacks=["before_save", "before_create", "after_create", "before_update", "after_update", "after_save", "after_destroy"]
110
- @@callbacks.each do |callback|
111
- #we first have to make an initialized array for each of the callbacks, to prevent problems if they are not called
112
- eval %{
113
- @@#{callback}_names=[]
114
226
 
115
- def self.#{callback}(*args)
116
- args.each do |arg|
117
- @@#{callback}_names << arg.to_s if @@#{callback}_names.index(arg.to_s).nil?
118
- end
119
- # asdf @@#{callback}_names=args.map{|arg| arg.to_s}
120
- end
121
227
 
122
- def run_#{callback}
123
- @@#{callback}_names.each { |name|
124
- unless eval(name)
125
- return false
126
- end
127
- }
128
- return true
228
+ # Since SimpleDB supports multiple attributes per value, the values are an array.
229
+ # This method will return the value unwrapped if it's the only, otherwise it will return the array.
230
+ def get_attribute(arg)
231
+ arg = arg.to_s
232
+ if self[arg].class==Array
233
+ if self[arg].length==1
234
+ ret = self[arg][0]
235
+ else
236
+ ret = self[arg]
237
+ end
238
+ else
239
+ ret = self[arg]
240
+ end
241
+ ret
129
242
  end
130
- }
243
+
244
+ def make_dirty(arg, value)
245
+ # todo: only set dirty if it changed
246
+ #puts 'making dirty ' + @dirty.inspect
247
+ @dirty[arg] = get_attribute(arg) # Store old value (not sure if we need it?)
248
+ #puts 'end making dirty ' + @dirty.inspect
131
249
  end
132
250
 
133
- @@attributes = []
134
251
  def self.has_attributes(*args)
135
252
  args.each do |arg|
136
- @@attributes << arg if @@attributes.index(arg).nil?
253
+ defined_attributes[arg] = SimpleRecord::Base::Attribute.new(:string) if defined_attributes[arg].nil?
137
254
  # define reader method
255
+ arg_s = arg.to_s # to get rid of all the to_s calls
138
256
  send :define_method, arg do
139
257
  ret = nil
140
- if self[arg.to_s].class==Array
141
- if self[arg.to_s].length==1
142
- ret = self[arg.to_s][0]
143
- else
144
- ret = self[arg.to_s]
145
- end
146
- else
147
- ret = self[arg.to_s]
148
- end
258
+ ret = get_attribute(arg)
149
259
  return nil if ret.nil?
150
260
  return un_offset_if_int(arg, ret)
151
261
  end
152
262
 
153
263
  # define writer method
154
- method_name = (arg.to_s+"=")
264
+ method_name = (arg_s+"=")
155
265
  send(:define_method, method_name) do |value|
156
- self[arg.to_s]=value# end
266
+ make_dirty(arg_s, value)
267
+ self[arg.to_s]=value
268
+ end
269
+
270
+ # Now for dirty methods: http://api.rubyonrails.org/classes/ActiveRecord/Dirty.html
271
+ # define changed? method
272
+ send(:define_method, arg_s + "_changed?") do
273
+ !@dirty[arg_s].nil?
274
+ end
275
+
276
+ # define change method
277
+ send(:define_method, arg_s + "_change") do
278
+ old_val = @dirty[arg_s]
279
+ return nil if old_val.nil?
280
+ [old_val, get_attribute(arg_s)]
281
+ end
282
+
283
+ # define was method
284
+ send(:define_method, arg_s + "_was") do
285
+ old_val = @dirty[arg_s]
286
+ old_val
157
287
  end
158
288
  end
159
289
  end
@@ -171,30 +301,22 @@ module SimpleRecord
171
301
  are_booleans(*args)
172
302
  end
173
303
 
174
- @@ints = []
175
304
  def self.are_ints(*args)
176
305
  # puts 'calling are_ints: ' + args.inspect
177
306
  args.each do |arg|
178
- # todo: maybe @@ints and @@dates should be maps for quicker lookups
179
- @@ints << arg if @@ints.index(arg).nil?
307
+ defined_attributes[arg].type = :int
180
308
  end
181
- # @@ints = args
182
- # puts 'ints=' + @@ints.inspect
183
309
  end
184
310
 
185
- @@dates = []
186
311
  def self.are_dates(*args)
187
312
  args.each do |arg|
188
- @@dates << arg if @@dates.index(arg).nil?
313
+ defined_attributes[arg].type = :date
189
314
  end
190
- # @@dates = args
191
- # puts 'dates=' + @@dates.inspect
192
315
  end
193
316
 
194
- @@booleans = []
195
317
  def self.are_booleans(*args)
196
318
  args.each do |arg|
197
- @@booleans << arg if @@booleans.index(arg).nil?
319
+ defined_attributes[arg].type = :boolean
198
320
  end
199
321
  end
200
322
 
@@ -207,14 +329,17 @@ module SimpleRecord
207
329
  end
208
330
  end
209
331
 
210
- @@belongs_to_map = {}
211
332
  # One belongs_to association per call. Call multiple times if there are more than one.
212
333
  #
213
334
  # This method will also create an {association)_id method that will return the ID of the foreign object
214
335
  # without actually materializing it.
215
336
  def self.belongs_to(association_id, options = {})
216
- @@belongs_to_map[association_id] = options
337
+ attribute = SimpleRecord::Base::Attribute.new(:belongs_to)
338
+ defined_attributes[association_id] = attribute
339
+ attribute.options = options
340
+ #@@belongs_to_map[association_id] = options
217
341
  arg = association_id
342
+ arg_s = arg.to_s
218
343
  arg_id = arg.to_s + '_id'
219
344
 
220
345
  # todo: should also handle foreign_key http://74.125.95.132/search?q=cache:KqLkxuXiBBQJ:wiki.rubyonrails.org/rails/show/belongs_to+rails+belongs_to&hl=en&ct=clnk&cd=1&gl=us
@@ -224,7 +349,8 @@ module SimpleRecord
224
349
 
225
350
  # Define reader method
226
351
  send(:define_method, arg) do
227
- options2 = @@belongs_to_map[arg]
352
+ attribute = defined_attributes[arg]
353
+ options2 = attribute.options # @@belongs_to_map[arg]
228
354
  class_name = options2[:class_name] || arg.to_s[0...1].capitalize + arg.to_s[1...arg.to_s.length]
229
355
 
230
356
  # Camelize classnames with underscores (ie my_model.rb --> MyModel)
@@ -243,7 +369,7 @@ module SimpleRecord
243
369
  # puts 'belongs_to incache=' + ret.inspect
244
370
  end
245
371
  if ret.nil?
246
- to_eval = "#{class_name}.find(@attributes['#{arg_id}'][0], :auto_load=>true)"
372
+ to_eval = "#{class_name}.find(@attributes['#{arg_id}'][0])"
247
373
  # puts 'to eval=' + to_eval
248
374
  begin
249
375
  ret = eval(to_eval) # (defined? #{arg}_id)
@@ -261,26 +387,28 @@ module SimpleRecord
261
387
  return ret
262
388
  end
263
389
 
264
- # Define reader ID method
265
- send(:define_method, arg_id) do
266
- if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
267
- return @attributes[arg_id][0]
268
- end
269
- return nil
270
- end
271
-
272
390
 
273
391
  # Define writer method
274
392
  send(:define_method, arg.to_s + "=") do |value|
275
393
  arg_id = arg.to_s + '_id'
276
394
  if value.nil?
395
+ make_dirty(arg_id, nil)
277
396
  self[arg_id]=nil unless self[arg_id].nil? # if it went from something to nil, then we have to remember and remove attribute on save
278
397
  else
398
+ make_dirty(arg_id, value.id)
279
399
  self[arg_id]=value.id
280
400
  end
281
401
  end
282
402
 
283
403
 
404
+ # Define ID reader method for reading the associated objects id without getting the entire object
405
+ send(:define_method, arg_id) do
406
+ if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
407
+ return @attributes[arg_id][0]
408
+ end
409
+ return nil
410
+ end
411
+
284
412
  # Define writer method for setting the _id directly without the associated object
285
413
  send(:define_method, arg_id + "=") do |value|
286
414
  if value.nil?
@@ -318,27 +446,8 @@ module SimpleRecord
318
446
 
319
447
  end
320
448
 
321
- has_attributes :created, :updated
322
- before_create :set_created, :set_updated
323
- before_update :set_updated
324
- are_dates :created, :updated
325
-
326
- def set_created
327
- # puts 'SETTING CREATED'
328
- # @created = DateTime.now
329
- self[:created] = DateTime.now
330
- # @tester = 'some test value'
331
- # self[:tester] = 'some test value'
332
- end
333
-
334
- def set_updated
335
- # puts 'SETTING UPDATED'
336
- # @updated = DateTime.now
337
- self[:updated] = DateTime.now
338
- # @tester = 'some test value updated'
339
- end
340
-
341
449
  def initialize(*params)
450
+
342
451
  if params[0]
343
452
  #we have to handle the virtuals. Right now, this assumes that all parameters are passed from inside an array
344
453
  #this is the usually the case when the parameters are passed passed via POST and obtained from the params array
@@ -353,6 +462,34 @@ module SimpleRecord
353
462
  super()
354
463
  end
355
464
  @errors=SimpleRecord_errors.new
465
+ @dirty = {}
466
+
467
+
468
+ end
469
+
470
+ def clear_errors
471
+ @errors=SimpleRecord_errors.new
472
+ end
473
+
474
+ def []=(attribute, values)
475
+ @dirty[attribute] = get_attribute(attribute)
476
+ super
477
+ end
478
+
479
+
480
+ def set_created
481
+ # puts 'SETTING CREATED'
482
+ # @created = DateTime.now
483
+ self[:created] = DateTime.now
484
+ # @tester = 'some test value'
485
+ # self[:tester] = 'some test value'
486
+ end
487
+
488
+ def set_updated
489
+ # puts 'SETTING UPDATED'
490
+ # @updated = DateTime.now
491
+ self[:updated] = DateTime.now
492
+ # @tester = 'some test value updated'
356
493
  end
357
494
 
358
495
 
@@ -399,19 +536,27 @@ module SimpleRecord
399
536
 
400
537
  @create_domain_called = false
401
538
 
402
- def save(*params)
539
+ # Options:
540
+ # - :except => Array of attributes to NOT save
541
+ # - :dirty => true - Will only store attributes that were modified
542
+ #
543
+ def save(options={})
403
544
  # puts 'SAVING: ' + self.inspect
545
+ clear_errors
404
546
  is_create = self[:id].nil?
405
- ok = pre_save(*params)
547
+ ok = pre_save(options)
406
548
  if ok
407
549
  begin
408
550
  # puts 'is frozen? ' + self.frozen?.to_s + ' - ' + self.inspect
409
- to_delete = get_atts_to_delete
410
- if super(*params)
551
+ if options[:dirty] # Only used in simple_record right now
552
+ options[:dirty_atts] = @dirty
553
+ end
554
+ to_delete = get_atts_to_delete # todo: this should use the @dirty hash now
555
+ if super(options)
411
556
  # puts 'SAVED super'
412
557
  self.class.cache_results(self)
413
558
  delete_niled(to_delete)
414
- if run_after_save && is_create ? run_after_create : run_after_update
559
+ if is_create ? run_after_create : run_after_update && run_after_save
415
560
  return true
416
561
  else
417
562
  #I thought about calling destroy here, but rails doesn't behave that way, so neither will I
@@ -425,7 +570,7 @@ module SimpleRecord
425
570
  if (domain_ok($!))
426
571
  if !@create_domain_called
427
572
  @create_domain_called = true
428
- save(*params)
573
+ save(options)
429
574
  else
430
575
  raise $!
431
576
  end
@@ -440,45 +585,46 @@ module SimpleRecord
440
585
  end
441
586
 
442
587
  def pad_and_offset_ints_to_sdb()
443
- if !@@ints.nil?
444
- for i in @@ints
588
+
589
+ defined_attributes_local.each_pair do |name, att_meta|
445
590
  # puts 'int encoding: ' + i.to_s
446
- if !self[i.to_s].nil?
591
+ if att_meta.type == :int && !self[name.to_s].nil?
447
592
  # puts 'before: ' + self[i.to_s].inspect
448
- # puts @attributes.inspect
449
- # puts @attributes[i.to_s].inspect
450
- arr = @attributes[i.to_s]
451
- arr.collect!{ |x| self.class.pad_and_offset(x) }
452
- @attributes[i.to_s] = arr
593
+ # puts @attributes.inspect
594
+ # puts @attributes[i.to_s].inspect
595
+ arr = @attributes[name.to_s]
596
+ arr.collect!{ |x| self.class.pad_and_offset(x) }
597
+ @attributes[name.to_s] = arr
453
598
  # puts 'after: ' + @attributes[i.to_s].inspect
454
- else
455
- # puts 'was nil'
456
- end
457
599
  end
458
600
  end
459
601
  end
460
602
 
461
603
  def convert_dates_to_sdb()
462
- if !@@dates.nil?
463
- for i in @@dates
604
+
605
+ defined_attributes_local.each_pair do |name, att_meta|
464
606
  # puts 'int encoding: ' + i.to_s
465
- if !self[i.to_s].nil?
607
+ if att_meta.type == :date && !self[name.to_s].nil?
466
608
  # puts 'before: ' + self[i.to_s].inspect
467
- # puts @attributes.inspect
468
- # puts @attributes[i.to_s].inspect
469
- arr = @attributes[i.to_s]
470
- #puts 'padding date=' + i.to_s
471
- arr.collect!{ |x| self.class.pad_and_offset(x) }
472
- @attributes[i.to_s] = arr
609
+ # puts @attributes.inspect
610
+ # puts @attributes[i.to_s].inspect
611
+ arr = @attributes[name.to_s]
612
+ #puts 'padding date=' + i.to_s
613
+ arr.collect!{ |x| self.class.pad_and_offset(x) }
614
+ @attributes[name.to_s] = arr
473
615
  # puts 'after: ' + @attributes[i.to_s].inspect
474
- else
475
- # puts 'was nil'
476
- end
616
+ else
617
+ # puts 'was nil'
477
618
  end
478
619
  end
479
620
  end
480
621
 
481
- def pre_save(*params)
622
+ def pre_save(options)
623
+
624
+ is_create = self[:id].nil?
625
+ ok = run_before_validation && is_create ? run_before_validation_on_create : run_before_validation_on_update
626
+ return false unless ok
627
+
482
628
  if respond_to?('validate')
483
629
  validate
484
630
  # puts 'AFTER VALIDATIONS, ERRORS=' + errors.inspect
@@ -488,7 +634,9 @@ module SimpleRecord
488
634
  end
489
635
  end
490
636
 
491
- is_create = self[:id].nil?
637
+ ok = run_after_validation && is_create ? run_after_validation_on_create : run_after_validation_on_update
638
+ return false unless ok
639
+
492
640
  ok = respond_to?('before_save') ? before_save : true
493
641
  if ok
494
642
  if is_create && respond_to?('before_create')
@@ -518,6 +666,7 @@ module SimpleRecord
518
666
  end
519
667
 
520
668
  def get_atts_to_delete
669
+ # todo: this should use the @dirty hash now
521
670
  to_delete = []
522
671
  @attributes.each do |key, value|
523
672
  # puts 'value=' + value.inspect
@@ -530,12 +679,12 @@ module SimpleRecord
530
679
 
531
680
  # Run pre_save on each object, then runs batch_put_attributes
532
681
  # Returns
533
- def self.batch_save(objects)
682
+ def self.batch_save(objects, options={})
534
683
  results = []
535
684
  to_save = []
536
685
  if objects && objects.size > 0
537
686
  objects.each do |o|
538
- ok = o.pre_save
687
+ ok = o.pre_save(options)
539
688
  raise "Pre save failed on object [" + o.inspect + "]" if !ok
540
689
  results << ok
541
690
  next if !ok
@@ -563,51 +712,14 @@ module SimpleRecord
563
712
  end
564
713
 
565
714
  def un_offset_if_int(arg, x)
566
- if !@@ints.nil?
567
- for i in @@ints
568
- # puts 'unpadding: ' + i.to_s
569
- # unpad and unoffset
570
- if i == arg
571
- # puts 'unoffsetting ' + x.to_s
572
- x = un_offset_int(x)
573
- end
574
- end
575
- end
576
- if !@@dates.nil?
577
- for d in @@dates
578
- # puts 'converting created: ' + self['created'].inspect
579
- if d == arg
580
- x = to_date(x)
581
- end
582
- # if !self[d].nil?
583
- # self[d].collect!{ |d2|
584
- # if d2.is_a?(String)
585
- # DateTime.parse(d2)
586
- # else
587
- # d2
588
- # end
589
- # }
590
- # end
591
- # puts 'after=' + self['created'].inspect
592
- end
593
- end
594
- if !@@booleans.nil?
595
- for b in @@booleans
596
- # puts 'converting created: ' + self['created'].inspect
597
- if b == arg
598
- x = to_bool(x)
599
- end
600
- # if !self[d].nil?
601
- # self[d].collect!{ |d2|
602
- # if d2.is_a?(String)
603
- # DateTime.parse(d2)
604
- # else
605
- # d2
606
- # end
607
- # }
608
- # end
609
- # puts 'after=' + self['created'].inspect
610
- end
715
+ att_meta = defined_attributes_local[arg]
716
+ # puts 'int encoding: ' + i.to_s
717
+ if att_meta.type == :int
718
+ x = un_offset_int(x)
719
+ elsif att_meta.type == :date
720
+ x = to_date(x)
721
+ elsif att_meta.type == :boolean
722
+ x = to_bool(x)
611
723
  end
612
724
  x
613
725
  end
@@ -659,12 +771,9 @@ module SimpleRecord
659
771
  end
660
772
 
661
773
  def unpad_self
662
- if !@@ints.nil?
663
- for i in @@ints
664
- # puts 'unpadding: ' + i.to_s
665
- # unpad and unoffset
666
-
667
- unpad(i, @attributes)
774
+ defined_attributes_local.each_pair do |name, att_meta|
775
+ if att_meta.type == :int
776
+ unpad(name, @attributes)
668
777
  end
669
778
  end
670
779
  end
@@ -746,9 +855,9 @@ This is done on getters now
746
855
 
747
856
  # Pad and Offset number attributes
748
857
  options = params[1]
749
- # puts 'options=' + options.inspect
858
+ #puts 'options=' + options.inspect
750
859
  convert_condition_params(options)
751
- # puts 'after collect=' + options.inspect
860
+ #puts 'after collect=' + options.inspect
752
861
 
753
862
  results = all ? [] : nil
754
863
  begin
@@ -842,6 +951,26 @@ This is done on getters now
842
951
  return @@domain_prefix + self.class.name.tableize
843
952
  end
844
953
 
954
+ def changed
955
+ return @dirty.keys
956
+ end
957
+
958
+ def changed?
959
+ return @dirty.size > 0
960
+ end
961
+
962
+ def changes
963
+ ret = {}
964
+ #puts 'in CHANGES=' + @dirty.inspect
965
+ @dirty.each_pair {|key, value| ret[key] = [value, get_attribute(key)]}
966
+ return ret
967
+ end
968
+
969
+ def mark_as_old
970
+ super
971
+ @dirty = {}
972
+ end
973
+
845
974
  end
846
975
 
847
976
  class SimpleRecord_errors
@@ -950,3 +1079,4 @@ This is done on getters now
950
1079
 
951
1080
  end
952
1081
  end
1082
+
@@ -1,6 +1,34 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
2
+ require 'my_model'
2
3
 
3
4
  class MyChildModel < SimpleRecord::Base
4
5
  belongs_to :my_model
5
- has_attributes :name
6
- end
6
+ has_attributes :name, :child_attr
7
+
8
+ end
9
+
10
+
11
+ =begin
12
+
13
+
14
+ puts 'word'
15
+
16
+ mm = MyModel.new
17
+ puts 'word2'
18
+
19
+ mcm = MyChildModel.new
20
+
21
+ puts 'mcm instance methods=' + MyChildModel.instance_methods(true).inspect
22
+ #puts 'mcm=' + mcm.instance_methods(false)
23
+ puts 'mcm class vars = ' + mcm.class.class_variables.inspect
24
+ puts mcm.class == MyChildModel
25
+ puts 'saved? ' + mm.save.to_s
26
+ puts mm.errors.inspect
27
+
28
+ puts "mm attributes=" + MyModel.defined_attributes.inspect
29
+ puts "mcm attributes=" + MyChildModel.defined_attributes.inspect
30
+
31
+ mcm2 = MyChildModel.new
32
+ puts "mcm2 attributes=" + MyChildModel.defined_attributes.inspect
33
+
34
+ =end
data/test/my_model.rb CHANGED
@@ -2,10 +2,27 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
2
2
 
3
3
  class MyModel < SimpleRecord::Base
4
4
 
5
- has_attributes :name
5
+ has_attributes :name, :nickname
6
6
  has_ints :age
7
7
  has_booleans :cool
8
- has_dates :created, :updated, :birthday
8
+ has_dates :birthday
9
9
 
10
10
 
11
+ #callbacks
12
+ before_create :set_nickname
13
+
14
+ def set_nickname
15
+ self.nickname = name if self.nickname.blank?
16
+ end
17
+
18
+ def validate
19
+ errors.add("name", "can't be empty.") if name.blank?
20
+ end
21
+
22
+
23
+
24
+ def atts
25
+ @@attributes
26
+ end
27
+
11
28
  end
@@ -24,15 +24,27 @@ class TestSimpleRecord < Test::Unit::TestCase
24
24
  mm.age = 32
25
25
  mm.cool = true
26
26
  mm.save
27
+
28
+ assert !mm.created.nil?
29
+ assert !mm.updated.nil?
30
+ assert !mm.id.nil?
31
+ assert mm.age == 32
32
+ assert mm.cool = true
33
+ assert mm.name = "Travis"
34
+
27
35
  id = mm.id
28
36
  puts 'id=' + id.to_s
29
37
  # Get the object back
30
38
  mm2 = MyModel.find(id)
31
- puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
32
- puts mm2.cool.class.name
39
+ #puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
40
+ #puts mm2.cool.class.name
33
41
  assert mm2.id == mm.id
34
42
  assert mm2.age == mm.age
35
43
  assert mm2.cool == mm.cool
44
+ assert mm2.age == 32
45
+ assert mm2.cool = true
46
+ assert mm2.name = "Travis"
47
+ assert mm2.created.is_a? DateTime
36
48
  end
37
49
 
38
50
  def test_bad_query
@@ -83,39 +95,85 @@ class TestSimpleRecord < Test::Unit::TestCase
83
95
  end
84
96
 
85
97
  def test_callbacks
86
- # these DO NOT work right now, all objects get all callbacks
87
- # I tried like this, seem to be getting somewhere.
88
- #
89
- # class << self;
90
- # @@callbacks.each do |callback|
91
- # #we first have to make an initialized array for each of the callbacks, to prevent problems if they are not called
92
- # puts 'setting callback ' + callback.to_s + ' on ' + self.inspect
93
- # eval %{
94
- #
95
- # # add the methods to the class
96
- # def #{callback}(*args)
97
- # args.each do |arg|
98
- # cb_names = self.instance_variable_get(:@#{callback}_names)
99
- # cb_names = [] if cb_names.nil?
100
- # cb_names << arg.to_s if cb_names.index(arg.to_s).nil?
101
- # self.instance_variable_set(:@#{callback}_names, cb_names)
102
- # end
103
- ## asdf @@#{callback}_names=args.map{|arg| arg.to_s}
104
- # end
98
+
99
+
100
+ mm = MyModel.new
101
+ assert !mm.save
102
+ assert mm.errors.count == 1 # name is required
103
+
104
+ # test queued callback before_create
105
+ mm.name = "Travis"
106
+ assert mm.save
107
+ # now nickname should be set on before_create
108
+ assert mm.nickname == mm.name
109
+
110
+ mm2 = MyModel.find(mm.id)
111
+ assert mm2.nickname = mm.nickname
112
+ assert mm2.name = mm.name
113
+
114
+
115
+
116
+ end
117
+
118
+ def test_dirty
119
+ mm = MyModel.new
120
+ mm.name = "Travis"
121
+ mm.age = 32
122
+ mm.cool = true
123
+ mm.save
124
+ id = mm.id
125
+ puts 'id=' + id.to_s
126
+ # Get the object back
127
+ mm2 = MyModel.find(id)
128
+ puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
129
+ assert mm2.id == mm.id
130
+ assert mm2.age == mm.age
131
+ assert mm2.cool == mm.cool
132
+
133
+ mm2.name = "Travis 2"
134
+ mm2.save(:dirty=>true)
135
+
136
+ # todo: how do we assert this?
137
+
138
+ end
139
+
140
+ # http://api.rubyonrails.org/classes/ActiveRecord/Dirty.html#M002136
141
+ def test_changed
142
+ mm = MyModel.new
143
+ mm.name = "Travis"
144
+ mm.age = 32
145
+ mm.cool = true
146
+ mm.save
147
+
148
+ puts 'changed?=' + mm.changed?.to_s
149
+ assert !mm.changed?
150
+ assert mm.changed.size == 0
151
+ assert mm.changes.size == 0
152
+ assert !mm.name_changed?
153
+
154
+ mm.name = "Jim"
155
+ assert mm.changed?
156
+ assert mm.changed.size == 1
157
+ assert mm.changed[0] == "name"
158
+
159
+ assert mm.changes.size == 1
160
+ puts 'CHANGES=' + mm.changes.inspect
161
+ assert mm.changes["name"][0] == "Travis"
162
+ assert mm.changes["name"][1] == "Jim"
163
+
164
+ assert mm.name_changed?
165
+ assert mm.name_was == "Travis"
166
+ assert mm.name_change[0] == "Travis"
167
+ assert mm.name_change[1] == "Jim"
168
+
169
+ end
170
+
171
+ def test_attributes_correct
172
+
173
+ #MyModel.defined_attributes.each do |a|
105
174
  #
106
- # # now we run the methods in the callback array for this class
107
- #send :define_method, "run_#{callback}" do
108
- ## def run_#{callback}
109
- # cb_names = self.instance_variable_get(:@#{callback}_names)
110
- # cb_names.each { |name|
111
- # unless eval(name)
112
- # return false
113
- # end
114
- # }
115
- # return true
116
- # end
117
- # }
118
- # end
119
- # end
175
+ #end
176
+ #MyChildModel.defined_attributes.inspect
177
+
120
178
  end
121
179
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appoxy-simple_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.23
4
+ version: 1.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Reeder
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-07-15 00:00:00 -07:00
13
+ date: 2009-07-30 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -27,6 +27,7 @@ files:
27
27
  - README.markdown
28
28
  has_rdoc: true
29
29
  homepage: http://github.com/appoxy/simple_record/
30
+ licenses:
30
31
  post_install_message:
31
32
  rdoc_options:
32
33
  - --charset=UTF-8
@@ -47,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
48
  requirements: []
48
49
 
49
50
  rubyforge_project:
50
- rubygems_version: 1.2.0
51
+ rubygems_version: 1.3.5
51
52
  signing_key:
52
53
  specification_version: 2
53
54
  summary: Drop in replacement for ActiveRecord to Amazon SimpleDB instead.