fat_core 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/TODO.org +9 -0
- data/lib/fat_core/array.rb +22 -0
- data/lib/fat_core/hash.rb +9 -0
- data/lib/fat_core/table.rb +1 -1
- data/lib/fat_core/version.rb +1 -1
- data/spec/lib/array_spec.rb +16 -0
- data/spec/lib/table_spec.rb +88 -55
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8f9197b29ac69c96409642ef86bb5a5bf3fdace
|
4
|
+
data.tar.gz: 6aeb17344e346ebfc21030523929036934eee6a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3800832b0339a3c9deca6450bece102d33dc0a7912b18e9a0c743b85b438ba076bf1b290f70b0bd3a8d0fb48f65780be8375175d54aa50bd48fdf8dee89b05b3
|
7
|
+
data.tar.gz: 914b7895346e3a07422027e54b3ae11bdd5bed6297b3281488a93bd3e9a8d2b29efd7550b6510f32ec47c2bd5cd174762595f3f22b055ea0245f63de1de9d065
|
data/TODO.org
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
* Conversion to Spreadsheets
|
2
2
|
This is a [[https://github.com/westonganger/spreadsheet_architect][gem]] that I can include into the Table model to convert a table into
|
3
3
|
a spread-sheet, or even a sheet in a multi-sheet spreadsheet file.
|
4
|
+
|
4
5
|
* Formatters
|
5
6
|
Need to think about ways to define formatters for Table for different output
|
6
7
|
types, including tty, color-tty, latex, csv, spreadsheet?
|
8
|
+
|
7
9
|
* Add a Group Boundary concept
|
8
10
|
If I want a table to perform sub-totals at various break points, need to have a
|
9
11
|
way for a table to record its grouping boundaries. Maybe an array of row
|
10
12
|
numbers? Automatically injected by the group-by method?
|
13
|
+
|
14
|
+
* DONE Add uniq method and set operations
|
15
|
+
CLOSED: [2017-03-02 Thu 15:54]
|
16
|
+
- State "WAIT" from "TODO" [2017-03-02 Thu 15:54]
|
17
|
+
- State "TODO" from [2017-03-02 Thu 15:54]
|
18
|
+
For tables, add a method that eliminates any duplicate rows. Perhaps just
|
19
|
+
apply Array#uniq to the columns?
|
data/lib/fat_core/array.rb
CHANGED
@@ -2,4 +2,26 @@ class Array
|
|
2
2
|
def last_i
|
3
3
|
self.size - 1
|
4
4
|
end
|
5
|
+
|
6
|
+
# Return a new array that is the intersection of this Array with other, but
|
7
|
+
# without removing duplicates as the :& method does.
|
8
|
+
def intersect(other)
|
9
|
+
result = []
|
10
|
+
each do |itm|
|
11
|
+
result << itm if other.include?(itm)
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return an array that is the difference between this Array and the other, but
|
17
|
+
# without removing duplicates as the :- method does.
|
18
|
+
def difference(other)
|
19
|
+
result = deep_dup
|
20
|
+
other.each do |itm|
|
21
|
+
if (k = result.index(itm))
|
22
|
+
result.delete_at(k)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
5
27
|
end
|
data/lib/fat_core/hash.rb
CHANGED
@@ -20,6 +20,7 @@ class Hash
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
+
# Change each key of this Hash to its value in key_map
|
23
24
|
def remap_keys(key_map = {})
|
24
25
|
new_hash = {}
|
25
26
|
each_pair do |key, val|
|
@@ -31,4 +32,12 @@ class Hash
|
|
31
32
|
end
|
32
33
|
new_hash
|
33
34
|
end
|
35
|
+
|
36
|
+
# Change the keys of this Hash to new_keys, an array of keys
|
37
|
+
def replace_keys(new_keys)
|
38
|
+
unless keys.size == new_keys.size
|
39
|
+
raise ArgumentError, 'replace_keys: new keys size differs from key size'
|
40
|
+
end
|
41
|
+
to_a.each_with_index.map { |(_k, v), i| [new_keys[i], v] }.to_h
|
42
|
+
end
|
34
43
|
end
|
data/lib/fat_core/table.rb
CHANGED
@@ -304,7 +304,7 @@ module FatCore
|
|
304
304
|
# have N and M rows respectively, the joined table will have N * M
|
305
305
|
# rows.
|
306
306
|
#
|
307
|
-
JOIN_TYPES = [
|
307
|
+
JOIN_TYPES = [:inner, :left, :right, :full, :cross]
|
308
308
|
|
309
309
|
def join(other, *exps, join_type: :inner)
|
310
310
|
raise ArgumentError, 'need other table as first argument to join' unless other.is_a?(Table)
|
data/lib/fat_core/version.rb
CHANGED
data/spec/lib/array_spec.rb
CHANGED
@@ -5,4 +5,20 @@ describe Array do
|
|
5
5
|
letters = ('a'..'z').to_a
|
6
6
|
expect(letters.last_i).to eq(25)
|
7
7
|
end
|
8
|
+
|
9
|
+
it 'intersection' do
|
10
|
+
expect(%w(A A B A C A B).intersect(%w(A B A))).to eq(%w(A A B A A B))
|
11
|
+
expect(%w(A A B A C A B).intersect(%w(A B))).to eq(%w(A A B A A B))
|
12
|
+
expect(%w(A A B A C A B).intersect(%w(A))).to eq(%w(A A A A))
|
13
|
+
expect(%w(A A B A C A B).intersect(%w(B))).to eq(%w(B B))
|
14
|
+
expect(%w(A A B A C A B).intersect(%w(C))).to eq(%w(C))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'difference' do
|
18
|
+
expect(%w(A A B A C A B).difference(%w(A B A))).to eq(%w(A C A B))
|
19
|
+
expect(%w(A A B A C A B).difference(%w(A B))).to eq(%w(A A C A B))
|
20
|
+
expect(%w(A A B A C A B).difference(%w(A))).to eq(%w(A B A C A B))
|
21
|
+
expect(%w(A A B A C A B).difference(%w(B))).to eq(%w(A A A C A B))
|
22
|
+
expect(%w(A A B A C A B).difference(%w(C))).to eq(%w(A A B A A B))
|
23
|
+
end
|
8
24
|
end
|
data/spec/lib/table_spec.rb
CHANGED
@@ -519,61 +519,6 @@ EOS
|
|
519
519
|
end
|
520
520
|
end
|
521
521
|
|
522
|
-
describe 'union' do
|
523
|
-
it 'should be able to union with a compatible table' do
|
524
|
-
aoh = [
|
525
|
-
{ a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
|
526
|
-
{ a: '4', 'Two words' => '5', c: 6412, d: 'orange' },
|
527
|
-
{ a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
|
528
|
-
]
|
529
|
-
tab1 = Table.new(aoh)
|
530
|
-
aoh2 = [
|
531
|
-
{ t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
|
532
|
-
{ t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
|
533
|
-
{ t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
|
534
|
-
]
|
535
|
-
tab2 = Table.new(aoh2)
|
536
|
-
utab = tab1.union(tab2)
|
537
|
-
expect(utab.rows.size).to eq(6)
|
538
|
-
end
|
539
|
-
|
540
|
-
it 'should throw an exception for union with different sized tables' do
|
541
|
-
aoh = [
|
542
|
-
{ a: '5', 'Two words' => '20', c: '3,123' },
|
543
|
-
{ a: '4', 'Two words' => '5', c: 6412 },
|
544
|
-
{ a: '7', 'Two words' => '8', c: '$1,888' }
|
545
|
-
]
|
546
|
-
tab1 = Table.new(aoh)
|
547
|
-
aoh2 = [
|
548
|
-
{ t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
|
549
|
-
{ t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
|
550
|
-
{ t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
|
551
|
-
]
|
552
|
-
tab2 = Table.new(aoh2)
|
553
|
-
expect {
|
554
|
-
tab1.union(tab2)
|
555
|
-
}.to raise_error(/different number of columns/)
|
556
|
-
end
|
557
|
-
|
558
|
-
it 'should throw an exception for union with different types' do
|
559
|
-
aoh = [
|
560
|
-
{ a: '5', 'Two words' => '20', s: '5143', c: '3123' },
|
561
|
-
{ a: '4', 'Two words' => '5', s: 412, c: 6412 },
|
562
|
-
{ a: '7', 'Two words' => '8', s: '$1821', c: '$1888' }
|
563
|
-
]
|
564
|
-
tab1 = Table.new(aoh)
|
565
|
-
aoh2 = [
|
566
|
-
{ t: '8', 'Two worlds' => '65', s: '2016-01-17', u: 'kiwi' },
|
567
|
-
{ t: '87', 'Two worlds' => '12', s: Date.today, u: 'banana' },
|
568
|
-
{ t: '13', 'Two worlds' => '11', s: '[2015-05-21]', u: 'grape' }
|
569
|
-
]
|
570
|
-
tab2 = Table.new(aoh2)
|
571
|
-
expect {
|
572
|
-
tab1.union(tab2)
|
573
|
-
}.to raise_error(/different types/)
|
574
|
-
end
|
575
|
-
end
|
576
|
-
|
577
522
|
describe 'select' do
|
578
523
|
it 'should be able to select by column names' do
|
579
524
|
aoh = [
|
@@ -669,6 +614,7 @@ EOS
|
|
669
614
|
end
|
670
615
|
|
671
616
|
describe 'join' do
|
617
|
+
# These tests are taken from https://www.tutorialspoint.com/postgresql/postgresql_using_joins.htm
|
672
618
|
before :all do
|
673
619
|
@tab_a = Table.new([
|
674
620
|
{ id: 1, name: 'Paul', age: 32, address: 'California', salary: 20000, join_date: '2001-07-13' },
|
@@ -769,6 +715,93 @@ EOS
|
|
769
715
|
end
|
770
716
|
end
|
771
717
|
|
718
|
+
describe 'set operations' do
|
719
|
+
before :all do
|
720
|
+
aoh = [
|
721
|
+
{ a: '5', 'Two words' => '20', c: '3,123', d: 'apple' },
|
722
|
+
{ a: '4', 'Two words' => '5', c: 6412, d: 'orange' },
|
723
|
+
{ a: '4', 'Two words' => '5', c: 6412, d: 'orange' },
|
724
|
+
{ a: '7', 'Two words' => '8', c: '$1,888', d: 'apple' }
|
725
|
+
]
|
726
|
+
@tab1 = Table.new(aoh)
|
727
|
+
aoh2 = [
|
728
|
+
{ t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
|
729
|
+
{ t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
|
730
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
731
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
732
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
733
|
+
{ t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
|
734
|
+
]
|
735
|
+
@tab2 = Table.new(aoh2)
|
736
|
+
aoh2e = [
|
737
|
+
{ t: '8', 'Two worlds' => '65', s: '5,143', u: 'kiwi' },
|
738
|
+
{ t: '87', 'Two worlds' => '12', s: 412, u: 'banana' },
|
739
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
740
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
741
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
742
|
+
{ t: '4', 'Two worlds' => '5', s: 6412, u: 'orange' },
|
743
|
+
{ t: '13', 'Two worlds' => '11', s: '$1,821', u: 'grape' }
|
744
|
+
]
|
745
|
+
@tab2e = Table.new(aoh2e)
|
746
|
+
# Fewer columns
|
747
|
+
aoh3 = [
|
748
|
+
{ a: '5', 'Two words' => '20', c: '3,123' },
|
749
|
+
{ a: '4', 'Two words' => '5', c: 6412 },
|
750
|
+
{ a: '7', 'Two words' => '8', c: '$1,888' }
|
751
|
+
]
|
752
|
+
@tab3 = Table.new(aoh3)
|
753
|
+
# Different types
|
754
|
+
aoh4 = [
|
755
|
+
{ t: '8', 'Two worlds' => '65', s: '2016-01-17', u: 'kiwi' },
|
756
|
+
{ t: '87', 'Two worlds' => '12', s: Date.today, u: 'banana' },
|
757
|
+
{ t: '13', 'Two worlds' => '11', s: '[2015-05-21]', u: 'grape' }
|
758
|
+
]
|
759
|
+
@tab4 = Table.new(aoh4)
|
760
|
+
end
|
761
|
+
|
762
|
+
it 'union' do
|
763
|
+
utab = @tab1.union(@tab2)
|
764
|
+
expect(utab.size).to eq(6)
|
765
|
+
end
|
766
|
+
|
767
|
+
it 'union_all' do
|
768
|
+
utab = @tab1.union_all(@tab2)
|
769
|
+
expect(utab.size).to eq(10)
|
770
|
+
end
|
771
|
+
|
772
|
+
it 'intersect' do
|
773
|
+
utab = @tab1.intersect(@tab2)
|
774
|
+
expect(utab.size).to eq(1)
|
775
|
+
end
|
776
|
+
|
777
|
+
it 'intersect_all' do
|
778
|
+
utab = @tab1.intersect_all(@tab2)
|
779
|
+
expect(utab.size).to eq(2)
|
780
|
+
end
|
781
|
+
|
782
|
+
it 'except' do
|
783
|
+
utab = @tab2.except(@tab1)
|
784
|
+
expect(utab.size).to eq(4)
|
785
|
+
end
|
786
|
+
|
787
|
+
it 'except_all' do
|
788
|
+
utab = @tab2e.except_all(@tab1)
|
789
|
+
expect(utab.size).to eq(5)
|
790
|
+
end
|
791
|
+
|
792
|
+
it 'should throw an exception for union with different sized tables' do
|
793
|
+
expect {
|
794
|
+
@tab1.union(@tab3)
|
795
|
+
}.to raise_error(/different number of columns/)
|
796
|
+
end
|
797
|
+
|
798
|
+
it 'should throw an exception for union with different types' do
|
799
|
+
expect {
|
800
|
+
@tab1.union(@tab4)
|
801
|
+
}.to raise_error(/different column types/)
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
772
805
|
describe 'output' do
|
773
806
|
it 'should be able to return itself as an array of arrays' do
|
774
807
|
aoh = [
|