fat_core 1.4.0 → 1.5.0
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/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 = [
|