@@ -381,15 +381,24 @@ def initialize(args={})
381381 lazy_initialize ( args ) unless args . empty?
382382 end
383383
384- # Access an element of the model by its name
385- # @param [Symbol] name
386- # @return [Model, Types::Base, Wrapper]
387- def []( name )
388- elt = @elements [ name ]
389- return elt unless elt . is_a? ( Proc )
390-
391- # Lazy element -> generate it
392- @elements [ name ] = elt . call
384+ # @overload [](name)
385+ # Access an element of the model by its name
386+ # @param [Symbol] name
387+ # @return [Model, Types::Base, Wrapper]
388+ # @overload [](idx)
389+ # Access an element of root element by its index. Root element must be a {Sequence} or {SequenceOf}.
390+ # @param [Integer] idx
391+ # @return [Model, Types::Base, Wrapper]
392+ def []( name_or_idx )
393+ case name_or_idx
394+ when Symbol
395+ elt = @elements [ name_or_idx ]
396+ return elt unless elt . is_a? ( Proc )
397+
398+ @elements [ name_or_idx ] = elt . call
399+ when Integer
400+ root [ name_or_idx ]
401+ end
393402 end
394403
395404 # Set value of element +name+. Element should be a {Types::Base}.
@@ -582,29 +591,37 @@ def by_name(name)
582591 private
583592
584593 def generate_root ( args )
585- opts = args . slice ( :explicit , :implicit , :optional , :class , :default , :constructed , :tag_value )
594+ opts = args . slice ( :name , : explicit, :implicit , :optional , :class , :default , :constructed , :tag_value )
586595 root = self . class . class_eval { @root }
587596 root_options = self . class . options || { }
588597 root_options . merge! ( opts )
598+ @root_name = args [ :name ] || root . name
589599 @root = generate_element ( root , root_options )
590- @root_name = root . name
591- @elements [ root . name ] = @root
600+ @elements [ @root_name ] = @root
592601 end
593602
594603 def generate_element ( elt , opts = { } )
595604 case elt
596605 when BaseElem
597606 generate_base_element ( elt , opts )
598607 when ModelElem
608+ opts [ :name ] ||= elt . name
599609 elt . klass . new ( opts )
600610 when WrapElem
601- wrapped = elt . element . is_a? ( ModelElem ) ? elt . element . klass : generate_element ( elt . element )
602- wrapper = Wrapper . new ( wrapped , elt . options . merge ( opts ) )
603- @elements [ elt . element . name ] = proc { wrapper . element }
604- wrapper
611+ generate_wrapper_element ( elt , opts )
605612 end
606613 end
607614
615+ def generate_wrapper_element ( elt , opts )
616+ wrapped = elt . element . is_a? ( ModelElem ) ? elt . element . klass : generate_element ( elt . element )
617+ options = elt . options . merge ( opts )
618+ options [ :name ] = elt . element . name if elt . element . is_a? ( ModelElem )
619+ wrapper = Wrapper . new ( wrapped , options )
620+ # Use a proc as wrapper may be lazy
621+ @elements [ elt . element . name ] = proc { wrapper . element }
622+ wrapper
623+ end
624+
608625 def generate_base_element ( elt , opts )
609626 element = elt . proc . call ( opts )
610627 return element if elt . content . nil?
@@ -616,19 +633,20 @@ def generate_base_element(elt, opts)
616633 element
617634 end
618635
636+ # @author sdaubert
637+ # @author lemontree55
638+ # @author adfoster-r7
619639 def private_to_h ( element = nil ) # rubocop:disable Metrics/CyclomaticComplexity
620640 my_element = element || root
621- my_element = my_element . root if my_element . is_a? ( Model )
622641 value = case my_element
642+ when Model
643+ model_to_h ( my_element )
623644 when Types ::SequenceOf
624645 sequence_of_to_h ( my_element )
625646 when Types ::Sequence
626647 sequence_to_h ( my_element )
627- # @author adfoster-r7
628648 when Types ::Choice
629- raise ChoiceError . new ( my_element ) if my_element . chosen . nil?
630-
631- private_to_h ( my_element . value [ my_element . chosen ] )
649+ choice_to_h ( my_element )
632650 when Wrapper
633651 wrapper_to_h ( my_element )
634652 else
@@ -641,6 +659,15 @@ def private_to_h(element=nil) # rubocop:disable Metrics/CyclomaticComplexity
641659 end
642660 end
643661
662+ def model_to_h ( elt )
663+ hsh = elt . to_h
664+ if root . is_a? ( Types ::Choice )
665+ hsh [ hsh . keys . first ]
666+ else
667+ { @elements . key ( elt ) => hsh [ hsh . keys . first ] }
668+ end
669+ end
670+
644671 def sequence_of_to_h ( elt )
645672 if elt . of_type < Model
646673 elt . value &.map { |el | el . to_h . values . first }
@@ -655,8 +682,7 @@ def sequence_to_h(seq)
655682
656683 case el
657684 when Model
658- hsh = el . to_h
659- [ @elements . key ( el ) , hsh [ hsh . keys . first ] ]
685+ model_to_h ( el ) . to_a [ 0 ]
660686 when Wrapper
661687 [ unwrap_keyname ( @elements . key ( el ) ) , wrapper_to_h ( el ) ]
662688 else
@@ -666,6 +692,13 @@ def sequence_to_h(seq)
666692 ary . compact . to_h
667693 end
668694
695+ def choice_to_h ( elt )
696+ raise ChoiceError . new ( elt ) if elt . chosen . nil?
697+
698+ chosen = elt . value [ elt . chosen ]
699+ { chosen . name => private_to_h ( chosen ) }
700+ end
701+
669702 def unwrap_keyname ( key )
670703 key . to_s . delete_suffix ( '_wrapper' ) . to_sym
671704 end
0 commit comments