Module: StackingOrder
- Defined in:
- lib/stacking_order.rb,
lib/stacking_order/version.rb
Overview
Calculates how to print entries in a grid so that stack-cut pages reassemble into sequential order.
Constant Summary collapse
- VERSION =
'1.2.0'
Class Method Summary collapse
- .apply_two_sided_flip(result, rows, columns) ⇒ Object
- .flip_page_rows(page, rows, columns) ⇒ Object
-
.order(entries:, rows:, columns:, two_sided_flipped: false) ⇒ Array<Integer, nil>
Public API for calculating the stacking order for printing entries on pages with a grid layout.
- .pad_page(page, cells_per_page) ⇒ Object
-
.visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout) ⇒ Object
Utility method that prints the layout for the provided configuration, showing the entries on each page and the resulting stacks after cutting.
Class Method Details
.apply_two_sided_flip(result, rows, columns) ⇒ Object
84 85 86 87 88 89 90 |
# File 'lib/stacking_order.rb', line 84 def apply_two_sided_flip(result, rows, columns) cells_per_page = rows * columns result.each_slice(cells_per_page).with_index.flat_map do |page, page_index| padded_page = pad_page(page, cells_per_page) page_index.odd? ? flip_page_rows(padded_page, rows, columns) : padded_page end end |
.flip_page_rows(page, rows, columns) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/stacking_order.rb', line 98 def flip_page_rows(page, rows, columns) if rows == 1 row_slice = page.slice(0, columns) || [] return row_slice.reverse end flipped = [] rows.times do |row_index| source_row_index = rows - 1 - row_index row_slice = page.slice(source_row_index * columns, columns) || [] flipped.concat(row_slice) end flipped end |
.order(entries:, rows:, columns:, two_sided_flipped: false) ⇒ Array<Integer, nil>
Public API for calculating the stacking order for printing entries on pages with a grid layout. See README for details.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/stacking_order.rb', line 17 def order(entries:, rows:, columns:, two_sided_flipped: false) validate_arguments!(entries, rows, columns) return [] if entries.zero? cells_per_page = rows * columns num_pages = (entries.to_f / cells_per_page).ceil # In two-sided printing, every physical sheet of paper carries a front # and a back PDF page. An odd page count leaves the last paper with # content only on the front, producing cut folios whose backs are blank. num_pages += 1 if two_sided_flipped && num_pages.odd? result = [] num_pages.times do |page_index| cells_per_page.times do |cell_index| entry_number = (cell_index * num_pages) + page_index + 1 result << (entry_number <= entries ? entry_number : nil) end end if two_sided_flipped result = apply_two_sided_flip(result, rows, columns) end result.pop while result.last.nil? result end |
.pad_page(page, cells_per_page) ⇒ Object
92 93 94 95 96 |
# File 'lib/stacking_order.rb', line 92 def pad_page(page, cells_per_page) return page if page.length == cells_per_page page + Array.new(cells_per_page - page.length) end |
.visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout) ⇒ Object
Utility method that prints the layout for the provided configuration, showing the entries on each page and the resulting stacks after cutting. Useful for debugging or CLI demos.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/stacking_order.rb', line 49 def visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout) result = order(entries: entries, rows: rows, columns: columns, two_sided_flipped: two_sided_flipped) cells_per_page = rows * columns num_pages = (entries.to_f / cells_per_page).ceil io.puts io.puts('=' * 60) io.puts("Visualizing stacking order for #{entries} entries, #{rows} row(s), #{columns} column(s)") io.puts('=' * 60) io.puts("Result: #{result.inspect}") io.puts("\nPages layout:") result.each_slice(cells_per_page).with_index do |page, page_num| io.puts("\nPage #{page_num + 1}:") page.each_slice(columns).with_index do |row_values, row_num| formatted = row_values.map { |value| value ? format('%3d', value) : 'nil' }.join(' | ') io.puts(" Row #{row_num + 1}: #{formatted}") end end io.puts("\nAfter cutting and stacking:") cells_per_page.times do |cell_idx| row_idx = cell_idx / columns col_idx = cell_idx % columns stack = [] num_pages.times do |page_idx| pos = (page_idx * cells_per_page) + cell_idx stack << (pos < result.length ? result[pos] : nil) end io.puts(" Position [#{row_idx + 1},#{col_idx + 1}] stack (bottom→top): #{stack.compact.join(', ')}") end end |