carve-hexapdf 0.1.4 → 0.1.5

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: 9ca1e064f1b2cfe5886e3c9ead5c523e39d8017f560fa045c01e18af746ebdcc
4
- data.tar.gz: 7a5055cb52def857760862d08a68aa112623a698760169e85a23358f6f04d548
3
+ metadata.gz: 52d77d202d7f1390346e49475aa665563e045e3bcf0c411bfb10a0d99c800070
4
+ data.tar.gz: 74687ef32c19f1969dff555ace0311b406c65aecb2b7ea0fa6c5eeced9977b3c
5
5
  SHA512:
6
- metadata.gz: 3f24bf3e136eb703f0a3561b8f929f6ede44f372b2722fdf19560669420df44ada47ead8f14e3b2f3d858681c4ab0a5488c4723e44c9598e620c9920ab63bd68
7
- data.tar.gz: 5db634aa0f278239009b35018bc524a27295f1494c92be78f577f955d1af139086e06190207bc68f7fe4906650c52d3853fa5444f0a56b44308ec1fa07fd9e49
6
+ metadata.gz: 718e37565452624372860471353c73c80b26566e603d62b60912d2dba8ec5b99555c2671c7663ddc42dac18b88c620b091490908eb756f2c1277bf1a7f0ea731
7
+ data.tar.gz: 11b5129dd95d3f1ffd4260a136f6c842a381d4286fcaedac400ff53ca25b49b084e3d6f58c725b8a56d74dc29343149307c42ae586308b91701b546250302ef0
data/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.5] - 2026-10-24
11
+
12
+ Ruby interchange text now appears in rendered PDFs, and tables with span markers render without a PDF layout error.
13
+
14
+ ### Fixes
15
+
16
+ - Ruby base text and annotations render together instead of losing the annotation (#58).
17
+ - Tables with ownerless span markers or a header rowspan crossing into body rows render without a PDF layout error (#60).
18
+
19
+ **Full Changelog**: https://github.com/markup-carve/carve-hexapdf/compare/v0.1.4...v0.1.5
20
+
21
+
10
22
  ## [0.1.4] - 2026-10-23
11
23
 
12
24
  ### Fixed
data/README.md CHANGED
@@ -54,6 +54,9 @@ ast = Carve.parse("# From AST")
54
54
  pdf_bytes = Carve::Hexapdf.render_ast(ast)
55
55
  ```
56
56
 
57
+ For interchange `ruby` nodes, PDF text shows each pair as
58
+ `base(annotation)`, including `()` when the annotation is empty.
59
+
57
60
  ### Includes
58
61
 
59
62
  A Carve document can pull another file in with `{{ path }}`. A String has no
@@ -429,7 +429,9 @@ module Carve
429
429
  resolved = resolve_spans(Array(node[:rows]))
430
430
  return if resolved.empty?
431
431
 
432
- header_count = resolved.first.any? { |o| o[:header] } ? 1 : 0
432
+ # HexaPDF cannot repeat a header whose cell spans into the body.
433
+ header_count = resolved.first.any? { |o| o[:header] } &&
434
+ resolved.first.none? { |o| o[:row_span] > 1 } ? 1 : 0
433
435
  table_style = style_for("table")
434
436
  header_style = style_for("table.header")
435
437
 
@@ -478,8 +480,17 @@ module Carve
478
480
  case cell[:span]
479
481
  when "colspan"
480
482
  owner = last || col_owner[col - 1]
481
- owner[:col_span] += 1 if owner
482
- col_owner[col] = owner if owner
483
+ if owner
484
+ owner[:col_span] += 1
485
+ col_owner[col] = owner
486
+ else
487
+ # A leading marker has no cell to extend. Keep its grid slot
488
+ # so the table has a drawable cell in this row.
489
+ o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
490
+ emitted << o
491
+ last = o
492
+ col_owner[col] = o
493
+ end
483
494
  when "rowspan"
484
495
  owner = col_owner[col]
485
496
  # A multi-column cell has one `^` per covered column on the next
@@ -488,8 +499,12 @@ module Carve
488
499
  owner[:row_span] += 1
489
500
  bumped[owner.object_id] = true
490
501
  end
491
- # col_owner[col] stays pointing at the same originator so a
492
- # further `^` in the next row chains onto it.
502
+ if owner.nil?
503
+ o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
504
+ emitted << o
505
+ col_owner[col] = o
506
+ end
507
+ # A valid owner's slot remains available for further `^` rows.
493
508
  else
494
509
  o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
495
510
  emitted << o
@@ -594,6 +609,13 @@ module Carve
594
609
  when "substitution"
595
610
  emit_half(node[:old], node[:oldText], ctx.merge(strike: true), out)
596
611
  emit_half(node[:new], node[:newText], ctx.merge(underline: true), out)
612
+ when "ruby"
613
+ Array(node[:pairs]).each do |pair|
614
+ Array(pair[:base]).each { |part| emit_inline(part, ctx, out) }
615
+ out << run("(", ctx)
616
+ Array(pair[:annotation]).each { |part| emit_inline(part, ctx, out) }
617
+ out << run(")", ctx)
618
+ end
597
619
  when "smart_punctuation" then out << run(smart_punctuation_text(node), ctx)
598
620
  # A character the author escaped. The backslash is authoring syntax, so
599
621
  # the page shows the character - but the node has no children, so
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Carve
4
4
  module Hexapdf
5
- VERSION = "0.1.4"
5
+ VERSION = "0.1.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carve-hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - markup-carve
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-23 00:00:00.000000000 Z
11
+ date: 2026-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: carve-lang