doodle 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2008 Sean O'Halpin <monkeymind.textdriven.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,3 +1,12 @@
1
+ == 0.1.4 / 2008-05-06
2
+ - Features:
3
+ - keyed collections - see http://doodle.rubyforge.org/#keyed_collections for details
4
+ - specialized Attribute classes in #has - see
5
+ spec/specialized_attribute_class_spec.rb for example
6
+
7
+ - Bug fixes:
8
+ - fixed bug when using a collect generated method with a type but no arguments
9
+
1
10
  == 0.1.3 / 2008-05-01
2
11
  - really avoid wierd interaction with ActiveRecord this time
3
12
  - also, managed to get rid of crufty reliance on inspect and found
@@ -1,31 +1,33 @@
1
+ COPYING
2
+ CREDITS
1
3
  History.txt
2
4
  License.txt
3
5
  Manifest.txt
6
+ PostInstall.txt
4
7
  README.txt
5
- CREDITS
6
8
  Rakefile
7
9
  config/hoe.rb
8
10
  config/requirements.rb
9
- examples/smtp_tls.rb
10
- examples/example-01.rdoc
11
- examples/profile-options.rb
12
11
  examples/doodle-errors.rb
13
12
  examples/event-location.rb
14
- examples/parent.rb
13
+ examples/example-01.rb
14
+ examples/example-01.rdoc
15
15
  examples/example-02.rb
16
16
  examples/example-02.rdoc
17
- examples/example-01.rb
17
+ examples/mail-datatypes.rb
18
18
  examples/mail.rb
19
- examples/yaml-example2.rb
20
- examples/yaml-example.rb
19
+ examples/parent.rb
20
+ examples/profile-options.rb
21
+ examples/smtp_tls.rb
21
22
  examples/test-datatypes.rb
22
- examples/mail-datatypes.rb
23
+ examples/yaml-example.rb
24
+ examples/yaml-example2.rb
23
25
  lib/doodle.rb
24
- lib/molic_orderedhash.rb
25
26
  lib/doodle/datatypes.rb
26
27
  lib/doodle/rfc822.rb
27
28
  lib/doodle/utils.rb
28
29
  lib/doodle/version.rb
30
+ lib/molic_orderedhash.rb
29
31
  log/debug.log
30
32
  script/console
31
33
  script/destroy
@@ -36,6 +38,7 @@ spec/arg_order_spec.rb
36
38
  spec/attributes_spec.rb
37
39
  spec/bugs_spec.rb
38
40
  spec/class_spec.rb
41
+ spec/class_validation_spec.rb
39
42
  spec/class_var_spec.rb
40
43
  spec/collector_spec.rb
41
44
  spec/conversion_spec.rb
@@ -45,6 +48,7 @@ spec/doodle_spec.rb
45
48
  spec/extra_args_spec.rb
46
49
  spec/factory_spec.rb
47
50
  spec/flatten_first_level_spec.rb
51
+ spec/inheritance_spec.rb
48
52
  spec/init_spec.rb
49
53
  spec/new_doodle_spec.rb
50
54
  spec/required_spec.rb
@@ -52,10 +56,10 @@ spec/serialization_spec.rb
52
56
  spec/singleton_spec.rb
53
57
  spec/spec.opts
54
58
  spec/spec_helper.rb
59
+ spec/specialized_attribute_class_spec.rb
55
60
  spec/superclass_spec.rb
56
- spec/validation_spec.rb
57
61
  spec/validation2_spec.rb
62
+ spec/validation_spec.rb
58
63
  tasks/deployment.rake
59
64
  tasks/environment.rake
60
65
  tasks/rspec.rake
61
- tasks/website.rake
@@ -0,0 +1 @@
1
+ For more information on doodle, see http://doodle.rubyforge.org
@@ -6,7 +6,6 @@ $:.unshift(File.dirname(__FILE__)) unless
6
6
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
7
7
 
8
8
  require 'molic_orderedhash' # todo[replace this with own (required functions only) version]
9
- #require 'bleak_house' if ENV['BLEAK_HOUSE']
10
9
 
11
10
  # require Ruby 1.8.6 or higher
12
11
  if RUBY_VERSION < '1.8.6'
@@ -57,19 +56,6 @@ class Doodle
57
56
  def snake_case(camel_cased_word)
58
57
  camel_cased_word.gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
59
58
  end
60
- # what kind of object are we dealing with?
61
- def doodle_category(obj)
62
- return :nil if obj.class == NilClass
63
- if obj.kind_of?(Module)
64
- if obj.ancestors.include?(obj)
65
- :class
66
- else
67
- :singleton_class
68
- end
69
- else
70
- :instance
71
- end
72
- end
73
59
  end
74
60
  end
75
61
 
@@ -125,22 +111,17 @@ class Doodle
125
111
 
126
112
  # parents returns the set of parent classes of an object
127
113
  def parents
128
- # if singleton class (e.g. class << [Ff]oo; self; end) then it has
129
- # no parents
130
- case Doodle::Utils.doodle_category(self)
131
- when :instance
132
- klass = self.class
133
- when :class
134
- klass = superclass
135
- when :singleton_class
136
- klass = nil
137
- end
138
- klasses = []
139
- until klass.nil? || klass == klass.superclass
140
- klasses << klass
141
- klass = klass.superclass
142
- end
143
- klasses
114
+ anc = if respond_to?(:ancestors)
115
+ if ancestors.include?(self)
116
+ ancestors[1..-1]
117
+ else
118
+ # singletons have no parents (they're orphans)
119
+ []
120
+ end
121
+ else
122
+ self.class.ancestors
123
+ end
124
+ anc.select{|x| x.kind_of?(Class)}
144
125
  end
145
126
 
146
127
  # need concepts of
@@ -164,6 +145,7 @@ class Doodle
164
145
  private :collect_inherited
165
146
  end
166
147
 
148
+ # = embrace
167
149
  # the intent of embrace is to provide a way to create directives
168
150
  # that affect all members of a class 'family' without having to
169
151
  # modify Module, Class or Object - in some ways, it's similar to Ara
@@ -286,6 +268,8 @@ class Doodle
286
268
  end
287
269
  end
288
270
 
271
+ #### ERRORS COLLECTION
272
+
289
273
  # where should I put this?
290
274
  def errors
291
275
  __doodle__.errors
@@ -308,6 +292,8 @@ class Doodle
308
292
  end
309
293
  end
310
294
 
295
+ #### ERRORS COLLECTION
296
+
311
297
  def _handle_inherited_hash(tf, method)
312
298
  if tf
313
299
  collect_inherited(method).inject(OrderedHash.new){ |hash, item|
@@ -330,6 +316,7 @@ class Doodle
330
316
  # - if tf == false, returns only those attributes defined in the current object/class
331
317
  def attributes(tf = true)
332
318
  results = _handle_inherited_hash(tf, :local_attributes)
319
+ # if an instance, include the singleton_class attributes
333
320
  if !kind_of?(Class) && singleton_class.respond_to?(:attributes)
334
321
  results = results.merge(singleton_class.attributes)
335
322
  end
@@ -402,8 +389,10 @@ class Doodle
402
389
  def getter_setter(name, *args, &block)
403
390
  name = name.to_sym
404
391
  if block_given? || args.size > 0
392
+ #!p [:getter_setter, :setter, name, *args]
405
393
  _setter(name, *args, &block)
406
394
  else
395
+ #!p [:getter_setter, :getter, name]
407
396
  _getter(name)
408
397
  end
409
398
  end
@@ -413,6 +402,7 @@ class Doodle
413
402
  def _getter(name, &block)
414
403
  ivar = "@#{name}"
415
404
  if instance_variable_defined?(ivar)
405
+ #!p [:_getter, name, ivar, instance_variable_get(ivar)]
416
406
  instance_variable_get(ivar)
417
407
  else
418
408
  # handle default
@@ -421,6 +411,7 @@ class Doodle
421
411
  att = lookup_attribute(name)
422
412
  # special case for class/singleton :init
423
413
  if att.init_defined?
414
+ #!p [:_setter, att.init]
424
415
  _setter(name, att.init)
425
416
  elsif att.default_defined?
426
417
  case att.default
@@ -441,17 +432,20 @@ class Doodle
441
432
 
442
433
  # set an attribute by name - apply validation if defined
443
434
  def _setter(name, *args, &block)
444
- #Doodle::Debug.d { [:_setter, name, args] }
435
+ ##DBG: Doodle::Debug.d { [:_setter, name, args] }
445
436
  ivar = "@#{name}"
446
437
  if block_given?
447
438
  args.unshift(DeferredBlock.new(block))
448
439
  end
449
440
  if att = lookup_attribute(name)
450
- #Doodle::Debug.d { [:_setter, name, args] }
441
+ ##DBG: Doodle::Debug.d { [:_setter, name, args] }
442
+ #!p [:_setter, :got_att, name, *args]
451
443
  v = instance_variable_set(ivar, att.validate(self, *args))
444
+ #!p [:_setter, :got_att, name, :value, v]
452
445
  #v = instance_variable_set(ivar, *args)
453
446
  else
454
- #Doodle::Debug.d { [:_setter, "no attribute"] }
447
+ #!p [:_setter, :no_att, name, *args]
448
+ ##DBG: Doodle::Debug.d { [:_setter, "no attribute"] }
455
449
  v = instance_variable_set(ivar, *args)
456
450
  end
457
451
  validate!(false)
@@ -491,37 +485,43 @@ class Doodle
491
485
  # convert a value according to conversion rules
492
486
  def convert(owner, *args)
493
487
  begin
494
- value = args.first
495
- if (converter = conversions[value.class])
496
- value = converter[*args]
497
- else
498
- # try to find nearest ancestor
499
- ancestors = value.class.ancestors
500
- matches = ancestors & conversions.keys
501
- indexed_matches = matches.map{ |x| ancestors.index(x)}
502
- if indexed_matches.size > 0
503
- converter_class = ancestors[indexed_matches.min]
504
- if converter = conversions[converter_class]
505
- value = converter[*args]
488
+ args = args.map do |value|
489
+ if (converter = conversions[value.class])
490
+ #p [:convert, :using, value.class]
491
+ value = converter[*args]
492
+ else
493
+ # try to find nearest ancestor
494
+ ancestors = value.class.ancestors
495
+ matches = ancestors & conversions.keys
496
+ indexed_matches = matches.map{ |x| ancestors.index(x)}
497
+ if indexed_matches.size > 0
498
+ converter_class = ancestors[indexed_matches.min]
499
+ if converter = conversions[converter_class]
500
+ #p [:convert, :using, converter_class]
501
+ value = converter[*args]
502
+ end
506
503
  end
507
504
  end
505
+ value
508
506
  end
509
507
  rescue Exception => e
510
508
  owner.handle_error name, ConversionError, e.to_s, [caller[-1]]
511
509
  end
512
- value
510
+ if args.size > 1
511
+ args
512
+ else
513
+ args.first
514
+ end
513
515
  end
514
516
 
515
517
  # validate that args meet rules defined with +must+
516
518
  def validate(owner, *args)
517
- #Doodle::Debug.d { [:validate, self, :owner, owner, :args, args ] }
518
- # if I bypass convert here, the AR inspect wierdness stops
519
- # so what is going on?
520
- #return args.first
519
+ ##DBG: Doodle::Debug.d { [:validate, self, :owner, owner, :args, args ] }
520
+ #!p [:validate, :before_conversion, args]
521
521
  value = convert(owner, *args)
522
- #return args.first
522
+ #!p [:validate, :after_conversion, args, :becomes, value]
523
523
  validations.each do |v|
524
- #Doodle::Debug.d { [:validate, self, v, args, value] }
524
+ ##DBG: Doodle::Debug.d { [:validate, self, v, args, value] }
525
525
  if !v.block[value]
526
526
  owner.handle_error name, ValidationError, "#{ name } must #{ v.message } - got #{ value.class }(#{ value.inspect })", [caller[-1]]
527
527
  end
@@ -547,24 +547,50 @@ class Doodle
547
547
  end
548
548
  private :define_getter_setter
549
549
 
550
- # define a collector
550
+ # define a collector for appendable collections
551
551
  # - collection should provide a :<< method
552
- def define_collector(collection, name, klass = nil, &block)
552
+ def define_appendable_collector(collection, name, klass = nil, &block)
553
553
  # need to use string eval because passing block
554
554
  if klass.nil?
555
555
  sc_eval("def #{name}(*args, &block); args.unshift(block) if block_given?; #{collection}.<<(*args); end", __FILE__, __LINE__)
556
556
  else
557
- sc_eval("def #{name}(*args, &block);
558
- if args.all?{|x| x.kind_of?(#{klass})}
557
+ sc_eval("def #{name}(*args, &block)
558
+ if args.size > 0 and args.all?{|x| x.kind_of?(#{klass})}
559
559
  #{collection}.<<(*args)
560
560
  else
561
- #{collection} << #{klass}.new(*args, &block);
561
+ #{collection} << #{klass}.new(*args, &block)
562
562
  end
563
563
  end", __FILE__, __LINE__)
564
564
  end
565
565
  end
566
- private :define_collector
566
+ private :define_appendable_collector
567
567
 
568
+ # define a collector for keyed collections
569
+ # - collection should provide a :[] method
570
+ def define_keyed_collector(collection, name, key_method, klass = nil, &block)
571
+ #DBG: Doodle::Debug.d { [:define_keyed_collector, collection, name, key_method, klass]}
572
+ # need to use string eval because passing block
573
+ if klass.nil?
574
+ sc_eval("def #{name}(*args, &block)
575
+ args.each do |arg|
576
+ #{collection}[arg.send(:#{key_method})] = arg
577
+ end
578
+ end", __FILE__, __LINE__)
579
+ else
580
+ sc_eval("def #{name}(*args, &block)
581
+ if args.size > 0 and args.all?{|x| x.kind_of?(#{klass})}
582
+ args.each do |arg|
583
+ #{collection}[arg.send(:#{key_method})] = arg
584
+ end
585
+ else
586
+ obj = #{klass}.new(*args, &block)
587
+ #{collection}[obj.send(:#{key_method})] = obj
588
+ end
589
+ end", __FILE__, __LINE__)
590
+ end
591
+ end
592
+ private :define_keyed_collector
593
+
568
594
  # +has+ is an extended +attr_accessor+
569
595
  #
570
596
  # simple usage - just like +attr_accessor+:
@@ -588,19 +614,37 @@ class Doodle
588
614
  # end
589
615
  #
590
616
  def has(*args, &block)
591
- Doodle::Debug.d { [:has, self, self.class, args] }
592
- name = args.shift.to_sym
617
+ #DBG: Doodle::Debug.d { [:has, self, self.class, args] }
593
618
  # d { [:has2, name, args] }
594
619
  key_values, positional_args = args.partition{ |x| x.kind_of?(Hash)}
595
- handle_error name, ArgumentError, "Too many arguments" if positional_args.size > 0
596
- params = { :name => name }
620
+ if positional_args.size > 0
621
+ name = positional_args.shift.to_sym
622
+ params = { :name => name }
623
+ else
624
+ params = { }
625
+ end
597
626
  params = key_values.inject(params){ |acc, item| acc.merge(item)}
627
+ #DBG: Doodle::Debug.d { [:has, self, self.class, params] }
628
+ if !params.key?(:name)
629
+ handle_error name, ArgumentError, "Must have a name"
630
+ else
631
+ name = params[:name].to_sym
632
+ end
633
+ handle_error name, ArgumentError, "Too many arguments" if positional_args.size > 0
598
634
 
599
635
  # don't pass collector params through to Attribute
600
636
  collector_klass = nil
637
+ # fixme: this should be in specialized attribute class
638
+ # (and also distinction between appendable and keyed collections
601
639
  if collector = params.delete(:collect)
602
640
  if !params.key?(:init)
603
- params[:init] = []
641
+ if params.key?(:key)
642
+ #!p [:defining, :hash, name]
643
+ params[:init] = { }
644
+ else
645
+ #!p [:defining, :array, name]
646
+ params[:init] = []
647
+ end
604
648
  end
605
649
  if collector.kind_of?(Hash)
606
650
  collector_name, collector_klass = collector.to_a[0]
@@ -612,23 +656,40 @@ class Doodle
612
656
  if collector_klass !~ /^[A-Z]/
613
657
  collector_klass = nil
614
658
  end
659
+ #!p [:collector_klass, collector_klass, params[:init]]
660
+ end
661
+ if key = params.delete(:key)
662
+ define_keyed_collector name, collector_name, key, collector_klass
663
+ else
664
+ define_appendable_collector name, collector_name, collector_klass
615
665
  end
616
- define_collector name, collector_name, collector_klass
617
666
  end
667
+
668
+ # get specialized attribute class or use default
669
+ attribute_class = params.delete(:using) || Attribute
618
670
 
619
671
  # define getter setter before setting up attribute
620
672
  define_getter_setter name, *args, &block
621
- local_attributes[name] = attribute = Attribute.new(params, &block)
673
+ local_attributes[name] = attribute = attribute_class.new(params, &block)
674
+
622
675
  # if a collector has been defined and has a specific class, then you can pass in an array of hashes
623
676
  if collector_klass
677
+ # fixme: this should be in specialized attribute class
678
+ #!p [:collector_klass2, collector_klass, params[:init]]
624
679
  attribute.instance_eval {
680
+ # applying map to hashes returns an array, so avoid that by simply passing it through
681
+ from Hash do |hash|
682
+ hash
683
+ end
625
684
  from Enumerable do |enum|
626
685
  if !collector_klass.kind_of?(Class)
627
686
  tmp_klass = self.class.const_get(collector_klass)
628
687
  else
629
688
  tmp_klass = collector_klass
630
689
  end
631
- enum.map{|x|
690
+ #!p [:enumerating, name, enum]
691
+ results = enum.map{|x|
692
+ #!p [:enumerating, x]
632
693
  if x.kind_of?(tmp_klass)
633
694
  x
634
695
  elsif tmp_klass.conversions.key?(x.class)
@@ -637,6 +698,16 @@ class Doodle
637
698
  tmp_klass.new(x)
638
699
  end
639
700
  }
701
+ #!p [:enumerating, :results, results]
702
+ # fixme: this is all getting a bit too specific to arrays and hashes
703
+ # figure out a way to do this with specialized Doodle::Attribute?
704
+ if !key.nil?
705
+ results = results.inject({ }) do |hash, result|
706
+ hash[result.send(key)] = result
707
+ hash
708
+ end
709
+ end
710
+ results
640
711
  end
641
712
  }
642
713
  end
@@ -647,7 +718,7 @@ class Doodle
647
718
  def arg_order(*args)
648
719
  if args.size > 0
649
720
  begin
650
- args.uniq!
721
+ args = args.uniq
651
722
  args.each do |x|
652
723
  handle_error :arg_order, ArgumentError, "#{x} not a Symbol" if !(x.class <= Symbol)
653
724
  handle_error :arg_order, NameError, "#{x} not an attribute name" if !attributes.keys.include?(x)
@@ -662,7 +733,8 @@ class Doodle
662
733
  end
663
734
 
664
735
  def get_init_values(tf = true)
665
- attributes(tf).select{|n, a| a.init_defined? }.inject({}) {|hash, (n, a)|
736
+ attributes(tf).select{|n, a| a.init_defined? }.inject({}) {|hash, (n, a)|
737
+ #!p [:get_init_values, a.init]
666
738
  hash[n] = begin
667
739
  case a.init
668
740
  when NilClass, TrueClass, FalseClass, Fixnum
@@ -675,7 +747,8 @@ class Doodle
675
747
  rescue Exception => e
676
748
  a.init
677
749
  end
678
- ; hash }
750
+ hash
751
+ }
679
752
  end
680
753
  private :get_init_values
681
754
 
@@ -688,22 +761,22 @@ class Doodle
688
761
  # validate this object by applying all validations in sequence
689
762
  # - if all == true, validate all attributes, e.g. when loaded from YAML, else validate at object level only
690
763
  def validate!(all = true)
691
- #Doodle::Debug.d { [:validate!, all, caller] }
764
+ ##DBG: Doodle::Debug.d { [:validate!, all, caller] }
692
765
  if all
693
766
  clear_errors
694
767
  end
695
768
  if __doodle__.validation_on
696
769
  if self.class == Class
697
770
  attribs = class_attributes
698
- #Doodle::Debug.d { [:validate!, "using class_attributes", class_attributes] }
771
+ ##DBG: Doodle::Debug.d { [:validate!, "using class_attributes", class_attributes] }
699
772
  else
700
773
  attribs = attributes
701
- #Doodle::Debug.d { [:validate!, "using instance_attributes", attributes] }
774
+ ##DBG: Doodle::Debug.d { [:validate!, "using instance_attributes", attributes] }
702
775
  end
703
776
  attribs.each do |name, att|
704
777
  # treat default as special case
705
778
  if att.default_defined?
706
- #Doodle::Debug.d { [:validate!, "default_defined - breaking" ]}
779
+ ##DBG: Doodle::Debug.d { [:validate!, "default_defined - breaking" ]}
707
780
  break
708
781
  end
709
782
  ivar_name = "@#{att.name}"
@@ -712,7 +785,7 @@ class Doodle
712
785
  # validations are applied to raw instance variables
713
786
  # e.g. when loaded from YAML
714
787
  if all
715
- #Doodle::Debug.d { [:validate!, :sending, att.name, instance_variable_get(ivar_name) ] }
788
+ ##DBG: Doodle::Debug.d { [:validate!, :sending, att.name, instance_variable_get(ivar_name) ] }
716
789
  __send__("#{att.name}=", instance_variable_get(ivar_name))
717
790
  end
718
791
  elsif self.class != Class
@@ -721,9 +794,9 @@ class Doodle
721
794
  end
722
795
  # now apply instance level validations
723
796
 
724
- #Doodle::Debug.d { [:validate!, "validations", validations ]}
797
+ ##DBG: Doodle::Debug.d { [:validate!, "validations", validations ]}
725
798
  validations.each do |v|
726
- #Doodle::Debug.d { [:validate!, self, v ] }
799
+ ##DBG: Doodle::Debug.d { [:validate!, self, v ] }
727
800
  begin
728
801
  if !instance_eval(&v.block)
729
802
  handle_error self, ValidationError, "#{ self.class } must #{ v.message }", [caller[-1]]
@@ -756,31 +829,38 @@ class Doodle
756
829
  # after initialization (validate! is called if this method is
757
830
  # called after initialization)
758
831
  def initialize_from_hash(*args)
832
+ #!p [:initialize_from_hash, :args, *args]
759
833
  defer_validation do
760
834
  # hash initializer
761
835
  # separate into array of hashes of form [{:k1 => v1}, {:k2 => v2}] and positional args
762
836
  key_values, args = args.partition{ |x| x.kind_of?(Hash)}
763
- Doodle::Debug.d { [self.class, :initialize_from_hash, :key_values, key_values, :args, args] }
764
-
765
- # match up positional args with attribute names (from arg_order) using idiom to create hash from array of assocs
766
- arg_keywords = Hash[*(Utils.flatten_first_level(self.class.arg_order[0...args.size].zip(args)))]
837
+ #DBG: Doodle::Debug.d { [self.class, :initialize_from_hash, :key_values, key_values, :args, args] }
838
+ #!p [self.class, :initialize_from_hash, :key_values, key_values, :args, args]
767
839
 
768
840
  # set up initial values with ~clones~ of specified values (so not shared between instances)
769
841
  init_values = get_init_values
770
-
771
- # add to start of key_values array (so can be overridden by params)
772
- key_values.unshift(init_values)
842
+ #p [:init_values, init_values]
843
+
844
+ # match up positional args with attribute names (from arg_order) using idiom to create hash from array of assocs
845
+ arg_keywords = init_values.merge(Hash[*(Utils.flatten_first_level(self.class.arg_order[0...args.size].zip(args)))])
846
+ #p [self.class, :initialize_from_hash, :arg_keywords, arg_keywords]
773
847
 
774
848
  # merge all hash args into one
775
- key_values = key_values.inject(arg_keywords) { |hash, item| hash.merge(item)}
849
+ key_values = key_values.inject(arg_keywords) { |hash, item|
850
+ #p [self.class, :initialize_from_hash, :merge, hash, item]
851
+ hash.merge(item)
852
+ }
853
+ #p [self.class, :initialize_from_hash, :key_values2, key_values]
776
854
 
777
855
  # convert key names to symbols
778
856
  key_values = key_values.inject({}) {|h, (k, v)| h[k.to_sym] = v; h}
779
- Doodle::Debug.d { [self.class, :initialize_from_hash, :key_values2, key_values, :args2, args] }
857
+ #DBG: Doodle::Debug.d { [self.class, :initialize_from_hash, :key_values2, key_values, :args2, args] }
858
+ #p [self.class, :initialize_from_hash, :key_values3, key_values]
780
859
 
781
860
  # create attributes
782
861
  key_values.keys.each do |key|
783
- Doodle::Debug.d { [self.class, :initialize_from_hash, :setting, key, key_values[key]] }
862
+ #DBG: Doodle::Debug.d { [self.class, :initialize_from_hash, :setting, key, key_values[key]] }
863
+ #p [self.class, :initialize_from_hash, :setting, key, key_values[key]]
784
864
  if respond_to?(key)
785
865
  __send__(key, key_values[key])
786
866
  else