prawn_hebrew 0.1.6 → 0.2.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/prawn_hebrew.rb +158 -11
  3. data/lib/version.rb +1 -1
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c923e10c8587bf590c02c70f3ef62dd6d2e95c6fb5c338c453e41db11fce73a
4
- data.tar.gz: 15fee6431648b088fd6b6e824db4a00f43880eb7a30cc208a0ecbc0b59ffeaf6
3
+ metadata.gz: 223562a63ced0cedfc7d8b64ddae8408b3302a57676fa97ef100bf7266cf7203
4
+ data.tar.gz: ec4ee45cf9a40979dcbc63d37ee914ef34520a80604b62a984b0eabc4556b535
5
5
  SHA512:
6
- metadata.gz: b6ed446d3c436f65630bfb528b79735e6c2d9cc4120b68e70c7c173047868081068a3eb22689d79ac472d2db7306cf3373feb8998b520b613f9fa466f69a27f3
7
- data.tar.gz: a4ae2aaa3b7b7e8990df02a953345010e66aaa41b167ba3dea0e44011d1719081397fcc2fea5a2c5e12e2ae0c04eb2ca94e84d464e4b23fcc4045e87e7673370
6
+ metadata.gz: d99416beb3197fe6ab2955447f9319c41a5d074bc230ec7e56acdb30fcb6701d27cd5c850308c1c24c1e48e1c649af947dba886a68c1db68913aec12bfcbb07e
7
+ data.tar.gz: e4edc4bf10ff2395ae65b2f07269ab5e53c7d42adb9080ba62b0fa7f64567c6e176f3b050a0b429072d0734b6e52c4ca1727a8694c5b5c802c46220022d3060a
data/lib/prawn_hebrew.rb CHANGED
@@ -2,21 +2,78 @@ require 'prawn'
2
2
  require_relative 'version'
3
3
 
4
4
  module PrawnHebrew
5
+ # Simple wrapper class for Hebrew text in table cells
6
+ class HebrewTableCell
7
+ attr_reader :text
8
+
9
+ def initialize(text, hebrew_text: false)
10
+ @text = text
11
+ @hebrew_text = hebrew_text
12
+ end
13
+
14
+ def to_s
15
+ @text.to_s
16
+ end
17
+ end
18
+
5
19
  module Text
6
20
  DEFAULT_HEBREW_FONT = 'GveretLevinHebrew'.freeze
7
21
  DEFAULT_ENGLISH_FONT = 'Helvetica'.freeze
8
22
 
9
23
  # Set to true for debugging which text rendering path is used
10
24
  DEBUG_MODE = false
11
- INVISIBLE_CHARS = /[\u2011\u2010\u2012\u2013\u2014\u2018\u2019\u201C\u201D\u2026\u200B\u200C\u200D\u200E\u200F\uFEFF\u00AD\u202A\u202B\u202C\u202D\u202E]/.freeze
12
- NBSP_CHARS = /[\u00A0\u202F]/.freeze
25
+
26
+ # Characters that should be removed or replaced to prevent Prawn errors
27
+ # Zero-width and invisible characters
28
+ INVISIBLE_CHARS = /[\u200B\u200C\u200D\u200E\u200F\uFEFF\u00AD\u202A\u202B\u202C\u202D\u202E\u2060\u2061\u2062\u2063\u2064\u206A\u206B\u206C\u206D\u206E\u206F]/.freeze
29
+
30
+ # Non-breaking spaces (replace with regular space)
31
+ NBSP_CHARS = /[\u00A0\u202F\u2007\u2008\u2009\u200A\u205F\u3000]/.freeze
32
+
33
+ # Dashes - em dash, en dash, figure dash, horizontal bar, etc. (replace with regular hyphen)
34
+ DASH_CHARS = /[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]/.freeze
35
+
36
+ # Quotation marks (replace with standard quotes)
37
+ SMART_QUOTES_DOUBLE = /[\u201C\u201D\u201E\u201F\u00AB\u00BB\u301D\u301E\u301F]/.freeze
38
+ SMART_QUOTES_SINGLE = /[\u2018\u2019\u201A\u201B\u2039\u203A]/.freeze
39
+
40
+ # Ellipsis (replace with three dots)
41
+ ELLIPSIS_CHAR = /\u2026/.freeze
42
+
43
+ # Arrows and special symbols (replace with text equivalents)
44
+ ARROW_CHAR = /\u2192/.freeze # → (rightward arrow)
45
+ LEFT_ARROW = /\u2190/.freeze # ←
46
+ UP_ARROW = /\u2191/.freeze # ↑
47
+ DOWN_ARROW = /\u2193/.freeze # ↓
48
+
49
+ # Bullet points and list markers
50
+ BULLET_CHARS = /[\u2022\u2023\u2043\u204C\u204D\u2219\u25E6\u25AA\u25AB\u25CF\u25CB]/.freeze
51
+
52
+ # Other problematic characters
53
+ MISC_PROBLEM_CHARS = /[\u2028\u2029\uFFFC\uFFFD\uFFFF]/.freeze # line/paragraph separators, object replacement, replacement char
54
+
55
+ # Punctuation that should stay at the end of Hebrew text (rendered after in RTL)
56
+ TRAILING_PUNCTUATION = /([.,:;!?\-\u05BE\u05C3]+)$/.freeze # includes Hebrew punctuation
57
+ LEADING_PUNCTUATION = /^([.,:;!?\-\u05BE\u05C3()\[\]{}]+)/.freeze
13
58
 
14
59
 
15
60
 
16
61
 
17
62
  def sanitize_text(text)
18
63
  return text if text.nil?
19
- text.to_s.gsub(INVISIBLE_CHARS, ' ').gsub(NBSP_CHARS, ' ')
64
+ text.to_s
65
+ .gsub(INVISIBLE_CHARS, '') # Remove invisible characters completely
66
+ .gsub(NBSP_CHARS, ' ') # Replace non-breaking spaces with regular space
67
+ .gsub(DASH_CHARS, '-') # Replace all dash types with regular hyphen
68
+ .gsub(SMART_QUOTES_DOUBLE, '"') # Replace smart double quotes
69
+ .gsub(SMART_QUOTES_SINGLE, "'") # Replace smart single quotes
70
+ .gsub(ELLIPSIS_CHAR, '...') # Replace ellipsis with three dots
71
+ .gsub(ARROW_CHAR, '->') # Replace right arrow
72
+ .gsub(LEFT_ARROW, '<-') # Replace left arrow
73
+ .gsub(UP_ARROW, '^') # Replace up arrow
74
+ .gsub(DOWN_ARROW, 'v') # Replace down arrow
75
+ .gsub(BULLET_CHARS, '*') # Replace bullets with asterisk
76
+ .gsub(MISC_PROBLEM_CHARS, '') # Remove other problematic chars
20
77
  end
21
78
 
22
79
  def hebrew_formatted_text(text, size: 12, style: :normal, hebrew_font: DEFAULT_HEBREW_FONT, english_font: DEFAULT_ENGLISH_FONT)
@@ -42,10 +99,8 @@ module PrawnHebrew
42
99
  hebrew_run << word
43
100
  else
44
101
  unless hebrew_run.empty?
45
- hebrew_run.reverse.each_with_index do |hw, idx|
46
- all_fragments << { text: hw, font: hebrew_font, size: size, direction: :rtl, styles: styles }
47
- all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
48
- end
102
+ # Process Hebrew run and handle trailing punctuation
103
+ process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
49
104
  all_fragments << { text: ' ' }
50
105
  hebrew_run.clear
51
106
  end
@@ -54,10 +109,8 @@ module PrawnHebrew
54
109
  end
55
110
 
56
111
  unless hebrew_run.empty?
57
- hebrew_run.reverse.each_with_index do |hw, idx|
58
- all_fragments << { text: hw, font: hebrew_font, size: size, direction: :rtl, styles: styles }
59
- all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
60
- end
112
+ # Process remaining Hebrew run
113
+ process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
61
114
  end
62
115
 
63
116
  # Add newline between lines (except after the last line)
@@ -68,12 +121,84 @@ module PrawnHebrew
68
121
 
69
122
  all_fragments
70
123
  end
124
+
125
+ # Process a run of Hebrew words, handling punctuation correctly
126
+ def process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
127
+ # Check if the last word in the run has trailing punctuation
128
+ last_word = hebrew_run.last
129
+ trailing_punct = nil
130
+
131
+ if last_word =~ TRAILING_PUNCTUATION
132
+ trailing_punct = $1
133
+ # Remove trailing punctuation from the last word
134
+ hebrew_run[-1] = last_word.sub(TRAILING_PUNCTUATION, '')
135
+ end
136
+
137
+ # Check if the first word has leading punctuation (for RTL, this appears at the end)
138
+ first_word = hebrew_run.first
139
+ leading_punct = nil
140
+
141
+ if first_word =~ LEADING_PUNCTUATION
142
+ leading_punct = $1
143
+ hebrew_run[0] = first_word.sub(LEADING_PUNCTUATION, '')
144
+ end
145
+
146
+ # Add leading punctuation first (it will appear at the visual end due to RTL)
147
+ if leading_punct
148
+ all_fragments << { text: leading_punct, font: english_font, size: size, styles: styles }
149
+ end
150
+
151
+ # Reverse Hebrew words for RTL display
152
+ hebrew_run.reverse.each_with_index do |hw, idx|
153
+ next if hw.empty?
154
+ all_fragments << { text: hw, font: hebrew_font, size: size, direction: :rtl, styles: styles }
155
+ all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
156
+ end
157
+
158
+ # Add trailing punctuation at the end (it will appear at the visual end of Hebrew text)
159
+ if trailing_punct
160
+ all_fragments << { text: trailing_punct, font: english_font, size: size, styles: styles }
161
+ end
162
+ end
163
+
164
+ def hebrew_table(data, size: 12, style: :normal,
165
+ hebrew_font: DEFAULT_HEBREW_FONT,
166
+ english_font: DEFAULT_ENGLISH_FONT,
167
+ **table_opts)
168
+ # Process each row: sanitize and render Hebrew cells using formatted text
169
+ processed_data = data.map do |row|
170
+ row.map do |cell_content|
171
+ sanitize_text(cell_content.to_s)
172
+ end
173
+ end
174
+
175
+ # Create table with a block to apply Hebrew formatting to cells
176
+ table(processed_data, table_opts) do |table|
177
+ # Apply Hebrew formatting to cells that contain Hebrew text
178
+ table.cells.each do |cell|
179
+ cell_text = cell.content
180
+ if cell_text =~ /\p{Hebrew}/
181
+ # Use text_color and font to support Hebrew
182
+ cell.font = hebrew_font
183
+ cell.size = size
184
+ cell.text_color = table_opts[:text_color] || "000000"
185
+ else
186
+ # English cells
187
+ cell.font = english_font
188
+ cell.size = size
189
+ end
190
+ end
191
+ end
192
+ end
71
193
 
72
194
  def hebrew_text_box(text, size: 12, style: :normal,
73
195
  hebrew_font: DEFAULT_HEBREW_FONT,
74
196
  english_font: DEFAULT_ENGLISH_FONT,
75
197
  direction: :auto, **box_opts)
76
198
 
199
+ # Sanitize text first to remove problematic characters
200
+ text = sanitize_text(text)
201
+
77
202
  # Handle font specification in box_opts or use defaults
78
203
  final_hebrew_font = box_opts.delete(:hebrew_font) || hebrew_font
79
204
  final_english_font = box_opts.delete(:english_font) || english_font
@@ -223,6 +348,28 @@ module PrawnHebrew
223
348
  end
224
349
  end
225
350
  end
351
+
352
+ # Helper method to create table cells with Hebrew support
353
+ def hebrew_table_cell(text, size: 12, style: :normal,
354
+ hebrew_font: DEFAULT_HEBREW_FONT,
355
+ english_font: DEFAULT_ENGLISH_FONT,
356
+ **cell_opts)
357
+ # Create a hash that can be used as table cell content
358
+ # with Hebrew text handling
359
+ if text.to_s =~ /\p{Hebrew}/
360
+ {
361
+ content: text,
362
+ hebrew_text: true,
363
+ size: size,
364
+ style: style,
365
+ hebrew_font: hebrew_font,
366
+ english_font: english_font,
367
+ cell_opts: cell_opts
368
+ }
369
+ else
370
+ { content: text }
371
+ end
372
+ end
226
373
  end
227
374
  end
228
375
 
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PrawnHebrew
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn_hebrew
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Lite