stacking-order 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13c66a0c61b2744526f1e6113775629730d07cda8d528630c103f5ae276bce4f
4
- data.tar.gz: b8133c884d749092af5cb11e4b8b6879127cefb6a1f557fb95ba2eac888d738c
3
+ metadata.gz: 480df27d8a79f4868585d1e3d7bba83e25c1567405b36ab60d38d4bab161c602
4
+ data.tar.gz: 0d729b3fdeb4a8306a2f35930aa549ba3f800e594871be54241caafada54a240
5
5
  SHA512:
6
- metadata.gz: 0eb9c0442393fea05b44c548f4ce5f249cdc64e0e13843cfc8200ba15e0f08797eda11f3ed9856b00cc521d36ef0d815d7f66cd6bcb7fd562f0c58c373afc4d5
7
- data.tar.gz: 0d2a23b921e1341f76e0373844150e3fa633d83f186cbb3e6b2ee8817150d98898933ec7cd492ea621831e83f7007203d7bbe2b1caf6198a4742b54809534628
6
+ metadata.gz: a02a2a4642f48f6d81a9e3aa3d91497b62ae2ceb4a86d1e71efa27e282945e0af775da8ac0098ab978cf2a64dbd8e60497d37dfdf78e6ccfeeaf602010010a5b
7
+ data.tar.gz: ba7e487c563a741ce4d518bb4974459fae90ed0aaa8b696ca2451cfd512d8283c3d128e5e52960bd31329aa8f1a16f3f394faa67321907748c1d614106a5f391
data/README.md CHANGED
@@ -2,8 +2,14 @@
2
2
 
3
3
  A tiny Ruby gem that computes how to arrange records on a paginated grid so that,
4
4
  after cutting the printed stack into columns and re-stacking them, the final pile
5
- remains in sequential order. It is useful for printing badges, tickets, or any
6
- other grid-based layout that is cut in bulk.
5
+ remains in sequential order.
6
+
7
+ It is useful for printing badges, tickets, or any other grid-based layout that is
8
+ cut in bulk.
9
+
10
+ It has a `two_sided_flipped` option to support printing on both sides of the
11
+ paper, with the second side flipped, which can be used for printing traditional
12
+ Tibetan books (called pechas) or for similar texts from various traditions.
7
13
 
8
14
  ## Installation
9
15
 
@@ -28,6 +34,9 @@ order = StackingOrder.order(entries: 13, rows: 2, columns: 2)
28
34
  # => [1, 5, 9, 13, 2, 6, 10, nil, 3, 7, 11, nil, 4, 8, 12]
29
35
  # nil entries mark empty slots on the final, partially filled page.
30
36
 
37
+ StackingOrder.order(entries: 8, rows: 2, columns: 2, two_sided_flipped: true)
38
+ # => [1, 5, 6, 2, 3, 7, 8, 4]
39
+
31
40
  StackingOrder.visualize(entries: 6, rows: 2, columns: 2)
32
41
  # Prints page-by-page grids plus the stack order after cutting.
33
42
  ```
@@ -78,11 +87,12 @@ page-by-page grids and stack order) and returns non-zero on invalid arguments.
78
87
 
79
88
  ### Real-world usage
80
89
 
81
- This gem powers the stacking order calculations in
82
- [pecha-printer](https://github.com/jerefrer/pecha-printer), which itself backs
83
- the hosted service at <https://pecha-printer.frerejeremy.me>. By publishing the
84
- logic as a gem, the same algorithm can be reused by other Ruby/Rails projects or
85
- invoked manually via the CLI.
90
+ This gem powers [stacked-pdf-generator](https://github.com/jeremy/stacked-pdf-generator), which provides the pdfjam/podofocrop
91
+ tooling for producing final print-ready stacks.
92
+
93
+ In turn, stacked-pdf-generator is used by [pecha-printer](https://github.com/jerefrer/pecha-printer) and the hosted service at
94
+ <https://pecha-printer.frerejeremy.me>. Publishing the stacking logic separately lets other
95
+ Ruby/Rails projects (or CLI scripts) reuse it without needing the full PDF pipeline.
86
96
 
87
97
  ## Development
88
98
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StackingOrder
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -14,7 +14,7 @@ module StackingOrder
14
14
  # @param rows [Integer] Number of rows in the grid on each page
15
15
  # @param columns [Integer] Number of columns in the grid on each page
16
16
  # @return [Array<Integer, nil>] The order in which to print entries (with nil for empty cells)
17
- def order(entries:, rows:, columns:)
17
+ def order(entries:, rows:, columns:, two_sided_flipped: false)
18
18
  validate_arguments!(entries, rows, columns)
19
19
 
20
20
  return [] if entries.zero?
@@ -31,6 +31,10 @@ module StackingOrder
31
31
  end
32
32
  end
33
33
 
34
+ if two_sided_flipped
35
+ result = apply_two_sided_flip(result, rows, columns)
36
+ end
37
+
34
38
  result.pop while result.last.nil?
35
39
  result
36
40
  end
@@ -38,8 +42,8 @@ module StackingOrder
38
42
  # Utility method that prints the layout for the provided configuration,
39
43
  # showing the entries on each page and the resulting stacks after cutting.
40
44
  # Useful for debugging or CLI demos.
41
- def visualize(entries:, rows:, columns:, io: $stdout)
42
- result = order(entries: entries, rows: rows, columns: columns)
45
+ def visualize(entries:, rows:, columns:, two_sided_flipped: false, io: $stdout)
46
+ result = order(entries: entries, rows: rows, columns: columns, two_sided_flipped: two_sided_flipped)
43
47
  cells_per_page = rows * columns
44
48
  num_pages = (entries.to_f / cells_per_page).ceil
45
49
 
@@ -73,6 +77,35 @@ module StackingOrder
73
77
  end
74
78
  end
75
79
 
80
+ def apply_two_sided_flip(result, rows, columns)
81
+ cells_per_page = rows * columns
82
+ result.each_slice(cells_per_page).with_index.flat_map do |page, page_index|
83
+ padded_page = pad_page(page, cells_per_page)
84
+ page_index.odd? ? flip_page_rows(padded_page, rows, columns) : padded_page
85
+ end
86
+ end
87
+
88
+ def pad_page(page, cells_per_page)
89
+ return page if page.length == cells_per_page
90
+
91
+ page + Array.new(cells_per_page - page.length)
92
+ end
93
+
94
+ def flip_page_rows(page, rows, columns)
95
+ if rows == 1
96
+ row_slice = page.slice(0, columns) || []
97
+ return row_slice.reverse
98
+ end
99
+
100
+ flipped = []
101
+ rows.times do |row_index|
102
+ source_row_index = rows - 1 - row_index
103
+ row_slice = page.slice(source_row_index * columns, columns) || []
104
+ flipped.concat(row_slice)
105
+ end
106
+ flipped
107
+ end
108
+
76
109
  def validate_arguments!(entries, rows, columns)
77
110
  raise ArgumentError, 'entries must be non-negative' if entries.negative?
78
111
  raise ArgumentError, 'rows must be positive' if rows <= 0
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stacking-order
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-11-25 00:00:00.000000000 Z
10
+ date: 2025-11-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: minitest