rspreadsheet 0.2.14 → 0.2.15
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.
- checksums.yaml +4 -4
 - data/.travis.yml +2 -0
 - data/lib/helpers/class_extensions.rb +39 -95
 - data/lib/rspreadsheet/cell.rb +3 -5
 - data/lib/rspreadsheet/row.rb +349 -0
 - data/lib/rspreadsheet/version.rb +1 -1
 - data/lib/rspreadsheet/workbook.rb +17 -11
 - data/lib/rspreadsheet/worksheet.rb +0 -1
 - data/lib/rspreadsheet/xml_tied.rb +0 -4
 - data/spec/io_spec.rb +38 -0
 - data/spec/rspreadsheet_spec.rb +1 -21
 - data/spec/testfile1.ods +0 -0
 - data/spec/worksheet_spec.rb +0 -1
 - metadata +5 -5
 - data/spec/class_extensions_spec.rb +0 -46
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 8c4d7239e35070d3406af3f5c7aadb872d5c0038
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: e06d7243078d7531984714f29ed403ce62fcc9df
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: dfe7532c19164f3f96611793df3eb75e2c5d67c9c3763cfaee72e88f1e060ec54d9c0978c3e59183520ddc05f0ab5a88d09f8e5e03d15fc4397de5a78740c81f
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: f84bbe8045dfe515ac18e50df5a7482e7e6ba0282b57ba2f1ffa50991d3aec3b45a60c7080d7183a867a3839bd7f639a801b0b7e90b9d7aec9a1a59ab1a5fa34
         
     | 
    
        data/.travis.yml
    CHANGED
    
    
| 
         @@ -1,105 +1,49 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              module ClassExtensions
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
                refine Array do
         
     | 
| 
       6 
     | 
    
         
            -
                  def sum(identity = 0, &block)
         
     | 
| 
       7 
     | 
    
         
            -
                    if block_given?
         
     | 
| 
       8 
     | 
    
         
            -
                      map(&block).sum(identity)
         
     | 
| 
       9 
     | 
    
         
            -
                    else
         
     | 
| 
       10 
     | 
    
         
            -
                      inject(0){ |sum, element| sum.to_f + element.to_f } || identity
         
     | 
| 
       11 
     | 
    
         
            -
                    end
         
     | 
| 
       12 
     | 
    
         
            -
                  end
         
     | 
| 
       13 
     | 
    
         
            -
                end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                refine LibXML::XML::Node do
         
     | 
| 
       16 
     | 
    
         
            -
                  def ==(node2)  
         
     | 
| 
       17 
     | 
    
         
            -
                    self.simplification_of?(node2) and node2.simplification_of?(self)
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
                  # if node2 contains at least all that I do
         
     | 
| 
       20 
     | 
    
         
            -
                  def simplification_of?(node2)
         
     | 
| 
       21 
     | 
    
         
            -
                    first_diff(node2).nil?
         
     | 
| 
       22 
     | 
    
         
            -
                  end
         
     | 
| 
       23 
     | 
    
         
            -
                  # return first difference where self has something more than node2 does
         
     | 
| 
       24 
     | 
    
         
            -
                  def first_diff(node2)
         
     | 
| 
       25 
     | 
    
         
            -
                    where = self.path.split('/').last
         
     | 
| 
       26 
     | 
    
         
            -
                    
         
     | 
| 
       27 
     | 
    
         
            -
                    return "#{where}> Equivalent node does not exist: #{self.name} != NOTHING" if node2.nil?
         
     | 
| 
       28 
     | 
    
         
            -
                    return "#{where}> Names are different: #{self.name} != #{node2.name}" if (self.name != node2.name)
         
     | 
| 
       29 
     | 
    
         
            -
                    self.attributes.each do |attr|
         
     | 
| 
       30 
     | 
    
         
            -
                      return "#{where}> Attribute #{attr} have diffent values: #{attr.value} != #{node2.attributes[attr.name]}" unless node2.attributes[attr.name] == attr.value
         
     | 
| 
       31 
     | 
    
         
            -
                    end
         
     | 
| 
       32 
     | 
    
         
            -
                    
         
     | 
| 
       33 
     | 
    
         
            -
                    elems1 = self.elements
         
     | 
| 
       34 
     | 
    
         
            -
                    elems2 = node2.elements
         
     | 
| 
       35 
     | 
    
         
            -
                #     return "#{where}> elements have different number of subelements #{elems1.length} !=  #{elems2.length}" if (elems1.length != elems2.length) 
         
     | 
| 
       36 
     | 
    
         
            -
                    elems1.length.times do |i|
         
     | 
| 
       37 
     | 
    
         
            -
                      if (elems1[i].node_type_name == 'text') && ((elems1[i].to_s != elems2[i].to_s) )
         
     | 
| 
       38 
     | 
    
         
            -
                        return  "#{where}> #{i+1}th text subelements are different: #{elems1[i].to_s} != #{elems2[i].to_s}"
         
     | 
| 
       39 
     | 
    
         
            -
                      elsif (elems1[i].node_type_name == 'element') && (!elems1[i].simplification_of?(elems2[i]))
         
     | 
| 
       40 
     | 
    
         
            -
                        return "#{where}/[#{i+1}]#{elems1[i].first_diff(elems2[i])}"
         
     | 
| 
       41 
     | 
    
         
            -
                      end
         
     | 
| 
       42 
     | 
    
         
            -
                    end
         
     | 
| 
       43 
     | 
    
         
            -
                      
         
     | 
| 
       44 
     | 
    
         
            -
                    return nil
         
     | 
| 
       45 
     | 
    
         
            -
                  end
         
     | 
| 
       46 
     | 
    
         
            -
                  def elements
         
     | 
| 
       47 
     | 
    
         
            -
                    result = []
         
     | 
| 
       48 
     | 
    
         
            -
                    each_element { |e| result << e }
         
     | 
| 
       49 
     | 
    
         
            -
                    return result
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
      
 1 
     | 
    
         
            +
            # @private
         
     | 
| 
       51 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            class LibXML::XML::Node
         
     | 
| 
      
 4 
     | 
    
         
            +
              def elements
         
     | 
| 
      
 5 
     | 
    
         
            +
                result = []
         
     | 
| 
      
 6 
     | 
    
         
            +
                each_element { |e| result << e }
         
     | 
| 
      
 7 
     | 
    
         
            +
                return result
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              # if node2 contains at least all that I do
         
     | 
| 
      
 10 
     | 
    
         
            +
              def simplification_of?(node2)
         
     | 
| 
      
 11 
     | 
    
         
            +
                first_diff(node2).nil?
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              # return first difference where self has something more than node2 does
         
     | 
| 
      
 14 
     | 
    
         
            +
              def first_diff(node2)
         
     | 
| 
      
 15 
     | 
    
         
            +
                where = self.path.split('/').last
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                return "#{where}> Equivalent node does not exist: #{self.name} != NOTHING" if node2.nil?
         
     | 
| 
      
 18 
     | 
    
         
            +
                return "#{where}> Names are different: #{self.name} != #{node2.name}" if (self.name != node2.name)
         
     | 
| 
      
 19 
     | 
    
         
            +
                self.attributes.each do |attr|
         
     | 
| 
      
 20 
     | 
    
         
            +
                  return "#{where}> Attribute #{attr} have diffent values: #{attr.value} != #{node2.attributes[attr.name]}" unless node2.attributes[attr.name] == attr.value
         
     | 
| 
       52 
21 
     | 
    
         
             
                end
         
     | 
| 
       53 
22 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                    inject(0){ |sum, element| sum.to_f + element.to_f } || identity
         
     | 
| 
      
 23 
     | 
    
         
            +
                elems1 = self.elements
         
     | 
| 
      
 24 
     | 
    
         
            +
                elems2 = node2.elements
         
     | 
| 
      
 25 
     | 
    
         
            +
            #     return "#{where}> elements have different number of subelements #{elems1.length} !=  #{elems2.length}" if (elems1.length != elems2.length) 
         
     | 
| 
      
 26 
     | 
    
         
            +
                elems1.length.times do |i|
         
     | 
| 
      
 27 
     | 
    
         
            +
                  if (elems1[i].node_type_name == 'text') && ((elems1[i].to_s != elems2[i].to_s) )
         
     | 
| 
      
 28 
     | 
    
         
            +
                    return  "#{where}> #{i+1}th text subelements are different: #{elems1[i].to_s} != #{elems2[i].to_s}"
         
     | 
| 
      
 29 
     | 
    
         
            +
                  elsif (elems1[i].node_type_name == 'element') && (!elems1[i].simplification_of?(elems2[i]))
         
     | 
| 
      
 30 
     | 
    
         
            +
                    return "#{where}/[#{i+1}]#{elems1[i].first_diff(elems2[i])}"
         
     | 
| 
       63 
31 
     | 
    
         
             
                  end
         
     | 
| 
       64 
32 
     | 
    
         
             
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                   
         
     | 
| 
      
 34 
     | 
    
         
            +
                return nil
         
     | 
| 
       65 
35 
     | 
    
         
             
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              def equals?(node2)  #TODO redefine == with this
         
     | 
| 
      
 37 
     | 
    
         
            +
                self.simplification_of?(node2) and node2.simplification_of?(self)
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
       66 
40 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                 
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                  first_diff(node2).nil?
         
     | 
| 
      
 41 
     | 
    
         
            +
            class Array
         
     | 
| 
      
 42 
     | 
    
         
            +
              def sum(identity = 0, &block)
         
     | 
| 
      
 43 
     | 
    
         
            +
                if block_given?
         
     | 
| 
      
 44 
     | 
    
         
            +
                  map(&block).sum(identity)
         
     | 
| 
      
 45 
     | 
    
         
            +
                else
         
     | 
| 
      
 46 
     | 
    
         
            +
                  inject(0){ |sum, element| sum.to_f + element.to_f } || identity
         
     | 
| 
       74 
47 
     | 
    
         
             
                end
         
     | 
| 
       75 
     | 
    
         
            -
                # return first difference where self has something more than node2 does
         
     | 
| 
       76 
     | 
    
         
            -
                def first_diff(node2)
         
     | 
| 
       77 
     | 
    
         
            -
                  where = self.path.split('/').last
         
     | 
| 
       78 
     | 
    
         
            -
                  
         
     | 
| 
       79 
     | 
    
         
            -
                  return "#{where}> Equivalent node does not exist: #{self.name} != NOTHING" if node2.nil?
         
     | 
| 
       80 
     | 
    
         
            -
                  return "#{where}> Names are different: #{self.name} != #{node2.name}" if (self.name != node2.name)
         
     | 
| 
       81 
     | 
    
         
            -
                  self.attributes.each do |attr|
         
     | 
| 
       82 
     | 
    
         
            -
                    return "#{where}> Attribute #{attr} have diffent values: #{attr.value} != #{node2.attributes[attr.name]}" unless node2.attributes[attr.name] == attr.value
         
     | 
| 
       83 
     | 
    
         
            -
                  end
         
     | 
| 
       84 
     | 
    
         
            -
                  
         
     | 
| 
       85 
     | 
    
         
            -
                  elems1 = self.elements
         
     | 
| 
       86 
     | 
    
         
            -
                  elems2 = node2.elements
         
     | 
| 
       87 
     | 
    
         
            -
              #     return "#{where}> elements have different number of subelements #{elems1.length} !=  #{elems2.length}" if (elems1.length != elems2.length) 
         
     | 
| 
       88 
     | 
    
         
            -
                  elems1.length.times do |i|
         
     | 
| 
       89 
     | 
    
         
            -
                    if (elems1[i].node_type_name == 'text') && ((elems1[i].to_s != elems2[i].to_s) )
         
     | 
| 
       90 
     | 
    
         
            -
                      return  "#{where}> #{i+1}th text subelements are different: #{elems1[i].to_s} != #{elems2[i].to_s}"
         
     | 
| 
       91 
     | 
    
         
            -
                    elsif (elems1[i].node_type_name == 'element') && (!elems1[i].simplification_of?(elems2[i]))
         
     | 
| 
       92 
     | 
    
         
            -
                      return "#{where}/[#{i+1}]#{elems1[i].first_diff(elems2[i])}"
         
     | 
| 
       93 
     | 
    
         
            -
                    end
         
     | 
| 
       94 
     | 
    
         
            -
                  end
         
     | 
| 
       95 
     | 
    
         
            -
                    
         
     | 
| 
       96 
     | 
    
         
            -
                  return nil
         
     | 
| 
       97 
     | 
    
         
            -
                end
         
     | 
| 
       98 
     | 
    
         
            -
                def elements
         
     | 
| 
       99 
     | 
    
         
            -
                  result = []
         
     | 
| 
       100 
     | 
    
         
            -
                  each_element { |e| result << e }
         
     | 
| 
       101 
     | 
    
         
            -
                  return result
         
     | 
| 
       102 
     | 
    
         
            -
                end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
48 
     | 
    
         
             
              end
         
     | 
| 
       105 
49 
     | 
    
         
             
            end
         
     | 
    
        data/lib/rspreadsheet/cell.rb
    CHANGED
    
    | 
         @@ -7,10 +7,8 @@ require 'rspreadsheet/xml_tied' 
     | 
|
| 
       7 
7 
     | 
    
         
             
            require 'date'
         
     | 
| 
       8 
8 
     | 
    
         
             
            require 'bigdecimal'
         
     | 
| 
       9 
9 
     | 
    
         
             
            require 'bigdecimal/util' # for to_d method
         
     | 
| 
       10 
     | 
    
         
            -
            require 'helpers/class_extensions'
         
     | 
| 
       11 
10 
     | 
    
         | 
| 
       12 
11 
     | 
    
         
             
            module Rspreadsheet
         
     | 
| 
       13 
     | 
    
         
            -
            using ClassExtensions if RUBY_VERSION > '2.1'
         
     | 
| 
       14 
12 
     | 
    
         | 
| 
       15 
13 
     | 
    
         
             
            ###
         
     | 
| 
       16 
14 
     | 
    
         
             
            # Represents a cell in spreadsheet which has coordinates, contains value, formula and can be formated.
         
     | 
| 
         @@ -42,7 +40,7 @@ class Cell < XMLTiedItem 
     | 
|
| 
       42 
40 
     | 
    
         
             
              def coordinates; [rowi,coli] end
         
     | 
| 
       43 
41 
     | 
    
         
             
              def to_s; value.to_s end
         
     | 
| 
       44 
42 
     | 
    
         
             
              def valuexml; self.valuexmlnode.andand.inner_xml end
         
     | 
| 
       45 
     | 
    
         
            -
              def valuexmlnode; self.xmlnode. 
     | 
| 
      
 43 
     | 
    
         
            +
              def valuexmlnode; self.xmlnode.children.first end
         
     | 
| 
       46 
44 
     | 
    
         
             
              # use this to find node in cell xml. ex. xmlfind('.//text:a') finds all link nodes
         
     | 
| 
       47 
45 
     | 
    
         
             
              def valuexmlfindall(path)
         
     | 
| 
       48 
46 
     | 
    
         
             
                valuexmlnode.nil? ? [] : valuexmlnode.find(path)
         
     | 
| 
         @@ -152,10 +150,10 @@ class Cell < XMLTiedItem 
     | 
|
| 
       152 
150 
     | 
    
         
             
                    when 'N/A' then :unassigned
         
     | 
| 
       153 
151 
     | 
    
         
             
                    when 'currency' then :currency
         
     | 
| 
       154 
152 
     | 
    
         
             
                    else 
         
     | 
| 
       155 
     | 
    
         
            -
                      if xmlnode. 
     | 
| 
      
 153 
     | 
    
         
            +
                      if xmlnode.children.size == 0
         
     | 
| 
       156 
154 
     | 
    
         
             
                        nil
         
     | 
| 
       157 
155 
     | 
    
         
             
                      else 
         
     | 
| 
       158 
     | 
    
         
            -
                        raise "Unknown type at #{coordinates.to_s} from #{xmlnode.to_s} /  
     | 
| 
      
 156 
     | 
    
         
            +
                        raise "Unknown type at #{coordinates.to_s} from #{xmlnode.to_s} / children size=#{xmlnode.children.size.to_s} / type=#{xmlnode.attributes['value-type'].to_s}"
         
     | 
| 
       159 
157 
     | 
    
         
             
                      end
         
     | 
| 
       160 
158 
     | 
    
         
             
                  end
         
     | 
| 
       161 
159 
     | 
    
         | 
    
        data/lib/rspreadsheet/row.rb
    CHANGED
    
    | 
         @@ -120,4 +120,353 @@ class Row < XMLTiedItem 
     | 
|
| 
       120 
120 
     | 
    
         
             
              def set_index(value); @rowi=value end      
         
     | 
| 
       121 
121 
     | 
    
         
             
            end
         
     | 
| 
       122 
122 
     | 
    
         | 
| 
      
 123 
     | 
    
         
            +
            # class Row
         
     | 
| 
      
 124 
     | 
    
         
            +
            #   def initialize
         
     | 
| 
      
 125 
     | 
    
         
            +
            #     @readonly = :unknown
         
     | 
| 
      
 126 
     | 
    
         
            +
            #     @cells = {}
         
     | 
| 
      
 127 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 128 
     | 
    
         
            +
            #   def worksheet; @parent_array.worksheet end
         
     | 
| 
      
 129 
     | 
    
         
            +
            #   def parent_array; @parent_array end  # for debug only
         
     | 
| 
      
 130 
     | 
    
         
            +
            #   def used_col_range; 1..first_unused_column_index-1  end
         
     | 
| 
      
 131 
     | 
    
         
            +
            #   def used_range; used_col_range  end
         
     | 
| 
      
 132 
     | 
    
         
            +
            #   def first_unused_column_index; raise 'this should be redefined in subclasses' end
         
     | 
| 
      
 133 
     | 
    
         
            +
            # end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
              
         
     | 
| 
      
 136 
     | 
    
         
            +
            #  -------------------------- 
         
     | 
| 
      
 137 
     | 
    
         
            +
              
         
     | 
| 
      
 138 
     | 
    
         
            +
              
         
     | 
| 
      
 139 
     | 
    
         
            +
            # # XmlTiedArrayItemGroup is internal representation of repeated items in XmlTiedArray.
         
     | 
| 
      
 140 
     | 
    
         
            +
            # class XmlTiedArrayItemGroup
         
     | 
| 
      
 141 
     | 
    
         
            +
            # #   extend Forwardable
         
     | 
| 
      
 142 
     | 
    
         
            +
            # #   delegate [:normalize ] => :@row_group
         
     | 
| 
      
 143 
     | 
    
         
            +
            # 
         
     | 
| 
      
 144 
     | 
    
         
            +
            #   def normalize; @rowgroup.normalize  end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
            # end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
            # array which synchronizes with xml structure and reflects. number-xxx-repeated attributes
         
     | 
| 
      
 149 
     | 
    
         
            +
            # also caches returned objects for indexes.
         
     | 
| 
      
 150 
     | 
    
         
            +
            # options must contain
         
     | 
| 
      
 151 
     | 
    
         
            +
            #   :xml_items, :xml_repeated_attribute, :object_type
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            # class XmlTiedArray < Array
         
     | 
| 
      
 154 
     | 
    
         
            +
            #   def initialize(axmlnode, options={}) # TODO get rid of XmlTiedArray
         
     | 
| 
      
 155 
     | 
    
         
            +
            #     @xmlnode = axmlnode
         
     | 
| 
      
 156 
     | 
    
         
            +
            #     @options = options
         
     | 
| 
      
 157 
     | 
    
         
            +
            #     
         
     | 
| 
      
 158 
     | 
    
         
            +
            #     missing_options = [:xml_repeated_attribute,:xml_items_node_name,:object_type]-@options.keys
         
     | 
| 
      
 159 
     | 
    
         
            +
            #     raise "Some options missing (#{missing_options.inspect})" unless missing_options.empty?
         
     | 
| 
      
 160 
     | 
    
         
            +
            #     
         
     | 
| 
      
 161 
     | 
    
         
            +
            #     unless @xmlnode.nil?
         
     | 
| 
      
 162 
     | 
    
         
            +
            #       @xmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |group_source_node|
         
     | 
| 
      
 163 
     | 
    
         
            +
            #         self << parse_xml_to_group(group_source_node) # it is in @xmlnode so suffices to add object to @rowgroups
         
     | 
| 
      
 164 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 165 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 166 
     | 
    
         
            +
            #     @itemcache=Hash.new()
         
     | 
| 
      
 167 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 168 
     | 
    
         
            +
            #   def parse_xml_to_group(size_or_xmlnode) # parses xml to new RowGroup which can be added at the end
         
     | 
| 
      
 169 
     | 
    
         
            +
            #     # reading params
         
     | 
| 
      
 170 
     | 
    
         
            +
            #     if size_or_xmlnode.kind_of? LibXML::XML::Node
         
     | 
| 
      
 171 
     | 
    
         
            +
            #       size = (size_or_xmlnode[@options[:xml_repeated_attribute]] || 1).to_i
         
     | 
| 
      
 172 
     | 
    
         
            +
            #       node = size_or_xmlnode
         
     | 
| 
      
 173 
     | 
    
         
            +
            #     elsif size_or_xmlnode.to_i>0
         
     | 
| 
      
 174 
     | 
    
         
            +
            #       size = size_or_xmlnode.to_i
         
     | 
| 
      
 175 
     | 
    
         
            +
            #       node = nil
         
     | 
| 
      
 176 
     | 
    
         
            +
            #     else
         
     | 
| 
      
 177 
     | 
    
         
            +
            #       return nil
         
     | 
| 
      
 178 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 179 
     | 
    
         
            +
            #     index = first_unused_index
         
     | 
| 
      
 180 
     | 
    
         
            +
            #     # construct result
         
     | 
| 
      
 181 
     | 
    
         
            +
            #     Rspreadsheet::XmlTiedArrayItemGroup.new(self,index..index+size-1,node)
         
     | 
| 
      
 182 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 183 
     | 
    
         
            +
            #   def add_item_group(size_or_xmlnode)
         
     | 
| 
      
 184 
     | 
    
         
            +
            #     result = parse_xml_to_group(size_or_xmlnode)
         
     | 
| 
      
 185 
     | 
    
         
            +
            #     self << result
         
     | 
| 
      
 186 
     | 
    
         
            +
            #     @xmlnode << result.xmlnode
         
     | 
| 
      
 187 
     | 
    
         
            +
            #     result
         
     | 
| 
      
 188 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 189 
     | 
    
         
            +
            #   def first_unused_index
         
     | 
| 
      
 190 
     | 
    
         
            +
            #     empty? ? 1 : last.range.end+1
         
     | 
| 
      
 191 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 192 
     | 
    
         
            +
            #   # prolonges the RowArray to cantain rowi and returns it
         
     | 
| 
      
 193 
     | 
    
         
            +
            #   def detach_of_bound_item(index)
         
     | 
| 
      
 194 
     | 
    
         
            +
            #     fill_row_group_size = index-first_unused_index
         
     | 
| 
      
 195 
     | 
    
         
            +
            #     if fill_row_group_size>0
         
     | 
| 
      
 196 
     | 
    
         
            +
            #       add_item_group(fill_row_group_size) 
         
     | 
| 
      
 197 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 198 
     | 
    
         
            +
            #     add_item_group(1)
         
     | 
| 
      
 199 
     | 
    
         
            +
            #     get_item(index)   # aby se odpoved nacacheovala
         
     | 
| 
      
 200 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 201 
     | 
    
         
            +
            #   def get_item_group(index)
         
     | 
| 
      
 202 
     | 
    
         
            +
            #     find{ |item_group| item_group.range.cover?(index) }
         
     | 
| 
      
 203 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 204 
     | 
    
         
            +
            #   def detach_item(index); get_item(index) end # TODO předělat do lazy podoby, kdy tohle nebude stejny
         
     | 
| 
      
 205 
     | 
    
         
            +
            #   def get_item(index)
         
     | 
| 
      
 206 
     | 
    
         
            +
            #     if index>= first_unused_index
         
     | 
| 
      
 207 
     | 
    
         
            +
            #       nil
         
     | 
| 
      
 208 
     | 
    
         
            +
            #     else
         
     | 
| 
      
 209 
     | 
    
         
            +
            #       @itemcache[index] ||= Rspreadsheet::XmlTiedArrayItem.new(self,index)
         
     | 
| 
      
 210 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 211 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 212 
     | 
    
         
            +
            #   # This detaches item index from the group and perhaps splits the RowGroup
         
     | 
| 
      
 213 
     | 
    
         
            +
            #   # into two pieces. This makes the row individually editable.
         
     | 
| 
      
 214 
     | 
    
         
            +
            #   def detach(index)
         
     | 
| 
      
 215 
     | 
    
         
            +
            #     group_index = get_group_index(index)
         
     | 
| 
      
 216 
     | 
    
         
            +
            #     item_group = self[group_index]
         
     | 
| 
      
 217 
     | 
    
         
            +
            #     range = item_group.range
         
     | 
| 
      
 218 
     | 
    
         
            +
            #     return self if range==(index..index)
         
     | 
| 
      
 219 
     | 
    
         
            +
            # 
         
     | 
| 
      
 220 
     | 
    
         
            +
            #     # prepare new components
         
     | 
| 
      
 221 
     | 
    
         
            +
            #     replaceby = []
         
     | 
| 
      
 222 
     | 
    
         
            +
            #     replaceby << RowGroup.new(self,range.begin..index-1)
         
     | 
| 
      
 223 
     | 
    
         
            +
            #     replaceby << (result = SingleRow.new(self,index))
         
     | 
| 
      
 224 
     | 
    
         
            +
            #     replaceby << RowGroup.new(self,index+1..range.end)
         
     | 
| 
      
 225 
     | 
    
         
            +
            #     
         
     | 
| 
      
 226 
     | 
    
         
            +
            #     # put original range somewhere in replaceby and shorten it
         
     | 
| 
      
 227 
     | 
    
         
            +
            #     
         
     | 
| 
      
 228 
     | 
    
         
            +
            #     if index>range.begin
         
     | 
| 
      
 229 
     | 
    
         
            +
            #       replaceby[0] = item_group
         
     | 
| 
      
 230 
     | 
    
         
            +
            #       item_group.range = range.begin..index-1
         
     | 
| 
      
 231 
     | 
    
         
            +
            #     else
         
     | 
| 
      
 232 
     | 
    
         
            +
            #       replaceby[2] = item_group
         
     | 
| 
      
 233 
     | 
    
         
            +
            #       item_group.range = index+1..range.end
         
     | 
| 
      
 234 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 235 
     | 
    
         
            +
            #     
         
     | 
| 
      
 236 
     | 
    
         
            +
            #     # normalize and delete empty parts
         
     | 
| 
      
 237 
     | 
    
         
            +
            #     replaceby = replaceby.map(&:normalize).compact
         
     | 
| 
      
 238 
     | 
    
         
            +
            #     
         
     | 
| 
      
 239 
     | 
    
         
            +
            #     # do the replacement in xml
         
     | 
| 
      
 240 
     | 
    
         
            +
            #     marker = LibXML::XML::Node.new('temporarymarker')
         
     | 
| 
      
 241 
     | 
    
         
            +
            #     item_group.xmlnode.next = marker
         
     | 
| 
      
 242 
     | 
    
         
            +
            #     item_group.xmlnode.remove!
         
     | 
| 
      
 243 
     | 
    
         
            +
            #     replaceby.each{ |rg| 
         
     | 
| 
      
 244 
     | 
    
         
            +
            #       marker.prev = rg.xmlnode
         
     | 
| 
      
 245 
     | 
    
         
            +
            #     } 
         
     | 
| 
      
 246 
     | 
    
         
            +
            #     marker.remove!
         
     | 
| 
      
 247 
     | 
    
         
            +
            #     
         
     | 
| 
      
 248 
     | 
    
         
            +
            #     # do the replacement in array
         
     | 
| 
      
 249 
     | 
    
         
            +
            #     self[group_index..group_index]=replaceby
         
     | 
| 
      
 250 
     | 
    
         
            +
            #     result
         
     | 
| 
      
 251 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 252 
     | 
    
         
            +
            #   private
         
     | 
| 
      
 253 
     | 
    
         
            +
            #   def get_group_index(index)
         
     | 
| 
      
 254 
     | 
    
         
            +
            #     self.find_index{ |rowgroup| rowgroup.range.cover?(index) }
         
     | 
| 
      
 255 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 256 
     | 
    
         
            +
            # end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
            # class XmlTiedArrayItem
         
     | 
| 
      
 259 
     | 
    
         
            +
            #   attr_reader :index
         
     | 
| 
      
 260 
     | 
    
         
            +
            #   def initialize(aarray,aindex)
         
     | 
| 
      
 261 
     | 
    
         
            +
            #     @array = aarray
         
     | 
| 
      
 262 
     | 
    
         
            +
            #     @index = aindex
         
     | 
| 
      
 263 
     | 
    
         
            +
            #     if self.virtual?
         
     | 
| 
      
 264 
     | 
    
         
            +
            #       @object = nil
         
     | 
| 
      
 265 
     | 
    
         
            +
            #     else
         
     | 
| 
      
 266 
     | 
    
         
            +
            #       @object = @array.options[:object_type].new(group.xmlnode)
         
     | 
| 
      
 267 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 268 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 269 
     | 
    
         
            +
            #   def group; @array.get_item_group(index) end
         
     | 
| 
      
 270 
     | 
    
         
            +
            #   def repeated?; group.repeated? end
         
     | 
| 
      
 271 
     | 
    
         
            +
            #   def virtual?; ! self.repeated? end
         
     | 
| 
      
 272 
     | 
    
         
            +
            #   def array
         
     | 
| 
      
 273 
     | 
    
         
            +
            #     raise 'Group empty' if @group.nil? 
         
     | 
| 
      
 274 
     | 
    
         
            +
            #     @array
         
     | 
| 
      
 275 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 276 
     | 
    
         
            +
            # end
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
            # class RowArray < XmlTiedArray
         
     | 
| 
      
 279 
     | 
    
         
            +
            #   attr_reader :row_array_cache
         
     | 
| 
      
 280 
     | 
    
         
            +
            #   def initialize(aworksheet,aworksheet_node)
         
     | 
| 
      
 281 
     | 
    
         
            +
            #     @worksheet = aworksheet
         
     | 
| 
      
 282 
     | 
    
         
            +
            #     @row_array_cache = Hash.new()
         
     | 
| 
      
 283 
     | 
    
         
            +
            #     super(aworksheet_node, :xml_items_node_name => 'table-row', :xml_repeated_attribute => xml_repeated_attribute, :object_type=>Row)
         
     | 
| 
      
 284 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 285 
     | 
    
         
            +
            #   def get_row(rowi)
         
     | 
| 
      
 286 
     | 
    
         
            +
            #     if @row_array_cache.has_key?(rowi)
         
     | 
| 
      
 287 
     | 
    
         
            +
            #       return @row_array_cache[rowi]
         
     | 
| 
      
 288 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 289 
     | 
    
         
            +
            #     item = self.get_item(rowi)
         
     | 
| 
      
 290 
     | 
    
         
            +
            #     @row_array_cache[rowi] = if item.nil?
         
     | 
| 
      
 291 
     | 
    
         
            +
            #       if rowi>0 then Rspreadsheet::UninitializedEmptyRow.new(self,rowi) else nil end
         
     | 
| 
      
 292 
     | 
    
         
            +
            #     else
         
     | 
| 
      
 293 
     | 
    
         
            +
            #       if item.repeated?
         
     | 
| 
      
 294 
     | 
    
         
            +
            # 	Rspreadsheet::MemberOfRowGroup.new(item.index, item.group.to_rowgroup)
         
     | 
| 
      
 295 
     | 
    
         
            +
            #       else
         
     | 
| 
      
 296 
     | 
    
         
            +
            # 	Rspreadsheet::SingleRow.new_from_rowgroup(item.group.to_rowgroup)
         
     | 
| 
      
 297 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 298 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 299 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 300 
     | 
    
         
            +
            #   # aliases
         
     | 
| 
      
 301 
     | 
    
         
            +
            #   def first_unused_row_index; first_unused_index end
         
     | 
| 
      
 302 
     | 
    
         
            +
            #   def worksheet; @worksheet end
         
     | 
| 
      
 303 
     | 
    
         
            +
            #   def detach_of_bound_row_group(index)
         
     | 
| 
      
 304 
     | 
    
         
            +
            #     super(index)
         
     | 
| 
      
 305 
     | 
    
         
            +
            #     return get_row(index)
         
     | 
| 
      
 306 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 307 
     | 
    
         
            +
            # end
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
            # class Row
         
     | 
| 
      
 310 
     | 
    
         
            +
            #   def initialize
         
     | 
| 
      
 311 
     | 
    
         
            +
            #     @readonly = :unknown
         
     | 
| 
      
 312 
     | 
    
         
            +
            #     @cells = {}
         
     | 
| 
      
 313 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 314 
     | 
    
         
            +
            #   def self.empty_row_node
         
     | 
| 
      
 315 
     | 
    
         
            +
            #     LibXML::XML::Node.new('table-row',nil, Tools.get_namespace('table'))
         
     | 
| 
      
 316 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 317 
     | 
    
         
            +
            #   def worksheet; @parent_array.worksheet end
         
     | 
| 
      
 318 
     | 
    
         
            +
            #   def parent_array; @parent_array end  # for debug only
         
     | 
| 
      
 319 
     | 
    
         
            +
            #   def used_col_range; 1..first_unused_column_index-1  end
         
     | 
| 
      
 320 
     | 
    
         
            +
            #   def used_range; used_col_range  end
         
     | 
| 
      
 321 
     | 
    
         
            +
            #   def first_unused_column_index; raise 'this should be redefined in subclasses' end
         
     | 
| 
      
 322 
     | 
    
         
            +
            #   def cells(coli)
         
     | 
| 
      
 323 
     | 
    
         
            +
            #     coli = coli.to_i
         
     | 
| 
      
 324 
     | 
    
         
            +
            #     return nil if coli.to_i<=0
         
     | 
| 
      
 325 
     | 
    
         
            +
            #     @cells[coli] ||= get_cell(coli)
         
     | 
| 
      
 326 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 327 
     | 
    
         
            +
            # end
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
      
 329 
     | 
    
         
            +
            # class RowWithXMLNode < Row
         
     | 
| 
      
 330 
     | 
    
         
            +
            #   attr_accessor :xmlnode
         
     | 
| 
      
 331 
     | 
    
         
            +
            #   def style_name=(value); Tools.set_ns_attribute(@xmlnode,'table','style-name',value)  end
         
     | 
| 
      
 332 
     | 
    
         
            +
            #   def get_cell(coli)
         
     | 
| 
      
 333 
     | 
    
         
            +
            #     Cell.new(self,coli,cellnodes(coli))
         
     | 
| 
      
 334 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 335 
     | 
    
         
            +
            #   def nonemptycells
         
     | 
| 
      
 336 
     | 
    
         
            +
            #     nonemptycellsindexes.collect{ |index| cells(index) }
         
     | 
| 
      
 337 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 338 
     | 
    
         
            +
            #   def nonemptycellsindexes
         
     | 
| 
      
 339 
     | 
    
         
            +
            #     used_col_range.to_a.select do |coli|
         
     | 
| 
      
 340 
     | 
    
         
            +
            #       cellnode = cellnodes(coli)
         
     | 
| 
      
 341 
     | 
    
         
            +
            #       !(cellnode.content.nil? or cellnode.content.empty? or cellnode.content =='') or
         
     | 
| 
      
 342 
     | 
    
         
            +
            #       !cellnode.attributes.to_a.reject{ |attr| attr.name == 'number-columns-repeated'}.empty?
         
     | 
| 
      
 343 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 344 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 345 
     | 
    
         
            +
            #   def cellnodes(coli)
         
     | 
| 
      
 346 
     | 
    
         
            +
            #     cellnode = nil
         
     | 
| 
      
 347 
     | 
    
         
            +
            #     while true 
         
     | 
| 
      
 348 
     | 
    
         
            +
            #       curr_coli=1
         
     | 
| 
      
 349 
     | 
    
         
            +
            #       cellnode = @xmlnode.elements.select{|n| n.name=='table-cell'}.find do |el|
         
     | 
| 
      
 350 
     | 
    
         
            +
            #         curr_coli += (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
         
     | 
| 
      
 351 
     | 
    
         
            +
            #         curr_coli > coli
         
     | 
| 
      
 352 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 353 
     | 
    
         
            +
            #       unless cellnode.nil? 
         
     | 
| 
      
 354 
     | 
    
         
            +
            #         return cellnode
         
     | 
| 
      
 355 
     | 
    
         
            +
            #       else
         
     | 
| 
      
 356 
     | 
    
         
            +
            #         add_cell
         
     | 
| 
      
 357 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 358 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 359 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 360 
     | 
    
         
            +
            #   def add_cell(repeated=1)
         
     | 
| 
      
 361 
     | 
    
         
            +
            #     cell = Cell.new(self,first_unused_column_index)
         
     | 
| 
      
 362 
     | 
    
         
            +
            #     Tools.set_ns_attribute(cell.xmlnode,'table','number-columns-repeated',repeated) if repeated>1
         
     | 
| 
      
 363 
     | 
    
         
            +
            #     @xmlnode << cell.xmlnode
         
     | 
| 
      
 364 
     | 
    
         
            +
            #     cell
         
     | 
| 
      
 365 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 366 
     | 
    
         
            +
            #   def first_unused_column_index
         
     | 
| 
      
 367 
     | 
    
         
            +
            #     1 + @xmlnode.elements.select{|n| n.name=='table-cell'}.reduce(0) do |sum, el|
         
     | 
| 
      
 368 
     | 
    
         
            +
            #       sum + (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
         
     | 
| 
      
 369 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 370 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 371 
     | 
    
         
            +
            # end
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
            # class RowGroup < RowWithXMLNode
         
     | 
| 
      
 374 
     | 
    
         
            +
            #   @readonly = :yes_always
         
     | 
| 
      
 375 
     | 
    
         
            +
            #   attr_reader :range
         
     | 
| 
      
 376 
     | 
    
         
            +
            #   attr_accessor :parent_array, :xmlnode
         
     | 
| 
      
 377 
     | 
    
         
            +
            #   def initialize(aparent_array,arange,axmlnode=nil)
         
     | 
| 
      
 378 
     | 
    
         
            +
            #     super()
         
     | 
| 
      
 379 
     | 
    
         
            +
            #     @parent_array = aparent_array
         
     | 
| 
      
 380 
     | 
    
         
            +
            #     @range = arange
         
     | 
| 
      
 381 
     | 
    
         
            +
            #     if axmlnode.nil?
         
     | 
| 
      
 382 
     | 
    
         
            +
            #       axmlnode = Row.empty_row_node
         
     | 
| 
      
 383 
     | 
    
         
            +
            #       Tools.set_ns_attribute(axmlnode,'table','number-rows-repeated',range.size) if range.size>1
         
     | 
| 
      
 384 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 385 
     | 
    
         
            +
            #     @xmlnode = axmlnode
         
     | 
| 
      
 386 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 387 
     | 
    
         
            +
            #   # returns SingleRow if size of range is 1 and nil if it is 0 or less
         
     | 
| 
      
 388 
     | 
    
         
            +
            #   def normalize
         
     | 
| 
      
 389 
     | 
    
         
            +
            #     case range.size
         
     | 
| 
      
 390 
     | 
    
         
            +
            #       when 2..Float::INFINITY then self
         
     | 
| 
      
 391 
     | 
    
         
            +
            #       when 1 then SingleRow.new_from_rowgroup(self)
         
     | 
| 
      
 392 
     | 
    
         
            +
            #       else nil
         
     | 
| 
      
 393 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 394 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 395 
     | 
    
         
            +
            #   def repeated;  range.size   end
         
     | 
| 
      
 396 
     | 
    
         
            +
            #   def repeated?; range.size>1 end
         
     | 
| 
      
 397 
     | 
    
         
            +
            #   def range=(arange)
         
     | 
| 
      
 398 
     | 
    
         
            +
            #     @range=arange
         
     | 
| 
      
 399 
     | 
    
         
            +
            #     Tools.set_ns_attribute(@xmlnode,'table','number-rows-repeated',range.size, 1)
         
     | 
| 
      
 400 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 401 
     | 
    
         
            +
            # end
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
            # class SingleRow < RowWithXMLNode
         
     | 
| 
      
 404 
     | 
    
         
            +
            #   @readonly = :no
         
     | 
| 
      
 405 
     | 
    
         
            +
            #   attr_accessor :xmlnode
         
     | 
| 
      
 406 
     | 
    
         
            +
            #   # index  Integer
         
     | 
| 
      
 407 
     | 
    
         
            +
            #   def initialize(aparent_array,aindex,axmlnode=nil)
         
     | 
| 
      
 408 
     | 
    
         
            +
            #     super()
         
     | 
| 
      
 409 
     | 
    
         
            +
            #     @parent_array = aparent_array
         
     | 
| 
      
 410 
     | 
    
         
            +
            #     @index = aindex
         
     | 
| 
      
 411 
     | 
    
         
            +
            #     if axmlnode.nil?
         
     | 
| 
      
 412 
     | 
    
         
            +
            #       axmlnode = Row.empty_row_node
         
     | 
| 
      
 413 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 414 
     | 
    
         
            +
            #     @xmlnode = axmlnode
         
     | 
| 
      
 415 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 416 
     | 
    
         
            +
            #   def self.new_from_rowgroup(rg)
         
     | 
| 
      
 417 
     | 
    
         
            +
            #     anode = rg.xmlnode
         
     | 
| 
      
 418 
     | 
    
         
            +
            #     Tools.remove_ns_attribute(anode,'table','number-rows-repeated')
         
     | 
| 
      
 419 
     | 
    
         
            +
            #     SingleRow.new(rg.parent_array,rg.range.begin,anode)
         
     | 
| 
      
 420 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 421 
     | 
    
         
            +
            #   def normalize; self end
         
     | 
| 
      
 422 
     | 
    
         
            +
            #   def repeated?; false end
         
     | 
| 
      
 423 
     | 
    
         
            +
            #   def repeated; 1 end
         
     | 
| 
      
 424 
     | 
    
         
            +
            #   def range; (@index..@index) end
         
     | 
| 
      
 425 
     | 
    
         
            +
            #   def detach; self end
         
     | 
| 
      
 426 
     | 
    
         
            +
            #   def row; @index end
         
     | 
| 
      
 427 
     | 
    
         
            +
            #   def still_out_of_used_range?; false end
         
     | 
| 
      
 428 
     | 
    
         
            +
            # end
         
     | 
| 
      
 429 
     | 
    
         
            +
             
     | 
| 
      
 430 
     | 
    
         
            +
            # class LazyDetachableRow < Row
         
     | 
| 
      
 431 
     | 
    
         
            +
            #   @readonly = :yes_but_detachable
         
     | 
| 
      
 432 
     | 
    
         
            +
            #   def initialize(rowi)
         
     | 
| 
      
 433 
     | 
    
         
            +
            #     super()
         
     | 
| 
      
 434 
     | 
    
         
            +
            #     @index = rowi.to_i
         
     | 
| 
      
 435 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 436 
     | 
    
         
            +
            #   def add_cell; detach.add_cell end
         
     | 
| 
      
 437 
     | 
    
         
            +
            #   def style_name=(value); detach.style_name=value end
         
     | 
| 
      
 438 
     | 
    
         
            +
            #   def row; @index end
         
     | 
| 
      
 439 
     | 
    
         
            +
            # end
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
            # ## there are not data in this object, they are taken from RowGroup, but this is only readonly
         
     | 
| 
      
 442 
     | 
    
         
            +
            # class MemberOfRowGroup < LazyDetachableRow
         
     | 
| 
      
 443 
     | 
    
         
            +
            #   @readonly = :yes_but_detachable
         
     | 
| 
      
 444 
     | 
    
         
            +
            #   extend Forwardable
         
     | 
| 
      
 445 
     | 
    
         
            +
            #   delegate [:repeated?, :repeated, :xmlnode, :parent_array] => :@row_group
         
     | 
| 
      
 446 
     | 
    
         
            +
            #   attr_accessor :row_group # for dubugging
         
     | 
| 
      
 447 
     | 
    
         
            +
            # 
         
     | 
| 
      
 448 
     | 
    
         
            +
            #   # @index  Integer
         
     | 
| 
      
 449 
     | 
    
         
            +
            #   # @row_group   RepeatedRow
         
     | 
| 
      
 450 
     | 
    
         
            +
            #   def initialize(arowi,arow_group)
         
     | 
| 
      
 451 
     | 
    
         
            +
            #     super(arowi)
         
     | 
| 
      
 452 
     | 
    
         
            +
            #     @row_group = arow_group
         
     | 
| 
      
 453 
     | 
    
         
            +
            #     raise 'Wrong parameter given - class is '+@row_group.class.to_a unless @row_group.is_a? RowGroup
         
     | 
| 
      
 454 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 455 
     | 
    
         
            +
            #   def detach  # detaches MemberOfRowGroup from its RowGroup perhaps splitting RowGroup
         
     | 
| 
      
 456 
     | 
    
         
            +
            #     @row_group.parent_array.detach(@index)
         
     | 
| 
      
 457 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 458 
     | 
    
         
            +
            #   def get_cell(coli)
         
     | 
| 
      
 459 
     | 
    
         
            +
            #     c = Cell.new(self,coli,@row_group.cellnodes(coli))
         
     | 
| 
      
 460 
     | 
    
         
            +
            #     c.mode = :repeated
         
     | 
| 
      
 461 
     | 
    
         
            +
            #     c
         
     | 
| 
      
 462 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 463 
     | 
    
         
            +
            #   def first_unused_column_index
         
     | 
| 
      
 464 
     | 
    
         
            +
            #     @row_group.first_unused_column_index
         
     | 
| 
      
 465 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 466 
     | 
    
         
            +
            #   def nonemptycells
         
     | 
| 
      
 467 
     | 
    
         
            +
            #     @row_group.nonemptycellsindexes.collect{ |coli| cells(coli) }
         
     | 
| 
      
 468 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 469 
     | 
    
         
            +
            # end
         
     | 
| 
      
 470 
     | 
    
         
            +
             
     | 
| 
      
 471 
     | 
    
         
            +
             
     | 
| 
       123 
472 
     | 
    
         
             
            end
         
     | 
    
        data/lib/rspreadsheet/version.rb
    CHANGED
    
    
| 
         @@ -56,17 +56,23 @@ class Workbook 
     | 
|
| 
       56 
56 
     | 
    
         
             
              end
         
     | 
| 
       57 
57 
     | 
    
         
             
              # @param [String] Optional new filename
         
     | 
| 
       58 
58 
     | 
    
         
             
              # Saves the worksheet. Optionally you can provide new filename.
         
     | 
| 
       59 
     | 
    
         
            -
              def save( 
     | 
| 
       60 
     | 
    
         
            -
                if @filename.nil? and  
     | 
| 
       61 
     | 
    
         
            -
                 
     | 
| 
       62 
     | 
    
         
            -
                if  
     | 
| 
       63 
     | 
    
         
            -
                   
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                     
     | 
| 
      
 59 
     | 
    
         
            +
              def save(new_filename_or_io_object=nil)
         
     | 
| 
      
 60 
     | 
    
         
            +
                if @filename.nil? and new_filename_or_io_object.nil? then raise 'New file should be named on first save.' end
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                if new_filename_or_io_object.kind_of? StringIO
         
     | 
| 
      
 63 
     | 
    
         
            +
                  new_filename_or_io_object.write(@content_xml.to_s(indent: false))
         
     | 
| 
      
 64 
     | 
    
         
            +
                elsif new_filename_or_io_object.nil? or new_filename_or_io_object.kind_of? String
         
     | 
| 
      
 65 
     | 
    
         
            +
                 
         
     | 
| 
      
 66 
     | 
    
         
            +
                  if new_filename_or_io_object.kind_of? String   # the filename has changed 
         
     | 
| 
      
 67 
     | 
    
         
            +
                    # first copy the original file to new location (or template if it is a new file)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    FileUtils.cp(@filename || File.dirname(__FILE__)+'/empty_file_template.ods', new_filename_or_io_object)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    @filename = new_filename_or_io_object
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  Zip::File.open(@filename) do |zip|
         
     | 
| 
      
 72 
     | 
    
         
            +
                    # it is easy, because @xmlnode in in sync with contents all the time
         
     | 
| 
      
 73 
     | 
    
         
            +
                    zip.get_output_stream('content.xml') do |f|
         
     | 
| 
      
 74 
     | 
    
         
            +
                      f.write @content_xml.to_s(:indent => false)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
       70 
76 
     | 
    
         
             
                  end
         
     | 
| 
       71 
77 
     | 
    
         
             
                end
         
     | 
| 
       72 
78 
     | 
    
         
             
              end
         
     | 
    
        data/spec/io_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Rspreadsheet do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it 'can open spreadsheet and save it to file, resulting file has same content as original' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                spreadsheet = Rspreadsheet.new($test_filename)                 # open a file
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                # save it to temp file
         
     | 
| 
      
 8 
     | 
    
         
            +
                tmp_filename = '/tmp/testfile1.ods'        
         
     | 
| 
      
 9 
     | 
    
         
            +
                File.delete(tmp_filename) if File.exists?(tmp_filename)  # first delete temp file
         
     | 
| 
      
 10 
     | 
    
         
            +
                spreadsheet.save(tmp_filename)                                  # and save spreadsheet as temp file
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                # now compare content saved file to original
         
     | 
| 
      
 13 
     | 
    
         
            +
                contents_of_files_are_identical($test_filename,tmp_filename)
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
            #   it 'can open spreadsheet and store it to IO object', :xpending => 'Under development' do
         
     | 
| 
      
 17 
     | 
    
         
            +
            #     spreadsheet = Rspreadsheet.new($test_filename)                 # open a file
         
     | 
| 
      
 18 
     | 
    
         
            +
            #     
         
     | 
| 
      
 19 
     | 
    
         
            +
            #     stringio = StringIO.new
         
     | 
| 
      
 20 
     | 
    
         
            +
            #     spreadsheet.save(stringio)
         
     | 
| 
      
 21 
     | 
    
         
            +
            #     raise stringio.read
         
     | 
| 
      
 22 
     | 
    
         
            +
            #   
         
     | 
| 
      
 23 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            def contents_of_files_are_identical(filename1,filename2)
         
     | 
| 
      
 27 
     | 
    
         
            +
                @content_xml1 = Zip::File.open(filename1) do |zip|
         
     | 
| 
      
 28 
     | 
    
         
            +
                  LibXML::XML::Document.io zip.get_input_stream('content.xml')
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                @content_xml2 = Zip::File.open(filename2) do |zip|
         
     | 
| 
      
 31 
     | 
    
         
            +
                  LibXML::XML::Document.io zip.get_input_stream('content.xml')
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                @content_xml2.root.first_diff(@content_xml1.root).should be_nil
         
     | 
| 
      
 35 
     | 
    
         
            +
                @content_xml1.root.first_diff(@content_xml2.root).should be_nil
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                @content_xml1.root.equals?(@content_xml2.root).should == true
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/rspreadsheet_spec.rb
    CHANGED
    
    | 
         @@ -1,5 +1,4 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'spec_helper'
         
     | 
| 
       2 
     | 
    
         
            -
            using ClassExtensions if RUBY_VERSION > '2.1'
         
     | 
| 
       3 
2 
     | 
    
         | 
| 
       4 
3 
     | 
    
         
             
            describe Rspreadsheet do
         
     | 
| 
       5 
4 
     | 
    
         
             
              it 'can open ods testfile and reads its content correctly' do
         
     | 
| 
         @@ -26,25 +25,6 @@ describe Rspreadsheet do 
     | 
|
| 
       26 
25 
     | 
    
         
             
                  @sheet2[cell.rowi,cell.coli].should == cell.value
         
     | 
| 
       27 
26 
     | 
    
         
             
                end
         
     | 
| 
       28 
27 
     | 
    
         
             
              end
         
     | 
| 
       29 
     | 
    
         
            -
              it 'can open and save file, and saved file is exactly same as original' do
         
     | 
| 
       30 
     | 
    
         
            -
                tmp_filename = '/tmp/testfile1.ods'        # first delete temp file
         
     | 
| 
       31 
     | 
    
         
            -
                File.delete(tmp_filename) if File.exists?(tmp_filename)
         
     | 
| 
       32 
     | 
    
         
            -
                book = Rspreadsheet.new($test_filename)    # than open test file
         
     | 
| 
       33 
     | 
    
         
            -
                book.save(tmp_filename)                    # and save it as temp file
         
     | 
| 
       34 
     | 
    
         
            -
                
         
     | 
| 
       35 
     | 
    
         
            -
                # now compare them
         
     | 
| 
       36 
     | 
    
         
            -
                @content_xml1 = Zip::File.open($test_filename) do |zip|
         
     | 
| 
       37 
     | 
    
         
            -
                  LibXML::XML::Document.io zip.get_input_stream('content.xml')
         
     | 
| 
       38 
     | 
    
         
            -
                end
         
     | 
| 
       39 
     | 
    
         
            -
                @content_xml2 = Zip::File.open(tmp_filename) do |zip|
         
     | 
| 
       40 
     | 
    
         
            -
                  LibXML::XML::Document.io zip.get_input_stream('content.xml')
         
     | 
| 
       41 
     | 
    
         
            -
                end
         
     | 
| 
       42 
     | 
    
         
            -
                
         
     | 
| 
       43 
     | 
    
         
            -
                @content_xml2.root.first_diff(@content_xml1.root).should be_nil
         
     | 
| 
       44 
     | 
    
         
            -
                @content_xml1.root.first_diff(@content_xml2.root).should be_nil
         
     | 
| 
       45 
     | 
    
         
            -
                
         
     | 
| 
       46 
     | 
    
         
            -
                @content_xml1.root.should == @content_xml2.root
         
     | 
| 
       47 
     | 
    
         
            -
              end
         
     | 
| 
       48 
28 
     | 
    
         
             
              it 'when open and save file modified, than the file is different' do
         
     | 
| 
       49 
29 
     | 
    
         
             
                tmp_filename = '/tmp/testfile1.ods'        # first delete temp file
         
     | 
| 
       50 
30 
     | 
    
         
             
                File.delete(tmp_filename) if File.exists?(tmp_filename)
         
     | 
| 
         @@ -88,7 +68,7 @@ describe Rspreadsheet do 
     | 
|
| 
       88 
68 
     | 
    
         
             
                  sheet.cells(5,2).format.bold = true
         
     | 
| 
       89 
69 
     | 
    
         
             
                  sheet.cells(5,2).format.background_color = '#FF0000'
         
     | 
| 
       90 
70 
     | 
    
         
             
                }.not_to raise_error
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                
         
     | 
| 
       92 
72 
     | 
    
         
             
                sheet.rows(4).cellvalues.sum{|val| val.to_f}.should eq 4+7*4
         
     | 
| 
       93 
73 
     | 
    
         
             
                sheet.rows(4).cells.sum{ |cell| cell.value.to_f }.should eq 4+7*4
         
     | 
| 
       94 
74 
     | 
    
         | 
    
        data/spec/testfile1.ods
    CHANGED
    
    | 
         Binary file 
     | 
    
        data/spec/worksheet_spec.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: rspreadsheet
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.2. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.15
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Jakub A.Těšínský
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2016-01-22 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: libxml-ruby
         
     | 
| 
         @@ -191,8 +191,8 @@ files: 
     | 
|
| 
       191 
191 
     | 
    
         
             
            - reinstall_local_gem.sh
         
     | 
| 
       192 
192 
     | 
    
         
             
            - rspreadsheet.gemspec
         
     | 
| 
       193 
193 
     | 
    
         
             
            - spec/cell_spec.rb
         
     | 
| 
       194 
     | 
    
         
            -
            - spec/class_extensions_spec.rb
         
     | 
| 
       195 
194 
     | 
    
         
             
            - spec/column_spec.rb
         
     | 
| 
      
 195 
     | 
    
         
            +
            - spec/io_spec.rb
         
     | 
| 
       196 
196 
     | 
    
         
             
            - spec/row_spec.rb
         
     | 
| 
       197 
197 
     | 
    
         
             
            - spec/rspreadsheet_spec.rb
         
     | 
| 
       198 
198 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
         @@ -220,15 +220,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       220 
220 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       221 
221 
     | 
    
         
             
            requirements: []
         
     | 
| 
       222 
222 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       223 
     | 
    
         
            -
            rubygems_version: 2. 
     | 
| 
      
 223 
     | 
    
         
            +
            rubygems_version: 2.2.2
         
     | 
| 
       224 
224 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       225 
225 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       226 
226 
     | 
    
         
             
            summary: Manipulating spreadsheets with Ruby (read / create / modify OpenDocument
         
     | 
| 
       227 
227 
     | 
    
         
             
              Spreadsheet).
         
     | 
| 
       228 
228 
     | 
    
         
             
            test_files:
         
     | 
| 
       229 
229 
     | 
    
         
             
            - spec/cell_spec.rb
         
     | 
| 
       230 
     | 
    
         
            -
            - spec/class_extensions_spec.rb
         
     | 
| 
       231 
230 
     | 
    
         
             
            - spec/column_spec.rb
         
     | 
| 
      
 231 
     | 
    
         
            +
            - spec/io_spec.rb
         
     | 
| 
       232 
232 
     | 
    
         
             
            - spec/row_spec.rb
         
     | 
| 
       233 
233 
     | 
    
         
             
            - spec/rspreadsheet_spec.rb
         
     | 
| 
       234 
234 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
         @@ -1,46 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'spec_helper'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            if RUBY_VERSION > '2.1'
         
     | 
| 
       4 
     | 
    
         
            -
              using ClassExtensions 
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
              describe Array do
         
     | 
| 
       7 
     | 
    
         
            -
                it 'can sum simple array' do
         
     | 
| 
       8 
     | 
    
         
            -
                  a = [1,2,3,4]
         
     | 
| 
       9 
     | 
    
         
            -
                  a.sum.should == 10
         
     | 
| 
       10 
     | 
    
         
            -
                end
         
     | 
| 
       11 
     | 
    
         
            -
                it 'ignores text and nils while summing' do
         
     | 
| 
       12 
     | 
    
         
            -
                  a = [1,nil, nil,2,3,'foo',5.0]
         
     | 
| 
       13 
     | 
    
         
            -
                  a.sum.should == 11
         
     | 
| 
       14 
     | 
    
         
            -
                  [nil, 'nic'].sum.should == 0
         
     | 
| 
       15 
     | 
    
         
            -
                  [].sum.should == 0
         
     | 
| 
       16 
     | 
    
         
            -
                end
         
     | 
| 
       17 
     | 
    
         
            -
              end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
              describe LibXML::XML::Node do
         
     | 
| 
       20 
     | 
    
         
            -
                before do 
         
     | 
| 
       21 
     | 
    
         
            -
                  @n = LibXML::XML::Node.new('a')
         
     | 
| 
       22 
     | 
    
         
            -
                  @n << LibXML::XML::Node.new('i','italic')
         
     | 
| 
       23 
     | 
    
         
            -
                  b = LibXML::XML::Node.new('p','paragraph')
         
     | 
| 
       24 
     | 
    
         
            -
                  b << LibXML::XML::Node.new('b','boldtext')
         
     | 
| 
       25 
     | 
    
         
            -
                  @n << b
         
     | 
| 
       26 
     | 
    
         
            -
                  @n << LibXML::XML::Node.new_text('textnode')
         
     | 
| 
       27 
     | 
    
         
            -
                  
         
     | 
| 
       28 
     | 
    
         
            -
                  @m = LibXML::XML::Node.new('a')
         
     | 
| 
       29 
     | 
    
         
            -
                  @m << LibXML::XML::Node.new('i','italic')
         
     | 
| 
       30 
     | 
    
         
            -
                  c = LibXML::XML::Node.new('p','paragraph')
         
     | 
| 
       31 
     | 
    
         
            -
                  c << LibXML::XML::Node.new('b','boldtext')
         
     | 
| 
       32 
     | 
    
         
            -
                  @m << c
         
     | 
| 
       33 
     | 
    
         
            -
                  @m << LibXML::XML::Node.new_text('textnode')
         
     | 
| 
       34 
     | 
    
         
            -
                  
         
     | 
| 
       35 
     | 
    
         
            -
                  @m2 = LibXML::XML::Node.new('a')
         
     | 
| 
       36 
     | 
    
         
            -
                end
         
     | 
| 
       37 
     | 
    
         
            -
                it 'can compare nodes' do
         
     | 
| 
       38 
     | 
    
         
            -
                  @n.should == @m
         
     | 
| 
       39 
     | 
    
         
            -
                  @n.should_not == @m2
         
     | 
| 
       40 
     | 
    
         
            -
                end
         
     | 
| 
       41 
     | 
    
         
            -
                it 'has correct elements' do
         
     | 
| 
       42 
     | 
    
         
            -
              #     raise @n.first_diff(@m).inspect
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
              end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            end
         
     |