fat_table 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68369046961f41a0a22139e3b1b3f9f3465fc6e5e661d36f9ed09ab60d4fc99e
4
- data.tar.gz: 5ae22c1c1e40735f13734366172aa6aae66102c492d4911f8dd370a6fa29cf15
3
+ metadata.gz: f35f99181e39d7569ce7df958ae92742617826e54b8ed2c6352b73c5723a3d44
4
+ data.tar.gz: d37acb3f0be27191bafa17ae30b51dfd2db2c4a5d97e6c80fa5399f2618ea98b
5
5
  SHA512:
6
- metadata.gz: 470727e6d9afc2ed93658fecc7cab7c36f6b14a28d4682aeb8d54153058591e39a02f77ea9d8966b6d857ca1c463479350adc11e63952fde8404e2f9b614f3e4
7
- data.tar.gz: f13f33a01c5106c8b8a877fa61b16c1b32179a49c67fe7d542f339a384cbfc437037ac567d96cbb9e4f78e046ae46832e60d8f7d57313d95bf9b70778481f847
6
+ metadata.gz: eafd2077939c57673358a680490ccbe48218e8b290540790f3526b5945337e53c9366369c255adcc85e01916ad012cbad12132593def15350fd3993304bc5a30
7
+ data.tar.gz: e7a542986752ac4f632e7344c49080786e0e52ecbe224a0644a6da7b4ec65dd8ca2b9abe842ee295ad7cf19a7a0ccd0e93b22632716c95533665a21d14b5cc83
data/README.org CHANGED
@@ -81,6 +81,8 @@ org-mode buffer as an org-table, ready for processing by other code blocks.
81
81
  - [[#from-arrays-of-hashes][From Arrays of Hashes]]
82
82
  - [[#from-sql-queries][From SQL queries]]
83
83
  - [[#marking-groups-in-input][Marking Groups in Input]]
84
+ - [[#manually][Manually]]
85
+ - [[#when-reading-in-tables][When Reading in Tables]]
84
86
  - [[#accessing-parts-of-tables][Accessing Parts of Tables]]
85
87
  - [[#rows][Rows]]
86
88
  - [[#columns-1][Columns]]
@@ -861,6 +863,14 @@ creates will be used for all subsequent ~.from_sql~ calls until ~.connect~ is
861
863
  called again.
862
864
 
863
865
  *** Marking Groups in Input
866
+ **** Manually
867
+ At any point, you can add a boundary to a table by invokong the
868
+ ~mark_boundary~ method. Without an argument, it adds the boundary to the end
869
+ of the table; with a numeric argument, ~n~, it adds the boundary after row
870
+ ~n~.
871
+
872
+ **** When Reading in Tables
873
+
864
874
  ~FatTable~ tables has a concept of "groups" of rows that play a role in many of
865
875
  the methods for operating on them as explained [[Groups][below]].
866
876
 
@@ -53,7 +53,14 @@ module FatTable
53
53
  class Table
54
54
  # An Array of FatTable::Columns that constitute the table.
55
55
  attr_reader :columns
56
- attr_accessor :boundaries
56
+
57
+ # Record boundaries set explicitly with mark_boundaries or from reading
58
+ # hlines from input. When we want to access boundaries, however, we want
59
+ # to add an implict boundary at the last row of the table. Since, as the
60
+ # table grows, the implict boundary changes index, we synthesize the
61
+ # boundaries by dynamically adding the final boundary with the #boundaries
62
+ # method call.
63
+ attr_accessor :explicit_boundaries
57
64
 
58
65
  ###########################################################################
59
66
  # Constructors
@@ -64,7 +71,7 @@ module FatTable
64
71
  # Return an empty FatTable::Table object.
65
72
  def initialize(*heads)
66
73
  @columns = []
67
- @boundaries = []
74
+ @explicit_boundaries = []
68
75
  unless heads.empty?
69
76
  heads.each do |h|
70
77
  @columns << Column.new(header: h)
@@ -84,11 +91,10 @@ module FatTable
84
91
 
85
92
  def __empty!
86
93
  @columns = []
87
- @boundaries = []
94
+ @explicit_boundaries = []
88
95
  self
89
96
  end
90
97
 
91
-
92
98
  # :category: Constructors
93
99
 
94
100
  # Construct a Table from the contents of a CSV file named +fname+. Headers
@@ -454,8 +460,6 @@ module FatTable
454
460
  # large table, that would require that we construct all the rows for a range
455
461
  # of any size.
456
462
  def rows_range(first = 0, last = nil) # :nodoc:
457
- last ||= size - 1
458
- last = [last, 0].max
459
463
  raise UserError, 'first must be <= last' unless first <= last
460
464
 
461
465
  rows = []
@@ -501,6 +505,8 @@ module FatTable
501
505
  # the headers from the body) marks a boundary for the row immediately
502
506
  # preceding the hline.
503
507
  #
508
+ # Boundaries can also be added manually with the +mark_boundary+ method.
509
+ #
504
510
  # The #order_by method resets the boundaries then adds boundaries at the
505
511
  # last row of each group of rows on which the sort keys were equal as a
506
512
  # boundary.
@@ -536,7 +542,7 @@ module FatTable
536
542
 
537
543
  # Return the number of groups in the table.
538
544
  def number_of_groups
539
- boundaries.size
545
+ empty? ? 0 : boundaries.size
540
546
  end
541
547
 
542
548
  # Return the range of row indexes for boundary number +k+
@@ -546,17 +552,13 @@ module FatTable
546
552
  raise ArgumentError, "boundary number '#{k}' out of range in boundary_row_range"
547
553
  end
548
554
 
549
- if boundaries.empty?
550
- (0..size-1)
551
- elsif boundaries.size == 1
555
+ if boundaries.size == 1
552
556
  (0..boundaries.first)
553
- else
557
+ elsif k.zero?
554
558
  # Keep index at or above zero
555
- if k.zero?
556
- (0..boundaries[k])
557
- else
558
- (boundaries[k-1]+1..boundaries[k])
559
- end
559
+ (0..boundaries[k])
560
+ else
561
+ ((boundaries[k - 1] + 1)..boundaries[k])
560
562
  end
561
563
  end
562
564
 
@@ -581,19 +583,32 @@ module FatTable
581
583
  # the groups displayed in the output. This modifies the input table, so is a
582
584
  # departure from the otherwise immutability of Tables.
583
585
  def degroup!
584
- @boundaries = []
586
+ self.explicit_boundaries = []
585
587
  self
586
588
  end
587
589
 
588
590
  # Mark a group boundary at row +row+, and if +row+ is +nil+, mark the last
589
- # row in the table as a group boundary. This is mainly used for internal
590
- # purposes.
591
- def mark_boundary(row = nil) # :nodoc:
592
- if row
593
- boundaries.push(row)
594
- else
595
- boundaries.push(size - 1)
591
+ # row in the table as a group boundary. An attempt to add a boundary to
592
+ # an empty table has no effect. We adopt the convention that the last row
593
+ # of the table always marks an implicit boundary even if it is not in the
594
+ # @explicit_boundaries array. When we "mark" a boundary, we intend it to
595
+ # be an explicit boundary, even if it marks the last row of the table.
596
+ def mark_boundary(row_num = nil)
597
+ return self if empty?
598
+
599
+ if row_num
600
+ unless row_num < size
601
+ raise ArgumentError, "can't mark boundary at row #{row_num}, last row is #{size - 1}"
602
+ end
603
+ unless row_num >= 0
604
+ raise ArgumentError, "can't mark boundary at non-positive row #{row_num}"
605
+ end
606
+ explicit_boundaries.push(row_num)
607
+ elsif size > 0
608
+ explicit_boundaries.push(size - 1)
596
609
  end
610
+ normalize_boundaries
611
+ self
597
612
  end
598
613
 
599
614
  # :stopdoc:
@@ -601,10 +616,21 @@ module FatTable
601
616
  # Make sure size - 1 is last boundary and that they are unique and sorted.
602
617
  def normalize_boundaries
603
618
  unless empty?
604
- boundaries.push(size - 1) unless boundaries.include?(size - 1)
605
- self.boundaries = boundaries.uniq.sort
619
+ self.explicit_boundaries = explicit_boundaries.uniq.sort
620
+ end
621
+ explicit_boundaries
622
+ end
623
+
624
+ # Return the explicit_boundaries, augmented by an implicit boundary for
625
+ # the end of the table, unless it's already an implicit boundary.
626
+ def boundaries
627
+ return [] if empty?
628
+
629
+ if explicit_boundaries.last == size - 1
630
+ explicit_boundaries
631
+ else
632
+ explicit_boundaries + [size - 1]
606
633
  end
607
- boundaries
608
634
  end
609
635
 
610
636
  protected
@@ -613,24 +639,43 @@ module FatTable
613
639
  # increase each of the indexes in bounds by shift. This is used in the
614
640
  # #union_all method.
615
641
  def append_boundaries(bounds, shift: 0)
616
- @boundaries += bounds.map { |k| k + shift }
642
+ @explicit_boundaries += bounds.map { |k| k + shift }
617
643
  end
618
644
 
619
- # Return the group number to which row ~row~ belongs. Groups, from the
620
- # user's point of view are indexed starting at 1.
621
- def row_index_to_group_index(row)
645
+ # Return the group number to which row ~row_num~ belongs. Groups, from the
646
+ # user's point of view are indexed starting at 0.
647
+ def row_index_to_group_index(row_num)
622
648
  boundaries.each_with_index do |b_last, g_num|
623
- return (g_num + 1) if row <= b_last
649
+ return (g_num + 1) if row_num <= b_last
650
+ end
651
+ 0
652
+ end
653
+
654
+ # Return the index of the first row in group number +grp_num+
655
+ def first_row_num_in_group(grp_num)
656
+ if grp_num >= boundaries.size || grp_num < 0
657
+ raise ArgumentError, "group number #{grp_num} out of bounds"
624
658
  end
625
- 1
659
+
660
+ grp_num.zero? ? 0 : boundaries[grp_num - 1] + 1
626
661
  end
627
662
 
628
- def group_rows(row) # :nodoc:
663
+ # Return the index of the last row in group number +grp_num+
664
+ def last_row_num_in_group(grp_num)
665
+ if grp_num > boundaries.size || grp_num < 0
666
+ raise ArgumentError, "group number #{grp_num} out of bounds"
667
+ else
668
+ boundaries[grp_num]
669
+ end
670
+ end
671
+
672
+ # Return the rows for group number +grp_num+.
673
+ def group_rows(grp_num) # :nodoc:
629
674
  normalize_boundaries
630
- return [] unless row < boundaries.size
675
+ return [] unless grp_num < boundaries.size
631
676
 
632
- first = row.zero? ? 0 : boundaries[row - 1] + 1
633
- last = boundaries[row]
677
+ first = first_row_num_in_group(grp_num)
678
+ last = last_row_num_in_group(grp_num)
634
679
  rows_range(first, last)
635
680
  end
636
681
 
@@ -876,7 +921,7 @@ module FatTable
876
921
  ev.eval_after_hook(locals: new_row)
877
922
  result << new_row
878
923
  end
879
- result.boundaries = boundaries
924
+ result.explicit_boundaries = explicit_boundaries
880
925
  result.normalize_boundaries
881
926
  result
882
927
  end
@@ -1013,8 +1058,6 @@ module FatTable
1013
1058
  set_operation(other, :difference, distinct: false)
1014
1059
  end
1015
1060
 
1016
- public
1017
-
1018
1061
  # An Array of symbols for the valid join types.
1019
1062
  JOIN_TYPES = %i[inner left right full cross].freeze
1020
1063
 
@@ -1123,14 +1166,14 @@ module FatTable
1123
1166
  type: join_type)
1124
1167
  result << out_row
1125
1168
  end
1126
- next unless %i[left full].include?(join_type)
1169
+ next unless [:left, :full].include?(join_type)
1127
1170
  next if self_row_matched
1128
1171
 
1129
1172
  result << build_out_row(row_a: self_row,
1130
1173
  row_b: other_row_nils,
1131
1174
  type: join_type)
1132
1175
  end
1133
- if %i[right full].include?(join_type)
1176
+ if [:right, :full].include?(join_type)
1134
1177
  other_rows.each_with_index do |other_row, k|
1135
1178
  next if other_row_matches[k]
1136
1179
 
@@ -1259,7 +1302,7 @@ module FatTable
1259
1302
  partial_result = nil
1260
1303
  else
1261
1304
  # First of a pair of _a or _b
1262
- partial_result = String.new("(#{a_head}_a == ")
1305
+ partial_result = +"(#{a_head}_a == "
1263
1306
  end
1264
1307
  last_sym = a_head
1265
1308
  when /\A(?<sy>.*)_b\z/
@@ -1278,7 +1321,7 @@ module FatTable
1278
1321
  partial_result = nil
1279
1322
  else
1280
1323
  # First of a pair of _a or _b
1281
- partial_result = String.new("(#{b_head}_b == ")
1324
+ partial_result = +"(#{b_head}_b == "
1282
1325
  end
1283
1326
  b_common_heads << b_head
1284
1327
  last_sym = b_head
@@ -1385,15 +1428,6 @@ module FatTable
1385
1428
 
1386
1429
  # :category: Constructors
1387
1430
 
1388
- # Add a group boundary mark at the given row, or at the end of the table
1389
- # by default.
1390
- def add_boundary(at_row = nil)
1391
- row = at_row || (size - 1)
1392
- @boundaries << row
1393
- end
1394
-
1395
- # :category: Constructors
1396
-
1397
1431
  # Add a +row+ represented by a Hash having the headers as keys. If +mark:+
1398
1432
  # is set true, mark this row as a boundary. All tables should be built
1399
1433
  # ultimately using this method as a primitive.
@@ -1603,8 +1637,7 @@ module FatTable
1603
1637
  result.mark_boundary if k == size - 1 && add_boundaries
1604
1638
  end
1605
1639
  if inherit_boundaries
1606
- result.boundaries = normalize_boundaries
1607
- other.normalize_boundaries
1640
+ result.explicit_boundaries = boundaries
1608
1641
  result.append_boundaries(other.boundaries, shift: size)
1609
1642
  end
1610
1643
  result.normalize_boundaries
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FatTable
4
4
  # The current version of FatTable
5
- VERSION = '0.5.1'
5
+ VERSION = '0.5.2'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fat_table
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel E. Doherty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-21 00:00:00.000000000 Z
11
+ date: 2022-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler