tb 0.1
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/README +60 -0
- data/bin/tb +1137 -0
- data/lib/tb.rb +35 -0
- data/lib/tb/basic.rb +1071 -0
- data/lib/tb/csv.rb +125 -0
- data/lib/tb/enumerable.rb +284 -0
- data/lib/tb/fieldset.rb +96 -0
- data/lib/tb/pathfinder.rb +569 -0
- data/lib/tb/qtsv.rb +93 -0
- data/lib/tb/reader.rb +213 -0
- data/lib/tb/record.rb +129 -0
- data/lib/tb/tsv.rb +93 -0
- data/sample/excel2csv +270 -0
- data/sample/poi-xls2csv.rb +397 -0
- data/sample/poi-xls2csv.sh +39 -0
- data/test-all.rb +7 -0
- data/test/test_basic.rb +290 -0
- data/test/test_csv.rb +78 -0
- data/test/test_enumerable.rb +122 -0
- data/test/test_record.rb +12 -0
- data/test/test_tsv.rb +41 -0
- metadata +73 -0
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            #!/bin/sh
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # sample/poi-xls2csv.sh - script to run sample/poi-xls2csv.rb
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            # Copyright (C) 2011 Tanaka Akira  <akr@fsij.org>
         | 
| 6 | 
            +
            # 
         | 
| 7 | 
            +
            # Redistribution and use in source and binary forms, with or without
         | 
| 8 | 
            +
            # modification, are permitted provided that the following conditions are met:
         | 
| 9 | 
            +
            # 
         | 
| 10 | 
            +
            #  1. Redistributions of source code must retain the above copyright notice, this
         | 
| 11 | 
            +
            #     list of conditions and the following disclaimer.
         | 
| 12 | 
            +
            #  2. Redistributions in binary form must reproduce the above copyright notice,
         | 
| 13 | 
            +
            #     this list of conditions and the following disclaimer in the documentation
         | 
| 14 | 
            +
            #     and/or other materials provided with the distribution.
         | 
| 15 | 
            +
            #  3. The name of the author may not be used to endorse or promote products
         | 
| 16 | 
            +
            #     derived from this software without specific prior written permission.
         | 
| 17 | 
            +
            # 
         | 
| 18 | 
            +
            # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
         | 
| 19 | 
            +
            # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
         | 
| 20 | 
            +
            # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
         | 
| 21 | 
            +
            # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
         | 
| 22 | 
            +
            # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
         | 
| 23 | 
            +
            # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
         | 
| 24 | 
            +
            # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
         | 
| 25 | 
            +
            # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
         | 
| 26 | 
            +
            # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
         | 
| 27 | 
            +
            # OF SUCH DAMAGE.
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            # Ubuntu libjakarta-poi-java package installs /usr/share/java/jakarta-poi.jar.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            d="`dirname $0`"
         | 
| 32 | 
            +
            d="`cd $d; pwd`"
         | 
| 33 | 
            +
            d="`dirname $d`"
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            exec jruby -Ku \
         | 
| 36 | 
            +
            -I"$d/lib" \
         | 
| 37 | 
            +
            -I/usr/share/java \
         | 
| 38 | 
            +
            "$d/sample/poi-xls2csv.rb" \
         | 
| 39 | 
            +
            "$@"
         | 
    
        data/test-all.rb
    ADDED
    
    
    
        data/test/test_basic.rb
    ADDED
    
    | @@ -0,0 +1,290 @@ | |
| 1 | 
            +
            require 'tb'
         | 
| 2 | 
            +
            require 'test/unit'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class TestTbBasic < Test::Unit::TestCase
         | 
| 5 | 
            +
              def test_initialize
         | 
| 6 | 
            +
                t = Tb.new
         | 
| 7 | 
            +
                assert_equal([], t.list_fields)
         | 
| 8 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 9 | 
            +
                           %w[apple red],
         | 
| 10 | 
            +
                           %w[banana yellow],
         | 
| 11 | 
            +
                           %w[orange orange]
         | 
| 12 | 
            +
                assert_equal(%w[fruit color].sort, t.list_fields.sort)
         | 
| 13 | 
            +
                a = t.to_a.map {|r| r.to_h_with_reserved }
         | 
| 14 | 
            +
                assert_operator(a, :include?, {"_recordid"=>0, "fruit"=>"apple", "color"=>"red"})
         | 
| 15 | 
            +
                assert_operator(a, :include?, {"_recordid"=>1, "fruit"=>"banana", "color"=>"yellow"})
         | 
| 16 | 
            +
                assert_operator(a, :include?, {"_recordid"=>2, "fruit"=>"orange", "color"=>"orange"})
         | 
| 17 | 
            +
                assert_equal(3, a.length)
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def test_replace
         | 
| 21 | 
            +
                t1 = Tb.new %w[fruit color],
         | 
| 22 | 
            +
                            %w[apple red],
         | 
| 23 | 
            +
                            %w[banana yellow],
         | 
| 24 | 
            +
                            %w[orange orange]
         | 
| 25 | 
            +
                t2 = Tb.new %w[grain color],
         | 
| 26 | 
            +
                            %w[rice white],
         | 
| 27 | 
            +
                            %w[wheat light-brown]
         | 
| 28 | 
            +
                t1.replace t2
         | 
| 29 | 
            +
                assert_equal([{"grain"=>"rice", "color"=>"white"},
         | 
| 30 | 
            +
                              {"grain"=>"wheat", "color"=>"light-brown"}],
         | 
| 31 | 
            +
                             t2.to_a.map {|rec| rec.to_h })
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_enumerable
         | 
| 35 | 
            +
                t = Tb.new
         | 
| 36 | 
            +
                assert_kind_of(Enumerable, t)
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def test_define_field
         | 
| 40 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 41 | 
            +
                           %w[apple red],
         | 
| 42 | 
            +
                           %w[banana yellow],
         | 
| 43 | 
            +
                           %w[orange orange]
         | 
| 44 | 
            +
                t.define_field("namelen") {|record| record["fruit"].length }
         | 
| 45 | 
            +
                t.each {|rec|
         | 
| 46 | 
            +
                  case rec['fruit']
         | 
| 47 | 
            +
                  when 'apple' then assert_equal(5, rec['namelen'])
         | 
| 48 | 
            +
                  when 'banana' then assert_equal(6, rec['namelen'])
         | 
| 49 | 
            +
                  when 'orange' then assert_equal(6, rec['namelen'])
         | 
| 50 | 
            +
                  else raise
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                }
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              def test_list_fields
         | 
| 56 | 
            +
                t = Tb.new
         | 
| 57 | 
            +
                assert_equal([], t.list_fields)
         | 
| 58 | 
            +
                assert_equal([], t.list_fields)
         | 
| 59 | 
            +
                assert_equal(["_recordid"], t.list_fields_all)
         | 
| 60 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 61 | 
            +
                           %w[apple red],
         | 
| 62 | 
            +
                           %w[banana yellow],
         | 
| 63 | 
            +
                           %w[orange orange]
         | 
| 64 | 
            +
                assert_equal(%w[fruit color], t.list_fields)
         | 
| 65 | 
            +
                assert_equal(%w[fruit color], t.list_fields)
         | 
| 66 | 
            +
                assert_equal(%w[_recordid fruit color], t.list_fields_all)
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              def test_list_recordids
         | 
| 70 | 
            +
                t = Tb.new
         | 
| 71 | 
            +
                assert_equal([], t.list_recordids)
         | 
| 72 | 
            +
                recordid1 = t.allocate_recordid
         | 
| 73 | 
            +
                assert_equal([recordid1], t.list_recordids)
         | 
| 74 | 
            +
                recordid2 = t.allocate_recordid
         | 
| 75 | 
            +
                assert_equal([recordid1, recordid2], t.list_recordids)
         | 
| 76 | 
            +
                assert_equal(nil, t.delete_recordid(recordid1))
         | 
| 77 | 
            +
                assert_equal([recordid2], t.list_recordids)
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              def test_cell
         | 
| 81 | 
            +
                t = Tb.new %w[f g]
         | 
| 82 | 
            +
                recordid = t.allocate_recordid
         | 
| 83 | 
            +
                assert_equal(nil, t.get_cell(recordid, :f))
         | 
| 84 | 
            +
                t.set_cell(recordid, :f, 1)
         | 
| 85 | 
            +
                assert_equal(1, t.get_cell(recordid, :f))
         | 
| 86 | 
            +
                assert_equal(1, t.delete_cell(recordid, :f))
         | 
| 87 | 
            +
                assert_equal(nil, t.get_cell(recordid, :f))
         | 
| 88 | 
            +
                t.set_cell(recordid, :f, nil)
         | 
| 89 | 
            +
                assert_equal(nil, t.get_cell(recordid, :f))
         | 
| 90 | 
            +
                t.set_cell(recordid, :g, 2)
         | 
| 91 | 
            +
                assert_equal(2, t.get_cell(recordid, :g))
         | 
| 92 | 
            +
                t.set_cell(recordid, :g, nil)
         | 
| 93 | 
            +
                assert_equal(nil, t.get_cell(recordid, :g))
         | 
| 94 | 
            +
                t.delete_cell(recordid, :g)
         | 
| 95 | 
            +
                assert_equal(nil, t.get_cell(recordid, :g))
         | 
| 96 | 
            +
                t.delete_recordid(recordid)
         | 
| 97 | 
            +
                assert_raise(IndexError) { t.get_cell(recordid, :g) }
         | 
| 98 | 
            +
                assert_raise(IndexError) { t.get_cell(100, :g) }
         | 
| 99 | 
            +
                assert_raise(IndexError) { t.get_cell(-1, :g) }
         | 
| 100 | 
            +
                assert_raise(TypeError) { t.get_cell(:invalid_recordid, :g) }
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              def test_each_field
         | 
| 104 | 
            +
                t = Tb.new %w[a b z]
         | 
| 105 | 
            +
                a = []
         | 
| 106 | 
            +
                t.each_field_with_reserved {|f| a << f }
         | 
| 107 | 
            +
                assert_equal(%w[_recordid a b z], a)
         | 
| 108 | 
            +
                a = []
         | 
| 109 | 
            +
                t.each_field {|f| a << f }
         | 
| 110 | 
            +
                assert_equal(%w[a b z], a)
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
              def test_each_record
         | 
| 114 | 
            +
                t = Tb.new %w[a], [1], [2]
         | 
| 115 | 
            +
                records = []
         | 
| 116 | 
            +
                t.each {|record| records << record.to_h_with_reserved }
         | 
| 117 | 
            +
                assert_equal([{"_recordid"=>0, "a"=>1}, {"_recordid"=>1, "a"=>2}], records)
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
              def test_categorize
         | 
| 121 | 
            +
                t = Tb.new %w[a b c], [1,2,3], [2,4,3]
         | 
| 122 | 
            +
                assert_raise(ArgumentError) { t.tb_categorize('a') }
         | 
| 123 | 
            +
                assert_equal({1=>[2], 2=>[4]}, t.tb_categorize('a', 'b'))
         | 
| 124 | 
            +
                assert_equal({1=>{2=>[3]}, 2=>{4=>[3]}}, t.tb_categorize('a', 'b', 'c'))
         | 
| 125 | 
            +
                assert_equal({1=>[[2,3]], 2=>[[4,3]]}, t.tb_categorize('a', ['b', 'c']))
         | 
| 126 | 
            +
                assert_equal({[1,2]=>[3], [2,4]=>[3]}, t.tb_categorize(['a', 'b'], 'c'))
         | 
| 127 | 
            +
                assert_equal({3=>[2,4]}, t.tb_categorize('c', 'b'))
         | 
| 128 | 
            +
                assert_equal({3=>[true,true]}, t.tb_categorize('c', lambda {|e| true }))
         | 
| 129 | 
            +
                assert_equal({3=>2}, t.tb_categorize('c', 'b') {|ks, vs| vs.length } )
         | 
| 130 | 
            +
                assert_equal({3=>2}, t.tb_categorize('c', 'b',
         | 
| 131 | 
            +
                                                  :seed=>0,
         | 
| 132 | 
            +
                                                  :update=> lambda {|ks, s, v| s + 1 }))
         | 
| 133 | 
            +
                assert_equal({true => [1,2]}, t.tb_categorize(lambda {|e| true }, 'a'))
         | 
| 134 | 
            +
                h = t.tb_categorize('a', lambda {|e| e })
         | 
| 135 | 
            +
                assert_equal(2, h.size)
         | 
| 136 | 
            +
                assert_equal([1, 2], h.keys.sort)
         | 
| 137 | 
            +
                assert_instance_of(Array, h[1])
         | 
| 138 | 
            +
                assert_instance_of(Array, h[2])
         | 
| 139 | 
            +
                assert_equal(1, h[1].length)
         | 
| 140 | 
            +
                assert_equal(1, h[2].length)
         | 
| 141 | 
            +
                assert_instance_of(Tb::Record, h[1][0])
         | 
| 142 | 
            +
                assert_instance_of(Tb::Record, h[2][0])
         | 
| 143 | 
            +
                assert_same(t, h[1][0].table)
         | 
| 144 | 
            +
                assert_same(t, h[2][0].table)
         | 
| 145 | 
            +
                assert_equal(0, h[1][0].record_id)
         | 
| 146 | 
            +
                assert_equal(1, h[2][0].record_id)
         | 
| 147 | 
            +
                assert_same(t, h[2][0].table)
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                assert_raise(ArgumentError) { t.tb_categorize(:_foo, lambda {|e| true }) }
         | 
| 150 | 
            +
                assert_equal({3=>[2], 6=>[4]}, t.tb_categorize(lambda {|rec| rec['a'] * 3 }, 'b'))
         | 
| 151 | 
            +
                assert_equal({[1,2]=>[[2,3]], [2,4]=>[[4,3]]}, t.tb_categorize(['a', 'b'], ['b', 'c']))
         | 
| 152 | 
            +
                assert_equal({1=>2, 2=>4}, t.tb_categorize('a', 'b', :seed=>0, :op=>:+))
         | 
| 153 | 
            +
                assert_raise(ArgumentError) { t.tb_categorize('a', 'b', :op=>:+, :update=>lambda {|ks, s, v| v }) }
         | 
| 154 | 
            +
                i = -1
         | 
| 155 | 
            +
                assert_equal({3=>[0, 1]}, t.tb_categorize('c', lambda {|e| i += 1 }))
         | 
| 156 | 
            +
              end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
              def test_unique_categorize
         | 
| 159 | 
            +
                t = Tb.new %w[a b c], [1,2,3], [2,4,4]
         | 
| 160 | 
            +
                assert_equal({1=>3, 2=>4}, t.tb_unique_categorize("a", "c"))
         | 
| 161 | 
            +
                assert_equal({1=>[3], 2=>[4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
         | 
| 162 | 
            +
                assert_equal({1=>1, 2=>1}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
         | 
| 163 | 
            +
                assert_equal({1=>{2=>3}, 2=>{4=>4}}, t.tb_unique_categorize("a", "b", "c"))
         | 
| 164 | 
            +
                t.insert({"a"=>2, "b"=>7, "c"=>8})
         | 
| 165 | 
            +
                assert_equal({1=>{2=>3}, 2=>{4=>4, 7=>8}}, t.tb_unique_categorize("a", "b", "c"))
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              def test_unique_categorize_ambiguous
         | 
| 169 | 
            +
                t = Tb.new %w[a b c], [1,2,3], [1,4,4]
         | 
| 170 | 
            +
                assert_raise(ArgumentError) { t.tb_unique_categorize("a", "c") }
         | 
| 171 | 
            +
                assert_equal({1=>[3,4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
         | 
| 172 | 
            +
                assert_equal({1=>2}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
              def test_category_count
         | 
| 176 | 
            +
                t = Tb.new %w[a b c], [1,2,3], [2,4,3]
         | 
| 177 | 
            +
                assert_equal({1=>1, 2=>1}, t.tb_category_count("a"))
         | 
| 178 | 
            +
                assert_equal({2=>1, 4=>1}, t.tb_category_count("b"))
         | 
| 179 | 
            +
                assert_equal({3=>2}, t.tb_category_count("c"))
         | 
| 180 | 
            +
                assert_equal({3=>{1=>1, 2=>1}}, t.tb_category_count("c", "a"))
         | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
              def test_natjoin2
         | 
| 184 | 
            +
                t1 = Tb.new %w[a b], %w[1 2], %w[3 4], %w[0 4]
         | 
| 185 | 
            +
                t2 = Tb.new %w[b c], %w[2 3], %w[4 5]
         | 
| 186 | 
            +
                t3 = t1.natjoin2(t2)
         | 
| 187 | 
            +
                assert_equal([{"_recordid"=>0, "a"=>"1", "b"=>"2", "c"=>"3"},
         | 
| 188 | 
            +
                              {"_recordid"=>1, "a"=>"3", "b"=>"4", "c"=>"5"},
         | 
| 189 | 
            +
                              {"_recordid"=>2, "a"=>"0", "b"=>"4", "c"=>"5"}], t3.to_a.map {|r| r.to_h_with_reserved })
         | 
| 190 | 
            +
              end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
              def test_natjoin2_nocommon
         | 
| 193 | 
            +
                t1 = Tb.new %w[a b], %w[1 2], %w[3 4]
         | 
| 194 | 
            +
                t2 = Tb.new %w[c d], %w[5 6], %w[7 8]
         | 
| 195 | 
            +
                t3 = t1.natjoin2(t2)
         | 
| 196 | 
            +
                assert_equal([{"a"=>"1", "b"=>"2", "c"=>"5", "d"=>"6"},
         | 
| 197 | 
            +
                              {"a"=>"1", "b"=>"2", "c"=>"7", "d"=>"8"},
         | 
| 198 | 
            +
                              {"a"=>"3", "b"=>"4", "c"=>"5", "d"=>"6"},
         | 
| 199 | 
            +
                              {"a"=>"3", "b"=>"4", "c"=>"7", "d"=>"8"}],
         | 
| 200 | 
            +
                              t3.to_a.map {|r| r.to_h })
         | 
| 201 | 
            +
              end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
              def test_fmap!
         | 
| 204 | 
            +
                t = Tb.new %w[a b], %w[1 2], %w[3 4]
         | 
| 205 | 
            +
                t.fmap!("a") {|record, v| "foo" + v }
         | 
| 206 | 
            +
                assert_equal([{"_recordid"=>0, "a"=>"foo1", "b"=>"2"},
         | 
| 207 | 
            +
                              {"_recordid"=>1, "a"=>"foo3", "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
         | 
| 208 | 
            +
              end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
              def test_delete_field
         | 
| 211 | 
            +
                t = Tb.new(%w[a b], %w[1 2], %w[3 4])
         | 
| 212 | 
            +
                t.delete_field("a")
         | 
| 213 | 
            +
                assert_equal([{"_recordid"=>0, "b"=>"2"},
         | 
| 214 | 
            +
                              {"_recordid"=>1, "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
         | 
| 215 | 
            +
              end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
              def test_delete_recordid
         | 
| 218 | 
            +
                t = Tb.new %w[a]
         | 
| 219 | 
            +
                recordid = t.insert({"a"=>"foo"})
         | 
| 220 | 
            +
                t.insert({"a"=>"bar"})
         | 
| 221 | 
            +
                t.delete_recordid(recordid)
         | 
| 222 | 
            +
                t.insert({"a"=>"foo"})
         | 
| 223 | 
            +
                records = []
         | 
| 224 | 
            +
                t.each {|record|
         | 
| 225 | 
            +
                  record = record.to_h
         | 
| 226 | 
            +
                  record.delete('_recordid')
         | 
| 227 | 
            +
                  records << record
         | 
| 228 | 
            +
                }
         | 
| 229 | 
            +
                records = records.sort_by {|record| record['a'] }
         | 
| 230 | 
            +
                assert_equal([{"a"=>"bar"}, {"a"=>"foo"}], records)
         | 
| 231 | 
            +
              end
         | 
| 232 | 
            +
             | 
| 233 | 
            +
              def test_rename_field
         | 
| 234 | 
            +
                t1 = Tb.new %w[a b], [1, 2]
         | 
| 235 | 
            +
                assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
         | 
| 236 | 
            +
                t2 = t1.rename_field("a" => "c", "b" => "d")
         | 
| 237 | 
            +
                assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
         | 
| 238 | 
            +
                assert_equal([{"_recordid"=>0, "c"=>1, "d"=>2}], t2.to_a.map {|r| r.to_h_with_reserved })
         | 
| 239 | 
            +
              end
         | 
| 240 | 
            +
             | 
| 241 | 
            +
              def test_allocate_recordid
         | 
| 242 | 
            +
                t = Tb.new
         | 
| 243 | 
            +
                recordid1 = t.allocate_recordid(100)
         | 
| 244 | 
            +
                assert_equal(100, recordid1)
         | 
| 245 | 
            +
                recordid2 = t.allocate_recordid(200)
         | 
| 246 | 
            +
                assert_equal(200, recordid2)
         | 
| 247 | 
            +
                recordid3 = t.allocate_recordid
         | 
| 248 | 
            +
                assert(recordid3 != recordid1)
         | 
| 249 | 
            +
                assert(recordid3 != recordid2)
         | 
| 250 | 
            +
              end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
              def test_reorder_fields!
         | 
| 253 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 254 | 
            +
                           %w[apple red],
         | 
| 255 | 
            +
                           %w[banana yellow],
         | 
| 256 | 
            +
                           %w[orange orange]
         | 
| 257 | 
            +
                assert_equal(%w[fruit color], t.list_fields)
         | 
| 258 | 
            +
                t.reorder_fields! %w[color fruit]
         | 
| 259 | 
            +
                assert_equal(%w[_recordid color fruit], t.list_fields_all)
         | 
| 260 | 
            +
                t.reorder_fields! %w[fruit _recordid color]
         | 
| 261 | 
            +
                assert_equal(%w[fruit _recordid color], t.list_fields_all)
         | 
| 262 | 
            +
              end
         | 
| 263 | 
            +
             | 
| 264 | 
            +
              def test_has_field?
         | 
| 265 | 
            +
                t = Tb.new %w[fruit color], 
         | 
| 266 | 
            +
                           %w[apple red], 
         | 
| 267 | 
            +
                           %w[banana yellow], 
         | 
| 268 | 
            +
                           %w[orange orange] 
         | 
| 269 | 
            +
                assert_equal(true, t.has_field?("fruit"))
         | 
| 270 | 
            +
                assert_equal(false, t.has_field?("foo"))
         | 
| 271 | 
            +
              end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
              def test_filter
         | 
| 274 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 275 | 
            +
                           %w[apple red],
         | 
| 276 | 
            +
                           %w[banana yellow],
         | 
| 277 | 
            +
                           %w[orange orange]
         | 
| 278 | 
            +
                t2 = t.filter {|rec| rec["fruit"] == "banana" }
         | 
| 279 | 
            +
                assert_equal(1, t2.size)
         | 
| 280 | 
            +
              end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
              def test_reorder_records_by
         | 
| 283 | 
            +
                t = Tb.new %w[fruit color],
         | 
| 284 | 
            +
                           %w[apple red],
         | 
| 285 | 
            +
                           %w[banana yellow],
         | 
| 286 | 
            +
                           %w[orange orange]
         | 
| 287 | 
            +
                t2 = t.reorder_records_by {|rec| rec["color"] }
         | 
| 288 | 
            +
                assert_equal(t.map {|rec| rec["color"] }.sort, t2.map {|rec| rec["color"] })
         | 
| 289 | 
            +
              end
         | 
| 290 | 
            +
            end
         | 
    
        data/test/test_csv.rb
    ADDED
    
    | @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            require 'tb'
         | 
| 2 | 
            +
            require 'test/unit'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class TestTbCSV < Test::Unit::TestCase
         | 
| 5 | 
            +
              def test_parse
         | 
| 6 | 
            +
                csv = <<-'End'.gsub(/^\s+/, '')
         | 
| 7 | 
            +
                a,b
         | 
| 8 | 
            +
                1,2
         | 
| 9 | 
            +
                3,4
         | 
| 10 | 
            +
                End
         | 
| 11 | 
            +
                t = Tb.parse_csv(csv)
         | 
| 12 | 
            +
                records = []
         | 
| 13 | 
            +
                t.each_record {|record|
         | 
| 14 | 
            +
                  records << record.to_h_with_reserved
         | 
| 15 | 
            +
                }
         | 
| 16 | 
            +
                assert_equal(
         | 
| 17 | 
            +
                  [{"_recordid"=>0, "a"=>"1", "b"=>"2"},
         | 
| 18 | 
            +
                   {"_recordid"=>1, "a"=>"3", "b"=>"4"}],
         | 
| 19 | 
            +
                  records)
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_parse_empty
         | 
| 23 | 
            +
                csv = <<-'End'.gsub(/^\s+/, '')
         | 
| 24 | 
            +
                a,b,c
         | 
| 25 | 
            +
                1,,2
         | 
| 26 | 
            +
                3,"",4
         | 
| 27 | 
            +
                End
         | 
| 28 | 
            +
                t = Tb.parse_csv(csv)
         | 
| 29 | 
            +
                records = []
         | 
| 30 | 
            +
                t.each_record {|record|
         | 
| 31 | 
            +
                  records << record.to_h_with_reserved
         | 
| 32 | 
            +
                }
         | 
| 33 | 
            +
                assert_equal(
         | 
| 34 | 
            +
                  [{"_recordid"=>0, "a"=>"1", "c"=>"2"},
         | 
| 35 | 
            +
                   {"_recordid"=>1, "a"=>"3", "b"=>"", "c"=>"4"}],
         | 
| 36 | 
            +
                  records)
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def test_parse_conv
         | 
| 40 | 
            +
                csv = "foo\na,b\n1,2\n"
         | 
| 41 | 
            +
                t = Tb.parse_csv(csv) {|aa|
         | 
| 42 | 
            +
                  assert_equal([%w[foo],
         | 
| 43 | 
            +
                               %w[a b],
         | 
| 44 | 
            +
                               %w[1 2]],
         | 
| 45 | 
            +
                               aa)
         | 
| 46 | 
            +
                  aa.shift
         | 
| 47 | 
            +
                  aa
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
                records = []
         | 
| 50 | 
            +
                t.each_record {|record|
         | 
| 51 | 
            +
                  records << record.to_h_with_reserved
         | 
| 52 | 
            +
                }
         | 
| 53 | 
            +
                assert_equal(
         | 
| 54 | 
            +
                  [{"_recordid"=>0, "a"=>"1", "b"=>"2"}],
         | 
| 55 | 
            +
                  records)
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def test_generate
         | 
| 59 | 
            +
                t = Tb.new %w[a b], [1, 2], [3, 4]
         | 
| 60 | 
            +
                out = t.generate_csv('', ['a', 'b'])
         | 
| 61 | 
            +
                assert_equal(<<-'End'.gsub(/^\s+/, ''), out)
         | 
| 62 | 
            +
                a,b
         | 
| 63 | 
            +
                1,2
         | 
| 64 | 
            +
                3,4
         | 
| 65 | 
            +
                End
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              def test_generate_empty
         | 
| 69 | 
            +
                t = Tb.new %w[a b c], [1, nil, 2], [3, '', 4]
         | 
| 70 | 
            +
                out = t.generate_csv('', ['a', 'b', 'c'])
         | 
| 71 | 
            +
                assert_equal(<<-'End'.gsub(/^\s+/, ''), out)
         | 
| 72 | 
            +
                a,b,c
         | 
| 73 | 
            +
                1,,2
         | 
| 74 | 
            +
                3,"",4
         | 
| 75 | 
            +
                End
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,122 @@ | |
| 1 | 
            +
            require 'tb/enumerable'
         | 
| 2 | 
            +
            require 'test/unit'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class TestTbEnumerable < Test::Unit::TestCase
         | 
| 5 | 
            +
              def test_categorize
         | 
| 6 | 
            +
                a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
         | 
| 7 | 
            +
                     {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
         | 
| 8 | 
            +
                     {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
         | 
| 9 | 
            +
                assert_equal({"yellow"=>["banana", "grapefruit"], "green"=>["melon"]},
         | 
| 10 | 
            +
                             a.tb_categorize(:color, :fruit))
         | 
| 11 | 
            +
                assert_equal({"sweet"=>["banana", "melon"], "tart"=>["grapefruit"]},
         | 
| 12 | 
            +
                             a.tb_categorize(:taste, :fruit))
         | 
| 13 | 
            +
                assert_equal({"sweet"=>{"yellow"=>["banana"], "green"=>["melon"]}, "tart"=>{"yellow"=>["grapefruit"]}},
         | 
| 14 | 
            +
                             a.tb_categorize(:taste, :color, :fruit))
         | 
| 15 | 
            +
                assert_equal({"sweet"=>["yellow", "green"], "tart"=>["yellow"]},
         | 
| 16 | 
            +
                             a.tb_categorize(:taste, :color))
         | 
| 17 | 
            +
                assert_equal({?n=>["banana", "melon"], ?e=>["grapefruit"]},
         | 
| 18 | 
            +
                             a.tb_categorize(lambda {|elt| elt[:fruit][4] }, :fruit))
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                assert_equal({"yellow"=>[true, true], "green"=>[true]},
         | 
| 21 | 
            +
                             a.tb_categorize(:color, lambda {|e| true }))
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                i = -1
         | 
| 24 | 
            +
                assert_equal({"yellow"=>[0, 2], "green"=>[1]},
         | 
| 25 | 
            +
                             a.tb_categorize(:color, lambda {|e| i += 1 }))
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                assert_equal({"yellow"=>[{:fruit=>"banana", :color=>"yellow", :taste=>"sweet", :price=>100},
         | 
| 28 | 
            +
                                         {:fruit=>"grapefruit", :color=>"yellow", :taste=>"tart", :price=>200}],
         | 
| 29 | 
            +
                              "green"=>[{:fruit=>"melon", :color=>"green", :taste=>"sweet", :price=>300}]},
         | 
| 30 | 
            +
                             a.tb_categorize(:color, lambda {|e| e }))
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                assert_equal({"yellow"=>[{:fruit=>"banana", :color=>"yellow", :taste=>"sweet", :price=>100},
         | 
| 33 | 
            +
                                         {:fruit=>"grapefruit", :color=>"yellow", :taste=>"tart", :price=>200}],
         | 
| 34 | 
            +
                              "green"=>[{:fruit=>"melon", :color=>"green", :taste=>"sweet", :price=>300}]},
         | 
| 35 | 
            +
                             a.tb_categorize(:color, lambda {|e| e }))
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                i = -1
         | 
| 38 | 
            +
                assert_equal({"yellow"=>[["banana", "sweet", 0], ["grapefruit", "tart", 2]],
         | 
| 39 | 
            +
                              "green"=>[["melon", "sweet", 1]]},
         | 
| 40 | 
            +
                             a.tb_categorize(:color, [:fruit, :taste, lambda {|e| i += 1 }]))
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                assert_equal({true=>["banana", "melon", "grapefruit"]},
         | 
| 43 | 
            +
                             a.tb_categorize(lambda {|e| true }, :fruit))
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
                assert_equal({"yellow"=>2, "green"=>1},
         | 
| 46 | 
            +
                             a.tb_categorize(:color, lambda {|e| true }, :seed=>0, :op=>lambda {|s, v| s+1 }))
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                assert_raise(ArgumentError) { a.tb_categorize(:color, lambda {|e| true }, :seed=>0,
         | 
| 49 | 
            +
                                                           :seed=>nil,
         | 
| 50 | 
            +
                                                           :op=>lambda {|s, v| s+1 },
         | 
| 51 | 
            +
                                                           :update=>lambda {|ks, s, v| s+1 }) }
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                assert_equal({"yellow"=>"bananagrapefruit", "green"=>"melon"},
         | 
| 54 | 
            +
                             a.tb_categorize(:color, :fruit, :seed=>"", :op=>:+))
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                assert_equal({"yellow"=>2, "green"=>1},
         | 
| 57 | 
            +
                             a.tb_categorize(:color, lambda {|e| 1 }, :op=>:+))
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                assert_equal({"yellow"=>"banana,grapefruit", "green"=>"melon"},
         | 
| 60 | 
            +
                             a.tb_categorize(:color, :fruit) {|ks, vs| vs.join(",") } )
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                assert_equal({"yellow"=>150.0, "green"=>300.0},
         | 
| 63 | 
            +
                             a.tb_categorize(:color, :price) {|ks, vs| vs.inject(0.0, &:+) / vs.length })
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                assert_equal({"yellow"=>{"banana"=>100.0, "grapefruit"=>200.0}, "green"=>{"melon"=>300.0}},
         | 
| 66 | 
            +
                             a.tb_categorize(:color, :fruit, :price) {|ks, vs| vs.inject(0.0, &:+) / vs.length })
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                assert_raise(ArgumentError) { a.tb_categorize('a') }
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def test_categorize_proc
         | 
| 72 | 
            +
                c = Object.new
         | 
| 73 | 
            +
                def c.call(v) 10 end
         | 
| 74 | 
            +
                assert_equal({10=>[10]}, [[1]].tb_categorize(c, c))
         | 
| 75 | 
            +
                assert_raise(NoMethodError) { [[1]].tb_categorize(0, 0, :seed=>nil, :update=>c) }
         | 
| 76 | 
            +
                assert_raise(NoMethodError) { [[1]].tb_categorize(0, 0, :seed=>nil, :op=>c) }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                t = Object.new
         | 
| 79 | 
            +
                def t.to_proc() lambda {|*| 11 } end
         | 
| 80 | 
            +
                assert_raise(TypeError) { [[1]].tb_categorize(t, t) }
         | 
| 81 | 
            +
                assert_equal({1=>11}, [[1]].tb_categorize(0, 0, :seed=>nil, :update=>t))
         | 
| 82 | 
            +
                assert_equal({1=>11}, [[1]].tb_categorize(0, 0, :seed=>nil, :op=>t))
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                ct = Object.new
         | 
| 85 | 
            +
                def ct.call(v) 12 end
         | 
| 86 | 
            +
                def ct.to_proc() lambda {|*| 13 } end
         | 
| 87 | 
            +
                assert_equal({12=>[12]}, [[1]].tb_categorize(ct, ct))
         | 
| 88 | 
            +
                assert_equal({1=>13}, [[1]].tb_categorize(0, 0, :seed=>nil, :update=>ct))
         | 
| 89 | 
            +
                assert_equal({1=>13}, [[1]].tb_categorize(0, 0, :seed=>nil, :op=>ct))
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def test_unique_categorize
         | 
| 93 | 
            +
                a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
         | 
| 94 | 
            +
                     {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
         | 
| 95 | 
            +
                     {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
         | 
| 96 | 
            +
                assert_equal({"banana"=>100, "melon"=>300, "grapefruit"=>200},
         | 
| 97 | 
            +
                             a.tb_unique_categorize(:fruit, :price))
         | 
| 98 | 
            +
              
         | 
| 99 | 
            +
                assert_raise(ArgumentError) { a.tb_unique_categorize(:color, :price) }
         | 
| 100 | 
            +
              
         | 
| 101 | 
            +
                assert_equal({"sweet"=>400, "tart"=>200},
         | 
| 102 | 
            +
                             a.tb_unique_categorize(:taste, :price) {|s, v| !s ? v : s + v })
         | 
| 103 | 
            +
              
         | 
| 104 | 
            +
                assert_equal({"yellow"=>300, "green"=>300},
         | 
| 105 | 
            +
                             a.tb_unique_categorize(:color, :price, :seed=>0) {|s, v| s + v })
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              def test_category_count
         | 
| 109 | 
            +
                a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
         | 
| 110 | 
            +
                     {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
         | 
| 111 | 
            +
                     {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
         | 
| 112 | 
            +
              
         | 
| 113 | 
            +
                assert_equal({"yellow"=>2, "green"=>1},
         | 
| 114 | 
            +
                             a.tb_category_count(:color))
         | 
| 115 | 
            +
              
         | 
| 116 | 
            +
                assert_equal({"sweet"=>2, "tart"=>1},
         | 
| 117 | 
            +
                             a.tb_category_count(:taste))
         | 
| 118 | 
            +
              
         | 
| 119 | 
            +
                assert_equal({"sweet"=>{"yellow"=>1, "green"=>1}, "tart"=>{"yellow"=>1}},
         | 
| 120 | 
            +
                             a.tb_category_count(:taste, :color))
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
            end
         |