acro_that 0.1.2 → 0.1.4
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/CHANGELOG.md +16 -0
- data/README.md +26 -0
- data/lib/acro_that/actions/add_field.rb +2 -55
- data/lib/acro_that/actions/base.rb +4 -0
- data/lib/acro_that/actions/remove_field.rb +1 -5
- data/lib/acro_that/dict_scan.rb +7 -0
- data/lib/acro_that/document.rb +53 -43
- data/lib/acro_that/page.rb +91 -0
- data/lib/acro_that/version.rb +1 -1
- data/lib/acro_that.rb +1 -0
- data/publish +183 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 40016774a590828e59c4c9ea4331a8d170ccd536d7522cbdb193fefda3f28333
|
|
4
|
+
data.tar.gz: bade6f113359d96d1f7c1a85efd7033732350c0b19bf40dd412e104da359aa5a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60e6c6afd93cfd8911c0b0a0d4b6b080cb2c8af85a104cf3fd09f8fc7f9ac642999a8d5694c374ad64b71d4aa769f6d8b390cc82829317abd64598aa42e7280f
|
|
7
|
+
data.tar.gz: 31762cf9f6f285edd78976692e9c5bab7a67cf6298a03c8d4208b02927639be29e0d1f4ca1f14c3f1c170b9f617404e0931dc8bbedd17de79fcee5c80035dd29
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.3] - 2025-01-XX
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Fixed bug where fields added to multi-page PDFs were all placed on the same page. Fields now correctly appear on their specified pages when using the `page` option in `add_field`.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Refactored page-finding logic to eliminate code duplication across `Document` and `AddField` classes
|
|
15
|
+
- Unified page discovery through `Document#find_all_pages` and `Document#find_page_by_number` methods
|
|
16
|
+
- Updated all page detection patterns to use centralized `DictScan.is_page?` utility method
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `DictScan.is_page?` utility method for consistent page object detection across the codebase
|
|
20
|
+
- `Document#find_all_pages` private method for unified page discovery in document order
|
|
21
|
+
- `Document#find_page_by_number` private method for finding pages by page number
|
|
22
|
+
- Exposed `find_page_by_number` through `Base` module for use in action classes
|
|
23
|
+
|
|
8
24
|
## [0.1.1] - 2025-10-31
|
|
9
25
|
|
|
10
26
|
### Added
|
data/README.md
CHANGED
|
@@ -234,6 +234,32 @@ fields.each do |field|
|
|
|
234
234
|
end
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
+
#### `#list_pages`
|
|
238
|
+
Returns an array of `Page` objects representing all pages in the document. Each `Page` object provides page information and methods to add fields to that specific page.
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
pages = doc.list_pages
|
|
242
|
+
pages.each do |page|
|
|
243
|
+
puts "Page #{page.page_number}: #{page.width}x#{page.height}"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Add fields to specific pages - the page is automatically set!
|
|
247
|
+
first_page = pages[0]
|
|
248
|
+
first_page.add_field("Name", x: 100, y: 700, width: 200, height: 20)
|
|
249
|
+
|
|
250
|
+
second_page = pages[1]
|
|
251
|
+
second_page.add_field("Email", x: 100, y: 650, width: 200, height: 20)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Page Object Methods:**
|
|
255
|
+
- `page.page_number` - Returns the page number (1-indexed)
|
|
256
|
+
- `page.width` - Page width in points
|
|
257
|
+
- `page.height` - Page height in points
|
|
258
|
+
- `page.ref` - Page object reference `[obj_num, gen_num]`
|
|
259
|
+
- `page.metadata` - Hash containing page metadata (rotation, boxes, etc.)
|
|
260
|
+
- `page.add_field(name, options)` - Add a field to this page (page number is automatically set)
|
|
261
|
+
- `page.to_h` - Convert to hash for backward compatibility
|
|
262
|
+
|
|
237
263
|
#### `#add_field(name, options)`
|
|
238
264
|
Adds a new form field to the document. Options include:
|
|
239
265
|
- `value`: Default value for the field (String)
|
|
@@ -153,61 +153,8 @@ module AcroThat
|
|
|
153
153
|
end
|
|
154
154
|
|
|
155
155
|
def find_page_ref(page_num)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
next unless body
|
|
159
|
-
|
|
160
|
-
# Check for /Type /Page (actual page, not /Type/Pages)
|
|
161
|
-
# Must match /Type /Page or /Type/Page but NOT /Type/Pages
|
|
162
|
-
is_page = body.include?("/Type /Page") ||
|
|
163
|
-
(body =~ %r{/Type\s*/Page(?!s)\b})
|
|
164
|
-
next unless is_page
|
|
165
|
-
|
|
166
|
-
page_objects << ref
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# If still no pages found, try to find them via the page tree
|
|
170
|
-
if page_objects.empty?
|
|
171
|
-
# Find the document catalog's /Pages entry
|
|
172
|
-
root_ref = resolver.root_ref
|
|
173
|
-
if root_ref
|
|
174
|
-
catalog_body = resolver.object_body(root_ref)
|
|
175
|
-
if catalog_body && catalog_body =~ %r{/Pages\s+(\d+)\s+(\d+)\s+R}
|
|
176
|
-
pages_ref = [Integer(::Regexp.last_match(1)), Integer(::Regexp.last_match(2))]
|
|
177
|
-
pages_body = resolver.object_body(pages_ref)
|
|
178
|
-
|
|
179
|
-
# Extract /Kids array from Pages object
|
|
180
|
-
if pages_body && pages_body =~ %r{/Kids\s*\[(.*?)\]}m
|
|
181
|
-
kids_array = ::Regexp.last_match(1)
|
|
182
|
-
# Extract all object references from Kids array
|
|
183
|
-
kids_array.scan(/(\d+)\s+(\d+)\s+R/) do |num_str, gen_str|
|
|
184
|
-
kid_ref = [num_str.to_i, gen_str.to_i]
|
|
185
|
-
kid_body = resolver.object_body(kid_ref)
|
|
186
|
-
# Check if this kid is a page (not /Type/Pages)
|
|
187
|
-
if kid_body && (kid_body.include?("/Type /Page") || kid_body =~ %r{/Type\s*/Page(?!s)\b})
|
|
188
|
-
page_objects << kid_ref
|
|
189
|
-
elsif kid_body && kid_body.include?("/Type /Pages")
|
|
190
|
-
# Recursively find pages in this Pages node
|
|
191
|
-
if kid_body =~ %r{/Kids\s*\[(.*?)\]}m
|
|
192
|
-
kid_body[::Regexp.last_match(0)..].scan(/(\d+)\s+(\d+)\s+R/) do |n, g|
|
|
193
|
-
grandkid_ref = [n.to_i, g.to_i]
|
|
194
|
-
grandkid_body = resolver.object_body(grandkid_ref)
|
|
195
|
-
if grandkid_body && (grandkid_body.include?("/Type /Page") || grandkid_body =~ %r{/Type\s*/Page(?!s)\b})
|
|
196
|
-
page_objects << grandkid_ref
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
return page_objects[0] if page_objects.empty?
|
|
208
|
-
return page_objects[page_num - 1] if page_num.positive? && page_num <= page_objects.length
|
|
209
|
-
|
|
210
|
-
page_objects[0]
|
|
156
|
+
# Use Document's unified page-finding method
|
|
157
|
+
find_page_by_number(page_num)
|
|
211
158
|
end
|
|
212
159
|
|
|
213
160
|
def add_widget_to_page(widget_obj_num, page_num)
|
|
@@ -107,11 +107,7 @@ module AcroThat
|
|
|
107
107
|
page_objects = []
|
|
108
108
|
resolver.each_object do |ref, body|
|
|
109
109
|
next unless body
|
|
110
|
-
|
|
111
|
-
is_page = body.include?("/Type /Page") ||
|
|
112
|
-
body.include?("/Type/Page") ||
|
|
113
|
-
(body.include?("/Type") && body.include?("/Page") && body =~ %r{/Type\s*/Page})
|
|
114
|
-
next unless is_page
|
|
110
|
+
next unless DictScan.is_page?(body)
|
|
115
111
|
|
|
116
112
|
page_objects << ref
|
|
117
113
|
end
|
data/lib/acro_that/dict_scan.rb
CHANGED
|
@@ -316,6 +316,13 @@ module AcroThat
|
|
|
316
316
|
body.include?("/Subtype") && body.include?("/Widget") && body =~ %r{/Subtype\s*/Widget}
|
|
317
317
|
end
|
|
318
318
|
|
|
319
|
+
# Check if a body represents a page object (not /Type/Pages)
|
|
320
|
+
def is_page?(body)
|
|
321
|
+
return false unless body
|
|
322
|
+
|
|
323
|
+
body.include?("/Type /Page") || body =~ %r{/Type\s*/Page(?!s)\b}
|
|
324
|
+
end
|
|
325
|
+
|
|
319
326
|
# Check if a field is multiline by checking /Ff flag bit 12 (0x1000)
|
|
320
327
|
def is_multiline_field?(dict_body)
|
|
321
328
|
return false unless dict_body
|
data/lib/acro_that/document.rb
CHANGED
|
@@ -74,35 +74,7 @@ module AcroThat
|
|
|
74
74
|
# Return an array of page information (page number, width, height, ref, metadata)
|
|
75
75
|
def list_pages
|
|
76
76
|
pages = []
|
|
77
|
-
page_objects =
|
|
78
|
-
|
|
79
|
-
# Try to get pages in document order via page tree first
|
|
80
|
-
root_ref = @resolver.root_ref
|
|
81
|
-
if root_ref
|
|
82
|
-
catalog_body = @resolver.object_body(root_ref)
|
|
83
|
-
if catalog_body && catalog_body =~ %r{/Pages\s+(\d+)\s+(\d+)\s+R}
|
|
84
|
-
pages_ref = [Integer(::Regexp.last_match(1)), Integer(::Regexp.last_match(2))]
|
|
85
|
-
|
|
86
|
-
# Recursively collect pages from page tree
|
|
87
|
-
collect_pages_from_tree(pages_ref, page_objects)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Fallback: collect all page objects if page tree didn't work
|
|
92
|
-
if page_objects.empty?
|
|
93
|
-
@resolver.each_object do |ref, body|
|
|
94
|
-
next unless body
|
|
95
|
-
|
|
96
|
-
# Match /Type /Page or /Type/Page but NOT /Type/Pages
|
|
97
|
-
is_page = body.include?("/Type /Page") || body =~ %r{/Type\s*/Page(?!s)\b}
|
|
98
|
-
next unless is_page
|
|
99
|
-
|
|
100
|
-
page_objects << ref unless page_objects.include?(ref)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Sort by object number as fallback
|
|
104
|
-
page_objects.sort_by! { |ref| ref[0] }
|
|
105
|
-
end
|
|
77
|
+
page_objects = find_all_pages
|
|
106
78
|
|
|
107
79
|
# Second pass: extract information from each page
|
|
108
80
|
page_objects.each_with_index do |ref, index|
|
|
@@ -207,13 +179,14 @@ module AcroThat
|
|
|
207
179
|
contents_refs: contents_refs
|
|
208
180
|
}
|
|
209
181
|
|
|
210
|
-
pages <<
|
|
211
|
-
|
|
212
|
-
width
|
|
213
|
-
height
|
|
214
|
-
ref
|
|
215
|
-
metadata
|
|
216
|
-
|
|
182
|
+
pages << Page.new(
|
|
183
|
+
index + 1, # Page number starting at 1
|
|
184
|
+
width,
|
|
185
|
+
height,
|
|
186
|
+
ref,
|
|
187
|
+
metadata,
|
|
188
|
+
self # Pass document reference
|
|
189
|
+
)
|
|
217
190
|
end
|
|
218
191
|
|
|
219
192
|
pages
|
|
@@ -554,8 +527,7 @@ module AcroThat
|
|
|
554
527
|
end
|
|
555
528
|
|
|
556
529
|
body = obj[:body]
|
|
557
|
-
|
|
558
|
-
next unless body&.include?("/Type /Page") || body =~ %r{/Type\s*/Page(?!s)\b}
|
|
530
|
+
next unless DictScan.is_page?(body)
|
|
559
531
|
|
|
560
532
|
# Handle inline /Annots array
|
|
561
533
|
if body =~ %r{/Annots\s*\[(.*?)\]}
|
|
@@ -706,7 +678,7 @@ module AcroThat
|
|
|
706
678
|
kid_body = @resolver.object_body(kid_ref)
|
|
707
679
|
|
|
708
680
|
# Check if this kid is a page (not /Type/Pages)
|
|
709
|
-
if kid_body &&
|
|
681
|
+
if kid_body && DictScan.is_page?(kid_body)
|
|
710
682
|
page_objects << kid_ref unless page_objects.include?(kid_ref)
|
|
711
683
|
elsif kid_body && kid_body.include?("/Type /Pages")
|
|
712
684
|
# Recursively find pages in this Pages node
|
|
@@ -716,14 +688,52 @@ module AcroThat
|
|
|
716
688
|
end
|
|
717
689
|
end
|
|
718
690
|
|
|
719
|
-
|
|
691
|
+
# Find all page objects in document order
|
|
692
|
+
# Returns an array of page references [obj_num, gen_num]
|
|
693
|
+
def find_all_pages
|
|
720
694
|
page_objects = []
|
|
721
|
-
@resolver.each_object do |ref, body|
|
|
722
|
-
next unless body&.include?("/Type /Page")
|
|
723
695
|
|
|
724
|
-
|
|
696
|
+
# First, try to get pages in document order via page tree
|
|
697
|
+
root_ref = @resolver.root_ref
|
|
698
|
+
if root_ref
|
|
699
|
+
catalog_body = @resolver.object_body(root_ref)
|
|
700
|
+
if catalog_body && catalog_body =~ %r{/Pages\s+(\d+)\s+(\d+)\s+R}
|
|
701
|
+
pages_ref = [Integer(::Regexp.last_match(1)), Integer(::Regexp.last_match(2))]
|
|
702
|
+
collect_pages_from_tree(pages_ref, page_objects)
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
# Fallback: collect all page objects if page tree didn't work
|
|
707
|
+
if page_objects.empty?
|
|
708
|
+
@resolver.each_object do |ref, body|
|
|
709
|
+
next unless body
|
|
710
|
+
|
|
711
|
+
next unless DictScan.is_page?(body)
|
|
712
|
+
|
|
713
|
+
page_objects << ref unless page_objects.include?(ref)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# Sort by object number as fallback
|
|
717
|
+
page_objects.sort_by! { |ref| ref[0] }
|
|
725
718
|
end
|
|
726
719
|
|
|
720
|
+
page_objects
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# Find a page by its page number (1-indexed)
|
|
724
|
+
# Returns [obj_num, gen_num] or nil if not found
|
|
725
|
+
def find_page_by_number(page_num)
|
|
726
|
+
page_objects = find_all_pages
|
|
727
|
+
|
|
728
|
+
return nil if page_objects.empty?
|
|
729
|
+
return page_objects[page_num - 1] if page_num.positive? && page_num <= page_objects.length
|
|
730
|
+
|
|
731
|
+
page_objects[0] # Default to first page if page_num is out of range
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
def find_page_number_for_ref(page_ref)
|
|
735
|
+
page_objects = find_all_pages
|
|
736
|
+
|
|
727
737
|
return nil if page_objects.empty?
|
|
728
738
|
|
|
729
739
|
page_index = page_objects.index(page_ref)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AcroThat
|
|
4
|
+
# Represents a page in a PDF document
|
|
5
|
+
class Page
|
|
6
|
+
attr_reader :page, :width, :height, :ref, :metadata, :document
|
|
7
|
+
|
|
8
|
+
def initialize(page, width, height, ref, metadata, document)
|
|
9
|
+
@page = page # Page number (1-indexed)
|
|
10
|
+
@width = width
|
|
11
|
+
@height = height
|
|
12
|
+
@ref = ref # [obj_num, gen_num]
|
|
13
|
+
@metadata = metadata # Hash with :rotate, :media_box, :crop_box, etc.
|
|
14
|
+
@document = document
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Add a field to this page
|
|
18
|
+
# Options are the same as Document#add_field, but :page is automatically set
|
|
19
|
+
def add_field(name, options = {})
|
|
20
|
+
# Automatically set the page number to this page
|
|
21
|
+
options_with_page = options.merge(page: @page)
|
|
22
|
+
@document.add_field(name, options_with_page)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get the page number
|
|
26
|
+
def page_number
|
|
27
|
+
@page
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Get the page reference [obj_num, gen_num]
|
|
31
|
+
def page_ref
|
|
32
|
+
@ref
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check if page has rotation
|
|
36
|
+
def rotated?
|
|
37
|
+
!@metadata[:rotate].nil? && @metadata[:rotate] != 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get rotation angle (0, 90, 180, 270)
|
|
41
|
+
def rotation
|
|
42
|
+
@metadata[:rotate] || 0
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Get MediaBox dimensions
|
|
46
|
+
def media_box
|
|
47
|
+
@metadata[:media_box]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Get CropBox dimensions
|
|
51
|
+
def crop_box
|
|
52
|
+
@metadata[:crop_box]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Get ArtBox dimensions
|
|
56
|
+
def art_box
|
|
57
|
+
@metadata[:art_box]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get BleedBox dimensions
|
|
61
|
+
def bleed_box
|
|
62
|
+
@metadata[:bleed_box]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get TrimBox dimensions
|
|
66
|
+
def trim_box
|
|
67
|
+
@metadata[:trim_box]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# String representation for debugging
|
|
71
|
+
def to_s
|
|
72
|
+
dims = width && height ? " #{width}x#{height}" : ""
|
|
73
|
+
rot = rotated? ? " (rotated #{rotation}°)" : ""
|
|
74
|
+
"#<AcroThat::Page page=#{page}#{dims}#{rot} ref=#{ref.inspect}>"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
alias inspect to_s
|
|
78
|
+
|
|
79
|
+
# Convert to hash for backward compatibility
|
|
80
|
+
def to_h
|
|
81
|
+
{
|
|
82
|
+
page: @page,
|
|
83
|
+
width: @width,
|
|
84
|
+
height: @height,
|
|
85
|
+
ref: @ref,
|
|
86
|
+
metadata: @metadata
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
data/lib/acro_that/version.rb
CHANGED
data/lib/acro_that.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "acro_that/objstm"
|
|
|
12
12
|
require_relative "acro_that/pdf_writer"
|
|
13
13
|
require_relative "acro_that/incremental_writer"
|
|
14
14
|
require_relative "acro_that/field"
|
|
15
|
+
require_relative "acro_that/page"
|
|
15
16
|
require_relative "acro_that/document"
|
|
16
17
|
|
|
17
18
|
# Load actions
|
data/publish
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e # Exit on any error
|
|
4
|
+
|
|
5
|
+
VERSION_FILE="lib/acro_that/version.rb"
|
|
6
|
+
GEMSPEC_FILE="acro_that.gemspec"
|
|
7
|
+
GEM_NAME="acro_that"
|
|
8
|
+
|
|
9
|
+
# Function to show usage
|
|
10
|
+
usage() {
|
|
11
|
+
cat << EOF
|
|
12
|
+
Usage: $0 [OPTIONS]
|
|
13
|
+
|
|
14
|
+
Publish acro_that gem to RubyGems.
|
|
15
|
+
|
|
16
|
+
OPTIONS:
|
|
17
|
+
-b, --bump TYPE Bump version before publishing (major|minor|patch)
|
|
18
|
+
-k, --key KEY RubyGems API key name (optional, uses credentials if not provided)
|
|
19
|
+
-h, --help Show this help message
|
|
20
|
+
|
|
21
|
+
EXAMPLES:
|
|
22
|
+
$0 # Publish current version without bumping
|
|
23
|
+
$0 -b patch # Bump patch version (0.1.2 -> 0.1.3)
|
|
24
|
+
$0 -b minor # Bump minor version (0.1.2 -> 0.2.0)
|
|
25
|
+
$0 -b major # Bump major version (0.1.2 -> 1.0.0)
|
|
26
|
+
$0 -b patch -k mykey # Bump patch and use specific API key
|
|
27
|
+
|
|
28
|
+
EOF
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Function to get current version
|
|
33
|
+
get_current_version() {
|
|
34
|
+
if [[ ! -f "$VERSION_FILE" ]]; then
|
|
35
|
+
echo "Error: $VERSION_FILE not found!" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Extract version using awk (works reliably on both macOS and Linux)
|
|
40
|
+
awk -F'"' '/VERSION =/ {print $2}' "$VERSION_FILE"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Function to bump version
|
|
44
|
+
bump_version() {
|
|
45
|
+
local bump_type=$1
|
|
46
|
+
local current_version=$(get_current_version)
|
|
47
|
+
|
|
48
|
+
IFS='.' read -ra VERSION_PARTS <<< "$current_version"
|
|
49
|
+
local major=${VERSION_PARTS[0]:-0}
|
|
50
|
+
local minor=${VERSION_PARTS[1]:-0}
|
|
51
|
+
local patch=${VERSION_PARTS[2]:-0}
|
|
52
|
+
|
|
53
|
+
case "$bump_type" in
|
|
54
|
+
major)
|
|
55
|
+
major=$((major + 1))
|
|
56
|
+
minor=0
|
|
57
|
+
patch=0
|
|
58
|
+
;;
|
|
59
|
+
minor)
|
|
60
|
+
minor=$((minor + 1))
|
|
61
|
+
patch=0
|
|
62
|
+
;;
|
|
63
|
+
patch)
|
|
64
|
+
patch=$((patch + 1))
|
|
65
|
+
;;
|
|
66
|
+
*)
|
|
67
|
+
echo "Error: Invalid bump type: $bump_type" >&2
|
|
68
|
+
echo "Must be one of: major, minor, patch" >&2
|
|
69
|
+
exit 1
|
|
70
|
+
;;
|
|
71
|
+
esac
|
|
72
|
+
|
|
73
|
+
local new_version="${major}.${minor}.${patch}"
|
|
74
|
+
|
|
75
|
+
# Update version in version.rb
|
|
76
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
77
|
+
# macOS uses BSD sed
|
|
78
|
+
sed -i '' "s/VERSION = \".*\"/VERSION = \"$new_version\"/" "$VERSION_FILE"
|
|
79
|
+
else
|
|
80
|
+
# Linux uses GNU sed
|
|
81
|
+
sed -i "s/VERSION = \".*\"/VERSION = \"$new_version\"/" "$VERSION_FILE"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
echo "$new_version"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Parse arguments
|
|
88
|
+
BUMP_TYPE=""
|
|
89
|
+
API_KEY=""
|
|
90
|
+
|
|
91
|
+
while [[ $# -gt 0 ]]; do
|
|
92
|
+
case $1 in
|
|
93
|
+
-b|--bump)
|
|
94
|
+
BUMP_TYPE="$2"
|
|
95
|
+
shift 2
|
|
96
|
+
;;
|
|
97
|
+
-k|--key)
|
|
98
|
+
API_KEY="$2"
|
|
99
|
+
shift 2
|
|
100
|
+
;;
|
|
101
|
+
-h|--help)
|
|
102
|
+
usage
|
|
103
|
+
;;
|
|
104
|
+
*)
|
|
105
|
+
echo "Error: Unknown option: $1" >&2
|
|
106
|
+
usage
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
done
|
|
110
|
+
|
|
111
|
+
# Validate bump type if provided
|
|
112
|
+
if [[ -n "$BUMP_TYPE" ]]; then
|
|
113
|
+
if [[ ! "$BUMP_TYPE" =~ ^(major|minor|patch)$ ]]; then
|
|
114
|
+
echo "Error: Invalid bump type: $BUMP_TYPE" >&2
|
|
115
|
+
echo "Must be one of: major, minor, patch" >&2
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Get version (after potential bump)
|
|
121
|
+
if [[ -n "$BUMP_TYPE" ]]; then
|
|
122
|
+
echo "Bumping $BUMP_TYPE version..."
|
|
123
|
+
VERSION=$(bump_version "$BUMP_TYPE")
|
|
124
|
+
echo "New version: $VERSION"
|
|
125
|
+
else
|
|
126
|
+
VERSION=$(get_current_version)
|
|
127
|
+
echo "Using current version: $VERSION"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Build the gem
|
|
131
|
+
echo "Building gem..."
|
|
132
|
+
GEM_FILE="${GEM_NAME}-${VERSION}.gem"
|
|
133
|
+
gem build "$GEMSPEC_FILE"
|
|
134
|
+
|
|
135
|
+
if [[ ! -f "$GEM_FILE" ]]; then
|
|
136
|
+
echo "Error: Failed to build gem file: $GEM_FILE" >&2
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
echo "Gem built successfully: $GEM_FILE"
|
|
141
|
+
|
|
142
|
+
# Push to RubyGems
|
|
143
|
+
echo "Pushing to RubyGems..."
|
|
144
|
+
if [[ -n "$API_KEY" ]]; then
|
|
145
|
+
gem push "$GEM_FILE" --key "$API_KEY"
|
|
146
|
+
else
|
|
147
|
+
gem push "$GEM_FILE"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
if [[ $? -ne 0 ]]; then
|
|
151
|
+
echo "Error: Failed to push gem to RubyGems" >&2
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
echo "Gem pushed to RubyGems successfully"
|
|
156
|
+
|
|
157
|
+
# Commit and push to git (only if version was bumped or if there are changes)
|
|
158
|
+
if [[ -n "$BUMP_TYPE" ]] || ! git diff --quiet "$VERSION_FILE"; then
|
|
159
|
+
echo "Committing version change..."
|
|
160
|
+
git add "$VERSION_FILE"
|
|
161
|
+
git commit -m "v${VERSION}"
|
|
162
|
+
|
|
163
|
+
echo "Creating and pushing tag..."
|
|
164
|
+
git tag -a "v${VERSION}" -m "Release version ${VERSION}"
|
|
165
|
+
|
|
166
|
+
echo "Pushing to origin..."
|
|
167
|
+
git push origin main
|
|
168
|
+
git push origin "v${VERSION}"
|
|
169
|
+
|
|
170
|
+
echo "Git operations completed successfully"
|
|
171
|
+
else
|
|
172
|
+
echo "No version changes to commit"
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
echo ""
|
|
176
|
+
echo "✅ Successfully published ${GEM_NAME} v${VERSION}!"
|
|
177
|
+
echo " - Gem built: ${GEM_FILE}"
|
|
178
|
+
echo " - Pushed to RubyGems"
|
|
179
|
+
if [[ -n "$BUMP_TYPE" ]]; then
|
|
180
|
+
echo " - Version bumped and committed"
|
|
181
|
+
echo " - Tagged as v${VERSION}"
|
|
182
|
+
fi
|
|
183
|
+
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acro_that
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Wynkoop
|
|
@@ -116,8 +116,10 @@ files:
|
|
|
116
116
|
- lib/acro_that/incremental_writer.rb
|
|
117
117
|
- lib/acro_that/object_resolver.rb
|
|
118
118
|
- lib/acro_that/objstm.rb
|
|
119
|
+
- lib/acro_that/page.rb
|
|
119
120
|
- lib/acro_that/pdf_writer.rb
|
|
120
121
|
- lib/acro_that/version.rb
|
|
122
|
+
- publish
|
|
121
123
|
homepage: https://github.com/wynk182/acro_that
|
|
122
124
|
licenses:
|
|
123
125
|
- MIT
|