order_tree 0.0.2
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/.DS_Store +0 -0
 - data/.gitignore +5 -0
 - data/.yardoc/checksums +5 -0
 - data/.yardoc/objects/root.dat +0 -0
 - data/.yardoc/proxy_types +0 -0
 - data/Gemfile +4 -0
 - data/README.md +26 -0
 - data/Rakefile +39 -0
 - data/lib/order_tree.rb +6 -0
 - data/lib/order_tree/order_tree.rb +319 -0
 - data/lib/order_tree/order_tree_node.rb +66 -0
 - data/lib/order_tree/unique_proxy.rb +96 -0
 - data/lib/order_tree/version.rb +3 -0
 - data/order_tree.gemspec +26 -0
 - data/spec/order_tree_spec.rb +338 -0
 - data/spec/spec_helper.rb +35 -0
 - metadata +110 -0
 
    
        data/.DS_Store
    ADDED
    
    | 
         Binary file 
     | 
    
        data/.yardoc/checksums
    ADDED
    
    | 
         @@ -0,0 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            lib/order_tree.rb 1587f76284fef215167a4b0970a1411503f6543f
         
     | 
| 
      
 2 
     | 
    
         
            +
            lib/order_tree/version.rb 12d621b5c0101d185a48bac5d5ad897d7b83053b
         
     | 
| 
      
 3 
     | 
    
         
            +
            lib/order_tree/unique_proxy.rb 632e468875c365d94b069f5c7e4d3d10030ccb55
         
     | 
| 
      
 4 
     | 
    
         
            +
            lib/order_tree/order_tree.rb 3dc2a2a576334be3fe9cd19fe999b310fbfd7ea6
         
     | 
| 
      
 5 
     | 
    
         
            +
            lib/order_tree/order_store.rb cfef2da2707e61ed0637a48e9a0c1a55d9578b1c
         
     | 
| 
         Binary file 
     | 
    
        data/.yardoc/proxy_types
    ADDED
    
    | 
         Binary file 
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #Ordered Tree
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This is a nested hash / unbalance tree structure which iterates over all of 
         
     | 
| 
      
 4 
     | 
    
         
            +
            its available values in insertion order.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ##Like a Normal Hash?
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Exactly like a normal hash.  Althought with a standard Ruby Hash it's impossible to 
         
     | 
| 
      
 9 
     | 
    
         
            +
            know whether or not `hash["a"]["b"]` was inserted before or after `hash["b"]["c"]`
         
     | 
| 
      
 10 
     | 
    
         
            +
            because each individual Hash maintains it's own insertion order.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Now you can know.  If you need to.  The main thing you gain with this over an
         
     | 
| 
      
 13 
     | 
    
         
            +
            Array is the ability to prune or transplant multiple values at the same
         
     | 
| 
      
 14 
     | 
    
         
            +
            time by cutting on one of the branches.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            ##Caveat
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            Each value is actually stored in a proxy object which maintains a unique id.
         
     | 
| 
      
 19 
     | 
    
         
            +
            This is necessary so that if you insert three `4`s into the tree you can tell
         
     | 
| 
      
 20 
     | 
    
         
            +
            which one came first.  This wouldn't actually be necessary in a C implementation,
         
     | 
| 
      
 21 
     | 
    
         
            +
            or in one based on WeakRefs, but it works okay here.
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            You can generally treat the OrderTree exactly like a nested hash, but be aware
         
     | 
| 
      
 24 
     | 
    
         
            +
            that the first and last methods (as well as the #each iterator) actually return
         
     | 
| 
      
 25 
     | 
    
         
            +
            an OrderTreeNode and not the actual object stored at that location.  (You can
         
     | 
| 
      
 26 
     | 
    
         
            +
            get at it by using #orig on the returned value.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 2 
     | 
    
         
            +
            Bundler::GemHelper.install_tasks
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rspec/core'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:spec) do |spec|
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.pattern = FileList['spec/**/*_spec.rb']
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.rspec_opts = "-d"
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:spec_with_report) do |spec|
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.fail_on_error = false
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.pattern = FileList['spec/**/*_spec.rb']
         
     | 
| 
      
 15 
     | 
    
         
            +
              spec.rspec_opts = "--format html --out report/test_report.html"
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            task :report do
         
     | 
| 
      
 19 
     | 
    
         
            +
              Dir.mkdir "report" unless File.exists? "report"
         
     | 
| 
      
 20 
     | 
    
         
            +
              Dir.mkdir "report/profile" unless File.exists? "report/profile"
         
     | 
| 
      
 21 
     | 
    
         
            +
              File.open "report/index.html","w" do |f|
         
     | 
| 
      
 22 
     | 
    
         
            +
                f.write <<-HTML
         
     | 
| 
      
 23 
     | 
    
         
            +
                  <html>
         
     | 
| 
      
 24 
     | 
    
         
            +
                    <body>
         
     | 
| 
      
 25 
     | 
    
         
            +
                      <h1> Status Report </h1>
         
     | 
| 
      
 26 
     | 
    
         
            +
                      <a href="coverage/index.html"> Coverage </a>
         
     | 
| 
      
 27 
     | 
    
         
            +
                      <a href="profile/profile.html"> Speed Profile </a>
         
     | 
| 
      
 28 
     | 
    
         
            +
                      <a href="test_report.html"> Test Report </a>
         
     | 
| 
      
 29 
     | 
    
         
            +
                    </body>
         
     | 
| 
      
 30 
     | 
    
         
            +
                  </html>
         
     | 
| 
      
 31 
     | 
    
         
            +
                HTML
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
              ENV["REPORT"] = "1" 
         
     | 
| 
      
 34 
     | 
    
         
            +
              Rake::Task[:spec_with_report].invoke
         
     | 
| 
      
 35 
     | 
    
         
            +
              ENV["REPORT"] = ""
         
     | 
| 
      
 36 
     | 
    
         
            +
            end 
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
    
        data/lib/order_tree.rb
    ADDED
    
    
| 
         @@ -0,0 +1,319 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'delegate'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module OrderTree
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A unbalance tree / nested hash type structure that implements #each and returns
         
     | 
| 
      
 6 
     | 
    
         
            +
              # the values in the order in which they were inserted, regardless of depth
         
     | 
| 
      
 7 
     | 
    
         
            +
              # It can mostly be treated as a nested hash - but #each will return a #path
         
     | 
| 
      
 8 
     | 
    
         
            +
              # to the values it iterates
         
     | 
| 
      
 9 
     | 
    
         
            +
              class OrderTree
         
     | 
| 
      
 10 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 11 
     | 
    
         
            +
                include ProxyOperator
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                class PathNotFound < StandardError; end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                attr_accessor :first, :root
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_reader :last
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
                # Create a new OrderTree
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @param [Hash] constructor - a hash literal for the initial values
         
     | 
| 
      
 20 
     | 
    
         
            +
                # @param [OrderTree] OrderTree - the root tree object.
         
     | 
| 
      
 21 
     | 
    
         
            +
                # @note The order of insertion might not be what you would expect for multi-
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   level hash literals. The most deeply nested values will be inserted FIRST.
         
     | 
| 
      
 23 
     | 
    
         
            +
                def initialize(constructor = {}, root = nil) 
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @_delegate_hash = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                  self.root = root || self 
         
     | 
| 
      
 26 
     | 
    
         
            +
                  constructor.each_with_object(self) do |(k,v),memo|
         
     | 
| 
      
 27 
     | 
    
         
            +
                    memo[k] = v
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  self.default = OrderTreeNode.new(nil,self) if self.root
         
     | 
| 
      
 30 
     | 
    
         
            +
                  _delegate_hash.default = self.default
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def last= obj
         
     | 
| 
      
 34 
     | 
    
         
            +
                  if @last.nil?
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @first = obj
         
     | 
| 
      
 36 
     | 
    
         
            +
                    @last = obj
         
     | 
| 
      
 37 
     | 
    
         
            +
                  else
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @last = obj
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
                protected :last=
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                # Set the default value for the tree
         
     | 
| 
      
 44 
     | 
    
         
            +
                # This place the default object behind a UniqueProxy. The default
         
     | 
| 
      
 45 
     | 
    
         
            +
                # is not remembered within the order
         
     | 
| 
      
 46 
     | 
    
         
            +
                # @param [Object] obj
         
     | 
| 
      
 47 
     | 
    
         
            +
                def default= obj
         
     | 
| 
      
 48 
     | 
    
         
            +
                  unless proxy? obj
         
     | 
| 
      
 49 
     | 
    
         
            +
                    obj = OrderTreeNode.new(obj,self) 
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @default = obj
         
     | 
| 
      
 52 
     | 
    
         
            +
                  _delegate_hash.default = @default
         
     | 
| 
      
 53 
     | 
    
         
            +
                  _delegate_hash.each_value do |v| 
         
     | 
| 
      
 54 
     | 
    
         
            +
                    if v.is_a? OrderTree
         
     | 
| 
      
 55 
     | 
    
         
            +
                      v.default= obj
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                attr_reader :default
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                # Yields each path, value pair of the OrderTree in the order in which it was
         
     | 
| 
      
 63 
     | 
    
         
            +
                # inserted
         
     | 
| 
      
 64 
     | 
    
         
            +
                # @return [Enumerator]
         
     | 
| 
      
 65 
     | 
    
         
            +
                # @yield [path, value] yields the path (as an array) to a value
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @yieldparam [Array] path the path as an array
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @yieldparam [Object] value the original object stored in the OrderTree
         
     | 
| 
      
 68 
     | 
    
         
            +
                def each_pair
         
     | 
| 
      
 69 
     | 
    
         
            +
                  return enum_for(:each_pair) unless block_given?
         
     | 
| 
      
 70 
     | 
    
         
            +
                  self.each do |c|
         
     | 
| 
      
 71 
     | 
    
         
            +
                    yield c.path, c.orig 
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                # @return [Array] the results of calling {#each}.to_a
         
     | 
| 
      
 76 
     | 
    
         
            +
                def order
         
     | 
| 
      
 77 
     | 
    
         
            +
                  each_pair.to_a
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
                # @return [Enumerator] collection of OrderTreeNode objects in insertion order
         
     | 
| 
      
 81 
     | 
    
         
            +
                def each
         
     | 
| 
      
 82 
     | 
    
         
            +
                  return enum_for(:each) unless block_given?
         
     | 
| 
      
 83 
     | 
    
         
            +
                  c = root.first
         
     | 
| 
      
 84 
     | 
    
         
            +
                  while c
         
     | 
| 
      
 85 
     | 
    
         
            +
                    yield c
         
     | 
| 
      
 86 
     | 
    
         
            +
                    c = c.next
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                # @return [Enumerator] collection of paths in insertion order
         
     | 
| 
      
 91 
     | 
    
         
            +
                def each_path 
         
     | 
| 
      
 92 
     | 
    
         
            +
                  return enum_for(:each_path) unless block_given?
         
     | 
| 
      
 93 
     | 
    
         
            +
                  self.each do |v|
         
     | 
| 
      
 94 
     | 
    
         
            +
                    yield v.path
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
                
         
     | 
| 
      
 98 
     | 
    
         
            +
                # @return [Enumerator] collection of leaf values in insertion order
         
     | 
| 
      
 99 
     | 
    
         
            +
                def each_leaf
         
     | 
| 
      
 100 
     | 
    
         
            +
                  return enum_for(:each_leaf) unless block_given?
         
     | 
| 
      
 101 
     | 
    
         
            +
                  self.each do |v|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    unless v.is_a? OrderTree
         
     | 
| 
      
 103 
     | 
    
         
            +
                      yield v.orig
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
                    
         
     | 
| 
      
 108 
     | 
    
         
            +
                # @return [Enumerator] collection of values in insertion order, including subnodes
         
     | 
| 
      
 109 
     | 
    
         
            +
                def each_value 
         
     | 
| 
      
 110 
     | 
    
         
            +
                  return enum_for(:each_value) unless block_given?
         
     | 
| 
      
 111 
     | 
    
         
            +
                  self.each do |v|
         
     | 
| 
      
 112 
     | 
    
         
            +
                    yield v.orig
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                # Finds the first occurence of an object in the tree
         
     | 
| 
      
 117 
     | 
    
         
            +
                # @param [Object] val the value to search for this is a O(n) operation
         
     | 
| 
      
 118 
     | 
    
         
            +
                # @param [Block] block if both a block and val are passed, the 
         
     | 
| 
      
 119 
     | 
    
         
            +
                #   block will be evalueated first, then the value
         
     | 
| 
      
 120 
     | 
    
         
            +
                # @return [Array, false, true] path to value, false if not found, or true if value == self
         
     | 
| 
      
 121 
     | 
    
         
            +
                # @yield [value] use the block to perform more complicated tests
         
     | 
| 
      
 122 
     | 
    
         
            +
                # @yieldreturn [Boolean]
         
     | 
| 
      
 123 
     | 
    
         
            +
                # @raises [ArgumentError] if neither a val nor block is given.
         
     | 
| 
      
 124 
     | 
    
         
            +
                # @note You cannot search for a nil value by passing nil as the value. You must
         
     | 
| 
      
 125 
     | 
    
         
            +
                #   pass a block that compares for nil
         
     | 
| 
      
 126 
     | 
    
         
            +
                # @note This methods does NOT guarantee that you will recieve the result
         
     | 
| 
      
 127 
     | 
    
         
            +
                #   in inserted order
         
     | 
| 
      
 128 
     | 
    
         
            +
                def path val = nil, &block
         
     | 
| 
      
 129 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 130 
     | 
    
         
            +
                    path! val, &block 
         
     | 
| 
      
 131 
     | 
    
         
            +
                  rescue PathNotFound
         
     | 
| 
      
 132 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                # Finds the first occurence of a specific insertion in the tree
         
     | 
| 
      
 137 
     | 
    
         
            +
                # @param [OrderTreeNode] val the proxy object to find 
         
     | 
| 
      
 138 
     | 
    
         
            +
                def strict_path val = nil
         
     | 
| 
      
 139 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 140 
     | 
    
         
            +
                    strict_path! val
         
     | 
| 
      
 141 
     | 
    
         
            +
                  rescue PathNotFound
         
     | 
| 
      
 142 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
                
         
     | 
| 
      
 146 
     | 
    
         
            +
                # Raises an exception if it can't determine the path
         
     | 
| 
      
 147 
     | 
    
         
            +
                # @see {#path}
         
     | 
| 
      
 148 
     | 
    
         
            +
                def path! val = nil, &block
         
     | 
| 
      
 149 
     | 
    
         
            +
                  raise ArgumentError, "requires search value or block" if val.nil? and block.nil?
         
     | 
| 
      
 150 
     | 
    
         
            +
                  __path(val, false, [], &block)
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                # Raises an exception if it can't find the object
         
     | 
| 
      
 154 
     | 
    
         
            +
                # @see {#strict_path}
         
     | 
| 
      
 155 
     | 
    
         
            +
                def strict_path! val
         
     | 
| 
      
 156 
     | 
    
         
            +
                  unless ProxyOperator.proxy? val 
         
     | 
| 
      
 157 
     | 
    
         
            +
                    raise ArgumentError, "OrderTreeNode expected for strict_path"
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  __path(val, true)
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 163 
     | 
    
         
            +
                def __path val = nil, strict = false, key_path = [], &block
         
     | 
| 
      
 164 
     | 
    
         
            +
                  op = strict ? :equal? : :==
         
     | 
| 
      
 165 
     | 
    
         
            +
                  return true if (yield(val) unless block.nil?) or self.__send__ op, val 
         
     | 
| 
      
 166 
     | 
    
         
            +
                  _delegate_hash.each do |k,v|
         
     | 
| 
      
 167 
     | 
    
         
            +
                    if (yield v unless block.nil?) or v.__send__ op, val
         
     | 
| 
      
 168 
     | 
    
         
            +
                      key_path << k 
         
     | 
| 
      
 169 
     | 
    
         
            +
                      break
         
     | 
| 
      
 170 
     | 
    
         
            +
                    elsif v.respond_to? :__path, true
         
     | 
| 
      
 171 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 172 
     | 
    
         
            +
                        v.__path(val, strict, key_path, &block)
         
     | 
| 
      
 173 
     | 
    
         
            +
                        key_path.unshift(k)
         
     | 
| 
      
 174 
     | 
    
         
            +
                        break
         
     | 
| 
      
 175 
     | 
    
         
            +
                      rescue PathNotFound
         
     | 
| 
      
 176 
     | 
    
         
            +
                        # try the next one 
         
     | 
| 
      
 177 
     | 
    
         
            +
                      end
         
     | 
| 
      
 178 
     | 
    
         
            +
                    end
         
     | 
| 
      
 179 
     | 
    
         
            +
                  end
         
     | 
| 
      
 180 
     | 
    
         
            +
                  raise PathNotFound, "Couldn't find path to #{val} in #{self.to_s}" if key_path.empty?
         
     | 
| 
      
 181 
     | 
    
         
            +
                  key_path
         
     | 
| 
      
 182 
     | 
    
         
            +
                end
         
     | 
| 
      
 183 
     | 
    
         
            +
                private :__path
         
     | 
| 
      
 184 
     | 
    
         
            +
               
         
     | 
| 
      
 185 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 186 
     | 
    
         
            +
                # @api Delegate
         
     | 
| 
      
 187 
     | 
    
         
            +
                def _delegate_hash 
         
     | 
| 
      
 188 
     | 
    
         
            +
                  @_delegate_hash
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
                private :_delegate_hash
         
     | 
| 
      
 191 
     | 
    
         
            +
                
         
     | 
| 
      
 192 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 193 
     | 
    
         
            +
                  "#<#{self.class}:#{'0x%x' % self.__id__ << 1}>"
         
     | 
| 
      
 194 
     | 
    
         
            +
                end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 197 
     | 
    
         
            +
                  _delegate_hash.inspect
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                # @param [OrderTree] other
         
     | 
| 
      
 201 
     | 
    
         
            +
                # @return [true] if self and other do not share all leaves or were inserted in a different order
         
     | 
| 
      
 202 
     | 
    
         
            +
                def != other
         
     | 
| 
      
 203 
     | 
    
         
            +
                  !(self == other)
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
      
 205 
     | 
    
         
            +
                
         
     | 
| 
      
 206 
     | 
    
         
            +
                # @param [OrderTree] other
         
     | 
| 
      
 207 
     | 
    
         
            +
                # @return [true] if self and other share all of their leaves and were inserted in the same order
         
     | 
| 
      
 208 
     | 
    
         
            +
                def == other 
         
     | 
| 
      
 209 
     | 
    
         
            +
                  return false if other.class != self.class
         
     | 
| 
      
 210 
     | 
    
         
            +
                  ov,sv = other.each_value.to_a, self.each_value.to_a
         
     | 
| 
      
 211 
     | 
    
         
            +
                  t_arr = ov.size > sv.size ? (ov.zip(sv)) : (sv.zip(ov))
         
     | 
| 
      
 212 
     | 
    
         
            +
                  t_arr.each do |sv, ov|
         
     | 
| 
      
 213 
     | 
    
         
            +
                    return false if sv.nil? ^ ov.nil?
         
     | 
| 
      
 214 
     | 
    
         
            +
                    if [ov,sv].map { |v| v.respond_to? :_delegate_hash, true}.all?
         
     | 
| 
      
 215 
     | 
    
         
            +
                      return false unless ov.send(:_delegate_hash) == sv.send(:_delegate_hash)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    elsif ov != sv
         
     | 
| 
      
 217 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 218 
     | 
    
         
            +
                    end
         
     | 
| 
      
 219 
     | 
    
         
            +
                  end
         
     | 
| 
      
 220 
     | 
    
         
            +
                end
         
     | 
| 
      
 221 
     | 
    
         
            +
               
         
     | 
| 
      
 222 
     | 
    
         
            +
                # @param [OrderTree] other
         
     | 
| 
      
 223 
     | 
    
         
            +
                # @return [true] if self and other contains the same key/path pairs as leaf nodes, regardless of their
         
     | 
| 
      
 224 
     | 
    
         
            +
                #   order of insertion
         
     | 
| 
      
 225 
     | 
    
         
            +
                def contents_equal? other
         
     | 
| 
      
 226 
     | 
    
         
            +
                  return false if other.class != self.class
         
     | 
| 
      
 227 
     | 
    
         
            +
                  ov,sv = other.each_leaf.to_a.sort, self.each_leaf.to_a.sort
         
     | 
| 
      
 228 
     | 
    
         
            +
                  t_arr = ov.size > sv.size ? (ov.zip(sv)) : (sv.zip(ov))
         
     | 
| 
      
 229 
     | 
    
         
            +
                  t_arr.each do |sv,ov|
         
     | 
| 
      
 230 
     | 
    
         
            +
                    return false unless sv == ov
         
     | 
| 
      
 231 
     | 
    
         
            +
                  end
         
     | 
| 
      
 232 
     | 
    
         
            +
                end
         
     | 
| 
      
 233 
     | 
    
         
            +
               
         
     | 
| 
      
 234 
     | 
    
         
            +
                # Returns the UniqueProxy at path.
         
     | 
| 
      
 235 
     | 
    
         
            +
                # @param [Array] path the path to return
         
     | 
| 
      
 236 
     | 
    
         
            +
                # @return [OrdeTreeNode] either OrderTreeNode default or the OrderTreeNode at path 
         
     | 
| 
      
 237 
     | 
    
         
            +
                def at *paths
         
     | 
| 
      
 238 
     | 
    
         
            +
                  t = self 
         
     | 
| 
      
 239 
     | 
    
         
            +
                  paths.each do |p|
         
     | 
| 
      
 240 
     | 
    
         
            +
                    if t.respond_to? :at # if it's a branch nodejkeep looking
         
     | 
| 
      
 241 
     | 
    
         
            +
                      t = (t.__send__ :_delegate_hash)[p]
         
     | 
| 
      
 242 
     | 
    
         
            +
                    else
         
     | 
| 
      
 243 
     | 
    
         
            +
                      #other wise resturn the default
         
     | 
| 
      
 244 
     | 
    
         
            +
                      return self.root.default
         
     | 
| 
      
 245 
     | 
    
         
            +
                    end
         
     | 
| 
      
 246 
     | 
    
         
            +
                  end
         
     | 
| 
      
 247 
     | 
    
         
            +
                  t
         
     | 
| 
      
 248 
     | 
    
         
            +
                end
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                # Return the object stored at path
         
     | 
| 
      
 251 
     | 
    
         
            +
                # @param [Array] path you may specify the path as either an array, or
         
     | 
| 
      
 252 
     | 
    
         
            +
                #   by using the nested hash syntax
         
     | 
| 
      
 253 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 254 
     | 
    
         
            +
                #    obj = OrderTree.new( :first => { :second => { :third => 3 }})
         
     | 
| 
      
 255 
     | 
    
         
            +
                #    obj[:first, :second, :third] #=> 3
         
     | 
| 
      
 256 
     | 
    
         
            +
                #    obj[:first][:second][:third] #=> 3
         
     | 
| 
      
 257 
     | 
    
         
            +
                def [] *paths
         
     | 
| 
      
 258 
     | 
    
         
            +
                  t = self.at *paths
         
     | 
| 
      
 259 
     | 
    
         
            +
                  t.orig
         
     | 
| 
      
 260 
     | 
    
         
            +
                end
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 264 
     | 
    
         
            +
                def _find_delegate_hash *paths
         
     | 
| 
      
 265 
     | 
    
         
            +
                  under = self
         
     | 
| 
      
 266 
     | 
    
         
            +
                  paths.each do |k|
         
     | 
| 
      
 267 
     | 
    
         
            +
                    under = under.instance_eval do
         
     | 
| 
      
 268 
     | 
    
         
            +
                      unless self.respond_to? :_delegate_hash, true
         
     | 
| 
      
 269 
     | 
    
         
            +
                        raise NoMethodError, "Can't reifiy tree leaf on access to #{paths}"
         
     | 
| 
      
 270 
     | 
    
         
            +
                      end
         
     | 
| 
      
 271 
     | 
    
         
            +
                      h = self.send :_delegate_hash
         
     | 
| 
      
 272 
     | 
    
         
            +
                      if h.has_key? k and k != paths.last
         
     | 
| 
      
 273 
     | 
    
         
            +
                        h[k]
         
     | 
| 
      
 274 
     | 
    
         
            +
                      else
         
     | 
| 
      
 275 
     | 
    
         
            +
                        break h 
         
     | 
| 
      
 276 
     | 
    
         
            +
                      end
         
     | 
| 
      
 277 
     | 
    
         
            +
                    end 
         
     | 
| 
      
 278 
     | 
    
         
            +
                  end
         
     | 
| 
      
 279 
     | 
    
         
            +
                  under
         
     | 
| 
      
 280 
     | 
    
         
            +
                end
         
     | 
| 
      
 281 
     | 
    
         
            +
                private :_find_delegate_hash
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
                # Prune branch from the tree
         
     | 
| 
      
 284 
     | 
    
         
            +
                # @param [Array] path
         
     | 
| 
      
 285 
     | 
    
         
            +
                def delete *paths
         
     | 
| 
      
 286 
     | 
    
         
            +
                  under = _find_delegate_hash *paths
         
     | 
| 
      
 287 
     | 
    
         
            +
                  if under.has_key? paths.last
         
     | 
| 
      
 288 
     | 
    
         
            +
                    under[paths.last].remove
         
     | 
| 
      
 289 
     | 
    
         
            +
                  end
         
     | 
| 
      
 290 
     | 
    
         
            +
                end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                # Stores the value at path
         
     | 
| 
      
 293 
     | 
    
         
            +
                # @param [Array] path
         
     | 
| 
      
 294 
     | 
    
         
            +
                # @param [Object] value
         
     | 
| 
      
 295 
     | 
    
         
            +
                def []= *paths, value
         
     | 
| 
      
 296 
     | 
    
         
            +
                  under = _find_delegate_hash *paths
         
     | 
| 
      
 297 
     | 
    
         
            +
                  
         
     | 
| 
      
 298 
     | 
    
         
            +
                  if value.kind_of? Hash or value.kind_of? OrderTree
         
     | 
| 
      
 299 
     | 
    
         
            +
                    value = OrderTree.new(value, @root)
         
     | 
| 
      
 300 
     | 
    
         
            +
                    value.default= self.root.default
         
     | 
| 
      
 301 
     | 
    
         
            +
                  end
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                  if under.has_key? paths.last # i am overwriting a path
         
     | 
| 
      
 304 
     | 
    
         
            +
                    under[paths.last].remove
         
     | 
| 
      
 305 
     | 
    
         
            +
                  end
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                  under[paths.last] = OrderTreeNode.new(value, self)
         
     | 
| 
      
 308 
     | 
    
         
            +
                  under[paths.last].prev = root.last if root.last
         
     | 
| 
      
 309 
     | 
    
         
            +
                  root.last.next = under[paths.last] if root.last
         
     | 
| 
      
 310 
     | 
    
         
            +
                  root.last = under[paths.last]
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                  #@order.push under[paths.last]
         
     | 
| 
      
 313 
     | 
    
         
            +
                  
         
     | 
| 
      
 314 
     | 
    
         
            +
                  #puts "insertion of '#{value}' in #{self.to_s} -> #{@order.to_s} (id #{under[paths.last].unique_id})"
         
     | 
| 
      
 315 
     | 
    
         
            +
                  value
         
     | 
| 
      
 316 
     | 
    
         
            +
                end
         
     | 
| 
      
 317 
     | 
    
         
            +
                alias :store :[]=
         
     | 
| 
      
 318 
     | 
    
         
            +
              end
         
     | 
| 
      
 319 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OrderTree
         
     | 
| 
      
 2 
     | 
    
         
            +
              class OrderTreeNode < UniqueProxy
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :next, :prev
         
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :tree
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :path
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize obj, tree
         
     | 
| 
      
 8 
     | 
    
         
            +
                  super(obj)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @tree = tree
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def remove
         
     | 
| 
      
 13 
     | 
    
         
            +
                  prev_node = self.prev
         
     | 
| 
      
 14 
     | 
    
         
            +
                  next_node = self.next
         
     | 
| 
      
 15 
     | 
    
         
            +
                  self.next.prev = prev_node if self.next 
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.prev.next = next_node if self.prev 
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  if self.tree.root.first.equal? self
         
     | 
| 
      
 19 
     | 
    
         
            +
                    self.tree.root.first = self.next
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # try this so that the node can remove
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # itself fromt he tree
         
     | 
| 
      
 24 
     | 
    
         
            +
                  my_path = self.path
         
     | 
| 
      
 25 
     | 
    
         
            +
                  self.tree.instance_eval do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    _delegate_hash.delete my_path.last
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @path = nil
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @tree = nil
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @next = nil
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @prev = nil
         
     | 
| 
      
 32 
     | 
    
         
            +
                  self
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def before other
         
     | 
| 
      
 36 
     | 
    
         
            +
                  (self <=> other) == -1 ? true : false
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def after other
         
     | 
| 
      
 40 
     | 
    
         
            +
                  (self <=> other) == 1 ? true : false
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def <=> other
         
     | 
| 
      
 44 
     | 
    
         
            +
                  if self.equal? other
         
     | 
| 
      
 45 
     | 
    
         
            +
                    return 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                  else
         
     | 
| 
      
 47 
     | 
    
         
            +
                    p, n = self.prev, self.next
         
     | 
| 
      
 48 
     | 
    
         
            +
                    while p or n
         
     | 
| 
      
 49 
     | 
    
         
            +
                      return 1 if p.equal? other
         
     | 
| 
      
 50 
     | 
    
         
            +
                      return -1 if n.equal? other
         
     | 
| 
      
 51 
     | 
    
         
            +
                      p = p.prev if p
         
     | 
| 
      
 52 
     | 
    
         
            +
                      n = n.next if n
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  raise ::ArgumentError, "Cannot compare #{self} and #{other} because they are not in the same tree" 
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def path
         
     | 
| 
      
 59 
     | 
    
         
            +
                  @path || self.path!
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                def path!
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @path = self.tree.root.strict_path! self
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,96 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'securerandom'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module OrderTree
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Mixin module that provides a proxy convience functions
         
     | 
| 
      
 6 
     | 
    
         
            +
              module ProxyOperator
         
     | 
| 
      
 7 
     | 
    
         
            +
                #@param [Object] obj object to test
         
     | 
| 
      
 8 
     | 
    
         
            +
                #@return [Boolean] is object in fact a proxy? 
         
     | 
| 
      
 9 
     | 
    
         
            +
                def proxy? obj
         
     | 
| 
      
 10 
     | 
    
         
            +
                  !!(obj.instance_eval { @is_proxy })
         
     | 
| 
      
 11 
     | 
    
         
            +
                rescue false
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                module_function :proxy?
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                #@param [Object] obj object to proxy
         
     | 
| 
      
 16 
     | 
    
         
            +
                #@return [UniqueProxy] create a unique proxy over obj
         
     | 
| 
      
 17 
     | 
    
         
            +
                def proxy obj
         
     | 
| 
      
 18 
     | 
    
         
            +
                  UniqueProxy.new obj
         
     | 
| 
      
 19 
     | 
    
         
            +
                rescue false
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
                module_function :proxy
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
              
         
     | 
| 
      
 24 
     | 
    
         
            +
              # Simple Proxy for distinguishing between the insertions of two identical
         
     | 
| 
      
 25 
     | 
    
         
            +
              # objects in an order tree.  Assign a unique ID to any object passed through
         
     | 
| 
      
 26 
     | 
    
         
            +
              # the proxy, so you can always find the same object, even if you move it
         
     | 
| 
      
 27 
     | 
    
         
            +
              # around in the tree. It also enables you to tell the differen between two
         
     | 
| 
      
 28 
     | 
    
         
            +
              # different insertions of the same singleton object.
         
     | 
| 
      
 29 
     | 
    
         
            +
              class UniqueProxy < BasicObject
         
     | 
| 
      
 30 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 31 
     | 
    
         
            +
                  attr_accessor :verbose_inspect
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # @param [Object] obj - the proxy target
         
     | 
| 
      
 35 
     | 
    
         
            +
                def initialize obj
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @is_proxy = true
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @obj = obj
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @uuid ||= ::SecureRandom.uuid
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                # @return [String] the unique ID of the proxy
         
     | 
| 
      
 42 
     | 
    
         
            +
                def unique_id
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @uuid
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # @return [String] a string describing the proxy if UniqueProxy.verbose_inspect is not false
         
     | 
| 
      
 47 
     | 
    
         
            +
                #   otherwise calls #inspect on the proxied object
         
     | 
| 
      
 48 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 49 
     | 
    
         
            +
                  if UniqueProxy.verbose_inspect
         
     | 
| 
      
 50 
     | 
    
         
            +
                    "#<#{UniqueProxy}::#{@uuid} => #{@obj.inspect}>"
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @obj.inspect
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                # @return [String] a eval-able string to create a new proxy over this proxied object
         
     | 
| 
      
 57 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 58 
     | 
    
         
            +
                  if UniqueProxy.verbose_inspect
         
     | 
| 
      
 59 
     | 
    
         
            +
                    "proxy(#{@obj.to_s})"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  else
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @obj.to_s
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                # Is true only if the other object has the same unique_id as self
         
     | 
| 
      
 66 
     | 
    
         
            +
                def equal? other
         
     | 
| 
      
 67 
     | 
    
         
            +
                  (@uuid == other.unique_id) rescue false
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                # @return [Object] the unproxied target
         
     | 
| 
      
 71 
     | 
    
         
            +
                def orig
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @obj
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
                
         
     | 
| 
      
 75 
     | 
    
         
            +
                # Dispatches methods calls to proxy target
         
     | 
| 
      
 76 
     | 
    
         
            +
                def method_missing(method, *args, &block)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @obj.__send__ method, *args, &block
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
               
         
     | 
| 
      
 80 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 81 
     | 
    
         
            +
                def !
         
     | 
| 
      
 82 
     | 
    
         
            +
                  !@obj
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
                
         
     | 
| 
      
 85 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 86 
     | 
    
         
            +
                def == arg
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @obj == arg
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
                
         
     | 
| 
      
 90 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 91 
     | 
    
         
            +
                def != arg
         
     | 
| 
      
 92 
     | 
    
         
            +
                  @obj != arg
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
            end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
    
        data/order_tree.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.push File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "order_tree/version"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.name        = "order_tree"
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version     = OrderTree::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.platform    = Gem::Platform::RUBY
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.authors     = ["Stephen Prater"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.email       = ["stephenp@agrussell.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.homepage    = "http://github.com/stephenprater/order_tree"
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.summary     = %q{An unbalanced tree / nested hash which remember insertion order}
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.description = %q{Use OrderTree when you need both insertion order access and nested hash path style access}
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.rubyforge_project = "order_tree"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_development_dependency('rspec')
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_development_dependency('simplecov')
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_development_dependency('ruby-prof')
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_development_dependency('ruby-debug19')
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,338 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'pp'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'order_tree'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            describe OrderTree::UniqueProxy do
         
     | 
| 
      
 8 
     | 
    
         
            +
              before :all do
         
     | 
| 
      
 9 
     | 
    
         
            +
                Object.send :include, OrderTree::ProxyOperator
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it "can tell apart things that are the same" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                (4 == 4).should eq true
         
     | 
| 
      
 14 
     | 
    
         
            +
                (4.equal? 4).should eq true #because fixnums are really the same object
         
     | 
| 
      
 15 
     | 
    
         
            +
                a = OrderTree::UniqueProxy.new(4)
         
     | 
| 
      
 16 
     | 
    
         
            +
                b = OrderTree::UniqueProxy.new(4)
         
     | 
| 
      
 17 
     | 
    
         
            +
                c = OrderTree::UniqueProxy.new(5)
         
     | 
| 
      
 18 
     | 
    
         
            +
                (a == b).should eq true
         
     | 
| 
      
 19 
     | 
    
         
            +
                (!c).should eq false
         
     | 
| 
      
 20 
     | 
    
         
            +
                (c != a).should eq true
         
     | 
| 
      
 21 
     | 
    
         
            +
                (a.equal? b).should eq false
         
     | 
| 
      
 22 
     | 
    
         
            +
                (a.orig.equal? b.orig).should eq true
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              it "can retrieve the unique id" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                a = OrderTree::UniqueProxy.new(4)
         
     | 
| 
      
 27 
     | 
    
         
            +
                b = OrderTree::UniqueProxy.new(4)
         
     | 
| 
      
 28 
     | 
    
         
            +
                a.unique_id.should_not eq b.unique_id
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              it "can identify a proxy" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                a = OrderTree::UniqueProxy.new(5)
         
     | 
| 
      
 33 
     | 
    
         
            +
                proxy(5).should eq proxy(5)
         
     | 
| 
      
 34 
     | 
    
         
            +
                (proxy(5).equal? proxy(5)).should be_false
         
     | 
| 
      
 35 
     | 
    
         
            +
                (proxy? a).should be_true
         
     | 
| 
      
 36 
     | 
    
         
            +
                (proxy? 5).should be_false
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              it "can help you inspect and to_s proxies" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                proxy(5).to_s.should eq "5"
         
     | 
| 
      
 41 
     | 
    
         
            +
                proxy(5).inspect.should eq "5"
         
     | 
| 
      
 42 
     | 
    
         
            +
                OrderTree::UniqueProxy.verbose_inspect = true
         
     | 
| 
      
 43 
     | 
    
         
            +
                p = proxy(5) 
         
     | 
| 
      
 44 
     | 
    
         
            +
                p.inspect.to_s.should match(/#<UniqueProxy:(.*?)\s=>\s5>/)
         
     | 
| 
      
 45 
     | 
    
         
            +
                p.to_s.should == "proxy(5)"
         
     | 
| 
      
 46 
     | 
    
         
            +
                OrderTree::UniqueProxy.verbose_inspect = false
         
     | 
| 
      
 47 
     | 
    
         
            +
                p2 = eval(p.to_s)
         
     | 
| 
      
 48 
     | 
    
         
            +
                p2.should eq p
         
     | 
| 
      
 49 
     | 
    
         
            +
                (p2.equal? p).should be_false
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            describe OrderTree::OrderTree do
         
     | 
| 
      
 54 
     | 
    
         
            +
               before :all do
         
     | 
| 
      
 55 
     | 
    
         
            +
                 @testhash = {
         
     | 
| 
      
 56 
     | 
    
         
            +
                  :from => {
         
     | 
| 
      
 57 
     | 
    
         
            +
                    :a => {
         
     | 
| 
      
 58 
     | 
    
         
            +
                      :b => 4,
         
     | 
| 
      
 59 
     | 
    
         
            +
                      :c => 4,
         
     | 
| 
      
 60 
     | 
    
         
            +
                    }
         
     | 
| 
      
 61 
     | 
    
         
            +
                  },
         
     | 
| 
      
 62 
     | 
    
         
            +
                  :to => {
         
     | 
| 
      
 63 
     | 
    
         
            +
                    :d => 4,
         
     | 
| 
      
 64 
     | 
    
         
            +
                    :e => 4,
         
     | 
| 
      
 65 
     | 
    
         
            +
                    :to_to => {
         
     | 
| 
      
 66 
     | 
    
         
            +
                      :f => 5,
         
     | 
| 
      
 67 
     | 
    
         
            +
                      :g => 6,
         
     | 
| 
      
 68 
     | 
    
         
            +
                      :h => 7,
         
     | 
| 
      
 69 
     | 
    
         
            +
                    }
         
     | 
| 
      
 70 
     | 
    
         
            +
                  }
         
     | 
| 
      
 71 
     | 
    
         
            +
                }
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                @testhash_insertion = { 
         
     | 
| 
      
 74 
     | 
    
         
            +
                  :to => {
         
     | 
| 
      
 75 
     | 
    
         
            +
                    :d => 4,
         
     | 
| 
      
 76 
     | 
    
         
            +
                    :e => 4,
         
     | 
| 
      
 77 
     | 
    
         
            +
                    :to_to => {
         
     | 
| 
      
 78 
     | 
    
         
            +
                      :f => 5,
         
     | 
| 
      
 79 
     | 
    
         
            +
                      :g => 6,
         
     | 
| 
      
 80 
     | 
    
         
            +
                      :h => 7,
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }
         
     | 
| 
      
 82 
     | 
    
         
            +
                  },
         
     | 
| 
      
 83 
     | 
    
         
            +
                  :from => {
         
     | 
| 
      
 84 
     | 
    
         
            +
                    :a => {
         
     | 
| 
      
 85 
     | 
    
         
            +
                      :b => 4,
         
     | 
| 
      
 86 
     | 
    
         
            +
                      :c => 4,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    }
         
     | 
| 
      
 88 
     | 
    
         
            +
                  }
         
     | 
| 
      
 89 
     | 
    
         
            +
                }
         
     | 
| 
      
 90 
     | 
    
         
            +
                
         
     | 
| 
      
 91 
     | 
    
         
            +
                @order = [[:from, :a, :b],
         
     | 
| 
      
 92 
     | 
    
         
            +
                          [:from, :a, :c],
         
     | 
| 
      
 93 
     | 
    
         
            +
                          [:from, :a],
         
     | 
| 
      
 94 
     | 
    
         
            +
                          [:from],
         
     | 
| 
      
 95 
     | 
    
         
            +
                          [:to, :d],
         
     | 
| 
      
 96 
     | 
    
         
            +
                          [:to, :e],
         
     | 
| 
      
 97 
     | 
    
         
            +
                          [:to, :to_to, :f],
         
     | 
| 
      
 98 
     | 
    
         
            +
                          [:to, :to_to, :g],
         
     | 
| 
      
 99 
     | 
    
         
            +
                          [:to, :to_to, :h],
         
     | 
| 
      
 100 
     | 
    
         
            +
                          [:to, :to_to],
         
     | 
| 
      
 101 
     | 
    
         
            +
                          [:to]]
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              it "initializes with a hash" do
         
     | 
| 
      
 105 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new(@testhash)
         
     | 
| 
      
 106 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new(@testhash_insertion)
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
              it "can retrieve based on path or nest" do
         
     | 
| 
      
 110 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new(@testhash)
         
     | 
| 
      
 111 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new(@testhash_insertion)
         
     | 
| 
      
 112 
     | 
    
         
            +
                [ot, ot2].map do |t|
         
     | 
| 
      
 113 
     | 
    
         
            +
                  t[:from][:a][:c].should eq 4
         
     | 
| 
      
 114 
     | 
    
         
            +
                  t[:from, :a, :c].should eq 4
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
              it "can set based on path or nest" do
         
     | 
| 
      
 119 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new(@testhash)
         
     | 
| 
      
 120 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new(@testhash_insertion)
         
     | 
| 
      
 121 
     | 
    
         
            +
                [ot, ot2].map do |t|
         
     | 
| 
      
 122 
     | 
    
         
            +
                  t[:from][:a][:d] = 4
         
     | 
| 
      
 123 
     | 
    
         
            +
                  t[:from, :a, :d].should eq 4
         
     | 
| 
      
 124 
     | 
    
         
            +
                  t[:from, :a, :e] = 6
         
     | 
| 
      
 125 
     | 
    
         
            +
                  t[:from][:a][:e].should eq 6
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
              it "remember the order" do
         
     | 
| 
      
 130 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new(@testhash)
         
     | 
| 
      
 131 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new(@testhash_insertion)
         
     | 
| 
      
 132 
     | 
    
         
            +
                ot.each_path.to_a.should eq @order
         
     | 
| 
      
 133 
     | 
    
         
            +
                ot2.each_path.to_a.should_not eq @order
         
     | 
| 
      
 134 
     | 
    
         
            +
              end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
              it "does not reify the hash on access" do
         
     | 
| 
      
 137 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new
         
     | 
| 
      
 138 
     | 
    
         
            +
                lambda do 
         
     | 
| 
      
 139 
     | 
    
         
            +
                  ot[:a, :b, :c] = 4
         
     | 
| 
      
 140 
     | 
    
         
            +
                end.should raise_error NoMethodError
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
              it "remembers the order after initialize" do
         
     | 
| 
      
 144 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new
         
     | 
| 
      
 145 
     | 
    
         
            +
                order_paths = [[:a],
         
     | 
| 
      
 146 
     | 
    
         
            +
                               [:a, :a1],
         
     | 
| 
      
 147 
     | 
    
         
            +
                               [:a, :a2],
         
     | 
| 
      
 148 
     | 
    
         
            +
                               [:b],
         
     | 
| 
      
 149 
     | 
    
         
            +
                               [:b, :c],
         
     | 
| 
      
 150 
     | 
    
         
            +
                               [:b, :c, :d]]
         
     | 
| 
      
 151 
     | 
    
         
            +
                order_paths.map do |v|
         
     | 
| 
      
 152 
     | 
    
         
            +
                  if [[:a], [:b], [:b, :c]].include? v
         
     | 
| 
      
 153 
     | 
    
         
            +
                    ot[*v] = {}
         
     | 
| 
      
 154 
     | 
    
         
            +
                  else
         
     | 
| 
      
 155 
     | 
    
         
            +
                    ot[*v] = 4
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
                ot.each_path.to_a.should eq order_paths
         
     | 
| 
      
 159 
     | 
    
         
            +
              end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
              it "can retrieve each pair" do
         
     | 
| 
      
 162 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                ot.each_pair.with_index do |(p,v),i|
         
     | 
| 
      
 165 
     | 
    
         
            +
                  p.should eq @order[i]
         
     | 
| 
      
 166 
     | 
    
         
            +
                  ot[*p].should eq v
         
     | 
| 
      
 167 
     | 
    
         
            +
                end
         
     | 
| 
      
 168 
     | 
    
         
            +
              end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
              it "can overwrite nodes" do
         
     | 
| 
      
 171 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 172 
     | 
    
         
            +
                ot[:from, :a, :c] = 'overwritten'
         
     | 
| 
      
 173 
     | 
    
         
            +
               
         
     | 
| 
      
 174 
     | 
    
         
            +
                new_pairs = ot.each_pair.to_a
         
     | 
| 
      
 175 
     | 
    
         
            +
                p,v = new_pairs.last
         
     | 
| 
      
 176 
     | 
    
         
            +
                p.should eq [:from, :a, :c]
         
     | 
| 
      
 177 
     | 
    
         
            +
                v.should eq 'overwritten'
         
     | 
| 
      
 178 
     | 
    
         
            +
               
         
     | 
| 
      
 179 
     | 
    
         
            +
                ot[:from, :a, :c] = 'overwritten again'
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                p.should eq [:from, :a, :c]
         
     | 
| 
      
 182 
     | 
    
         
            +
                ot[:from, :a, :c].should eq 'overwritten again'
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                new_pairs = ot.each_pair.to_a
         
     | 
| 
      
 185 
     | 
    
         
            +
                p,v = new_pairs.first
         
     | 
| 
      
 186 
     | 
    
         
            +
                p.should eq [:from, :a, :b]
         
     | 
| 
      
 187 
     | 
    
         
            +
                v.should eq 4
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                p,v = new_pairs[3]
         
     | 
| 
      
 190 
     | 
    
         
            +
                p.should eq [:to, :d]
         
     | 
| 
      
 191 
     | 
    
         
            +
                v.should eq 4
         
     | 
| 
      
 192 
     | 
    
         
            +
              end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
              it "does == comparison" do
         
     | 
| 
      
 195 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 196 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                ot.first.should eq ot2.first #because underlying objects are compared 
         
     | 
| 
      
 199 
     | 
    
         
            +
                (ot == ot2).should be_true #each order and == on the object
         
     | 
| 
      
 200 
     | 
    
         
            +
                ot.equal?(ot2).should be_false #we're comparing the proxies here
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                (ot.first.equal? ot2.first).should be_false
         
     | 
| 
      
 203 
     | 
    
         
            +
              end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
              it "does != comparison" do
         
     | 
| 
      
 206 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 207 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new @testhash_insertion
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                (ot != ot2).should be_true
         
     | 
| 
      
 210 
     | 
    
         
            +
              end
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
              it "does leaf/node equality with contents_equal?" do
         
     | 
| 
      
 213 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 214 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new @testhash_insertion
         
     | 
| 
      
 215 
     | 
    
         
            +
                (ot.contents_equal? ot2).should be_true
         
     | 
| 
      
 216 
     | 
    
         
            +
              end
         
     | 
| 
      
 217 
     | 
    
         
            +
                 
         
     | 
| 
      
 218 
     | 
    
         
            +
              it "overwriting a key moves it to the end of the order" do
         
     | 
| 
      
 219 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new
         
     | 
| 
      
 220 
     | 
    
         
            +
                ot[:a] = 4
         
     | 
| 
      
 221 
     | 
    
         
            +
                ot[:b] = 4
         
     | 
| 
      
 222 
     | 
    
         
            +
                ot.each_path.to_a.should eq [[:a], [:b]]
         
     | 
| 
      
 223 
     | 
    
         
            +
                ot[:a] = 5
         
     | 
| 
      
 224 
     | 
    
         
            +
                ot.each_path.to_a.should eq [[:b], [:a]]
         
     | 
| 
      
 225 
     | 
    
         
            +
              end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
              it "overwriting a nested keys moves to the end of the order" do
         
     | 
| 
      
 228 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new( {:a => { :b => 4}, :c => 5})
         
     | 
| 
      
 229 
     | 
    
         
            +
                ot.each_path.to_a.should eq [[:a, :b], [:a], [:c]]
         
     | 
| 
      
 230 
     | 
    
         
            +
                ot[:a,:b] = 5
         
     | 
| 
      
 231 
     | 
    
         
            +
                ot.each_path.to_a.should eq [[:a], [:c], [:a, :b]]
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
              it "does not double proxy the default" do
         
     | 
| 
      
 235 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 236 
     | 
    
         
            +
                (proxy? ot.default).should be_true
         
     | 
| 
      
 237 
     | 
    
         
            +
                (proxy? ot[:foobar]).should be_false
         
     | 
| 
      
 238 
     | 
    
         
            +
                (proxy? ot[:to, :to_to, :no_key]).should be_false
         
     | 
| 
      
 239 
     | 
    
         
            +
              end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
              it "returns a default when the key doesn't exist" do
         
     | 
| 
      
 242 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 243 
     | 
    
         
            +
                ot.default = "foo"
         
     | 
| 
      
 244 
     | 
    
         
            +
                ot[:to, :foo].should eq "foo"
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                #copies it to nested levels
         
     | 
| 
      
 247 
     | 
    
         
            +
                ot.default = "bar"
         
     | 
| 
      
 248 
     | 
    
         
            +
                ot[:to, :foo].should eq "bar"
         
     | 
| 
      
 249 
     | 
    
         
            +
                
         
     | 
| 
      
 250 
     | 
    
         
            +
                ot[:to, :to_to, :no_key].should eq "bar"
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
                # does't matter how deep i look
         
     | 
| 
      
 253 
     | 
    
         
            +
                ot[:foo, :bar, :foo, :monkey].should eq "bar"
         
     | 
| 
      
 254 
     | 
    
         
            +
              end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
              it "can find the path for value" do
         
     | 
| 
      
 257 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 258 
     | 
    
         
            +
                ot.path(7).should eq [:to, :to_to, :h]
         
     | 
| 
      
 259 
     | 
    
         
            +
                ot.path(8).should be_nil
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                lambda do
         
     | 
| 
      
 262 
     | 
    
         
            +
                  ot.path!(7).should eq [:to, :to_to, :h]
         
     | 
| 
      
 263 
     | 
    
         
            +
                  ot.path!(8)
         
     | 
| 
      
 264 
     | 
    
         
            +
                end.should raise_error OrderTree::OrderTree::PathNotFound
         
     | 
| 
      
 265 
     | 
    
         
            +
              end
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
              it "can prune the tree" do
         
     | 
| 
      
 268 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 269 
     | 
    
         
            +
                ot.default = "bob"
         
     | 
| 
      
 270 
     | 
    
         
            +
                ot.delete :from, :a, :b
         
     | 
| 
      
 271 
     | 
    
         
            +
                ot[:from, :a, :b].should eq "bob"
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
                to_to = ot.at :to, :to_to
         
     | 
| 
      
 274 
     | 
    
         
            +
                to_to.remove
         
     | 
| 
      
 275 
     | 
    
         
            +
                
         
     | 
| 
      
 276 
     | 
    
         
            +
                ot[:to, :to_to].should eq "bob"
         
     | 
| 
      
 277 
     | 
    
         
            +
              end
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
              it "can find the path for a node object" do
         
     | 
| 
      
 280 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 281 
     | 
    
         
            +
                lambda do
         
     | 
| 
      
 282 
     | 
    
         
            +
                  ot.strict_path(7)
         
     | 
| 
      
 283 
     | 
    
         
            +
                end.should raise_error ArgumentError
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
      
 285 
     | 
    
         
            +
                seven_node = ot.at *ot.path(7)
         
     | 
| 
      
 286 
     | 
    
         
            +
                ot.strict_path(seven_node).should eq [:to, :to_to, :h]
         
     | 
| 
      
 287 
     | 
    
         
            +
               
         
     | 
| 
      
 288 
     | 
    
         
            +
                seven_node.remove
         
     | 
| 
      
 289 
     | 
    
         
            +
                ot.strict_path(seven_node).should be_nil
         
     | 
| 
      
 290 
     | 
    
         
            +
                #this is the internal call that it uses - it's just here for completeness
         
     | 
| 
      
 291 
     | 
    
         
            +
                lambda do
         
     | 
| 
      
 292 
     | 
    
         
            +
                  ot.strict_path!(seven_node)
         
     | 
| 
      
 293 
     | 
    
         
            +
                end.should raise_error OrderTree::OrderTree::PathNotFound
         
     | 
| 
      
 294 
     | 
    
         
            +
              end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
              it "can run enumerable methods which depend on <=>" do
         
     | 
| 
      
 297 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 298 
     | 
    
         
            +
                ot.max.should eq ot.last 
         
     | 
| 
      
 299 
     | 
    
         
            +
                ot.min.should eq ot.first
         
     | 
| 
      
 300 
     | 
    
         
            +
                ot.sort.should eq ot.each_value.to_a
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                # roundabout
         
     | 
| 
      
 303 
     | 
    
         
            +
                ot.max.should eq ot[*ot.strict_path!(ot.last)]
         
     | 
| 
      
 304 
     | 
    
         
            +
                ot.min.should eq ot[*ot.strict_path!(ot.first)]
         
     | 
| 
      
 305 
     | 
    
         
            +
              end
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
              it "can tell you about insertion order, natch" do
         
     | 
| 
      
 308 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 309 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new @testhash_insertion
         
     | 
| 
      
 310 
     | 
    
         
            +
                
         
     | 
| 
      
 311 
     | 
    
         
            +
                (ot.at(:from, :a, :c).before(ot.at(:from, :a, :b))).should be_false
         
     | 
| 
      
 312 
     | 
    
         
            +
                (ot.at(:from, :a, :b).before(ot.at(:to, :d))).should be_true
         
     | 
| 
      
 313 
     | 
    
         
            +
             
     | 
| 
      
 314 
     | 
    
         
            +
                (ot.at(:from, :a, :c).after(ot.at(:from, :a, :b))).should be_true
         
     | 
| 
      
 315 
     | 
    
         
            +
                (ot.at(:to, :e).after(ot.at(:from, :a, :b))).should be_true
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                #this probably is only possible if you're doing this.
         
     | 
| 
      
 318 
     | 
    
         
            +
                (ot.at(:from, :a, :b) <=> ot.at(:from, :a, :b)).should eq 0
         
     | 
| 
      
 319 
     | 
    
         
            +
              end
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
              it "can't compare nodes across trees" do
         
     | 
| 
      
 322 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 323 
     | 
    
         
            +
                ot2 = OrderTree::OrderTree.new @testhash_insertion
         
     | 
| 
      
 324 
     | 
    
         
            +
                
         
     | 
| 
      
 325 
     | 
    
         
            +
                lambda do
         
     | 
| 
      
 326 
     | 
    
         
            +
                  ot.at(:from, :a, :c).before(ot2.at(:from, :a, :b))
         
     | 
| 
      
 327 
     | 
    
         
            +
                end.should raise_error ArgumentError
         
     | 
| 
      
 328 
     | 
    
         
            +
              end
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
              it "can run regular enumerable methods" do
         
     | 
| 
      
 331 
     | 
    
         
            +
                # i'm not going to try all of these, just the one i know
         
     | 
| 
      
 332 
     | 
    
         
            +
                # i didn't define.
         
     | 
| 
      
 333 
     | 
    
         
            +
                ot = OrderTree::OrderTree.new @testhash
         
     | 
| 
      
 334 
     | 
    
         
            +
                ot.each_cons(3).with_index do |v,idx|
         
     | 
| 
      
 335 
     | 
    
         
            +
                  v.collect { |e| e.path }.should eq @order[idx..idx+2]
         
     | 
| 
      
 336 
     | 
    
         
            +
                end
         
     | 
| 
      
 337 
     | 
    
         
            +
              end
         
     | 
| 
      
 338 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            if ENV["REPORT"] == "1" then
         
     | 
| 
      
 2 
     | 
    
         
            +
              require 'simplecov'
         
     | 
| 
      
 3 
     | 
    
         
            +
              require 'ruby-prof'
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'ruby-debug'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              SimpleCov.start do
         
     | 
| 
      
 7 
     | 
    
         
            +
                add_filter "spec.rb"
         
     | 
| 
      
 8 
     | 
    
         
            +
                coverage_dir "report/coverage"
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              RSpec.configure do |config|
         
     | 
| 
      
 12 
     | 
    
         
            +
                config.before :suite do |example|
         
     | 
| 
      
 13 
     | 
    
         
            +
                  STDOUT << '|'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  RubyProf.start
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                config.around :each do |example|
         
     | 
| 
      
 18 
     | 
    
         
            +
                  STDOUT << '.'
         
     | 
| 
      
 19 
     | 
    
         
            +
                  RubyProf.resume do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    example.run
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
                config.after :suite do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  result = RubyProf.stop
         
     | 
| 
      
 26 
     | 
    
         
            +
                  result.eliminate_methods!([/RSpec::Matchers#.*?/])
         
     | 
| 
      
 27 
     | 
    
         
            +
                  printer = RubyProf::MultiPrinter.new(result)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  printer.print(:path => 'report/profile', :profile => "profile")
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            # Requires supporting files with custom matchers and macros, etc,
         
     | 
| 
      
 34 
     | 
    
         
            +
            # in ./support/ and its subdirectories.
         
     | 
| 
      
 35 
     | 
    
         
            +
            Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,110 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: order_tree
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.2
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Stephen Prater
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2011-07-25 00:00:00.000000000 -05:00
         
     | 
| 
      
 13 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 15 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 17 
     | 
    
         
            +
              requirement: &3691310 !ruby/object:Gem::Requirement
         
     | 
| 
      
 18 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 19 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 20 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 21 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 22 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 23 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 24 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 25 
     | 
    
         
            +
              version_requirements: *3691310
         
     | 
| 
      
 26 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 27 
     | 
    
         
            +
              name: simplecov
         
     | 
| 
      
 28 
     | 
    
         
            +
              requirement: &3691090 !ruby/object:Gem::Requirement
         
     | 
| 
      
 29 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: *3691090
         
     | 
| 
      
 37 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 38 
     | 
    
         
            +
              name: ruby-prof
         
     | 
| 
      
 39 
     | 
    
         
            +
              requirement: &3690870 !ruby/object:Gem::Requirement
         
     | 
| 
      
 40 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 41 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 42 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 43 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 44 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 45 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 46 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 47 
     | 
    
         
            +
              version_requirements: *3690870
         
     | 
| 
      
 48 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 49 
     | 
    
         
            +
              name: ruby-debug19
         
     | 
| 
      
 50 
     | 
    
         
            +
              requirement: &3690650 !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 52 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 53 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 54 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 55 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 56 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 57 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 58 
     | 
    
         
            +
              version_requirements: *3690650
         
     | 
| 
      
 59 
     | 
    
         
            +
            description: Use OrderTree when you need both insertion order access and nested hash
         
     | 
| 
      
 60 
     | 
    
         
            +
              path style access
         
     | 
| 
      
 61 
     | 
    
         
            +
            email:
         
     | 
| 
      
 62 
     | 
    
         
            +
            - stephenp@agrussell.com
         
     | 
| 
      
 63 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 64 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 65 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 66 
     | 
    
         
            +
            files:
         
     | 
| 
      
 67 
     | 
    
         
            +
            - .DS_Store
         
     | 
| 
      
 68 
     | 
    
         
            +
            - .gitignore
         
     | 
| 
      
 69 
     | 
    
         
            +
            - .yardoc/checksums
         
     | 
| 
      
 70 
     | 
    
         
            +
            - .yardoc/objects/root.dat
         
     | 
| 
      
 71 
     | 
    
         
            +
            - .yardoc/proxy_types
         
     | 
| 
      
 72 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 73 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 74 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 75 
     | 
    
         
            +
            - lib/order_tree.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - lib/order_tree/order_tree.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/order_tree/order_tree_node.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/order_tree/unique_proxy.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/order_tree/version.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - order_tree.gemspec
         
     | 
| 
      
 81 
     | 
    
         
            +
            - spec/order_tree_spec.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 84 
     | 
    
         
            +
            homepage: http://github.com/stephenprater/order_tree
         
     | 
| 
      
 85 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 86 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 87 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 88 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 90 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 91 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 93 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 94 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 95 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 96 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 97 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 98 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 99 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 100 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 101 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 102 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 103 
     | 
    
         
            +
            rubyforge_project: order_tree
         
     | 
| 
      
 104 
     | 
    
         
            +
            rubygems_version: 1.5.2
         
     | 
| 
      
 105 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 106 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 107 
     | 
    
         
            +
            summary: An unbalanced tree / nested hash which remember insertion order
         
     | 
| 
      
 108 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 109 
     | 
    
         
            +
            - spec/order_tree_spec.rb
         
     | 
| 
      
 110 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     |