appoxy-simple_record 1.0.23 → 1.0.26

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/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.