|
5 | 5 | RSpec.describe Prawn::Text::ArabicShaping do |
6 | 6 | describe '.contains_arabic?' do |
7 | 7 | it 'returns true for Arabic text' do |
8 | | - expect(described_class.contains_arabic?('مرحبا')).to be true |
| 8 | + expect(described_class.contains_arabic?('مرحبا')).to be(true) |
9 | 9 | end |
10 | 10 |
|
11 | 11 | it 'returns false for Latin text' do |
12 | | - expect(described_class.contains_arabic?('Hello')).to be false |
| 12 | + expect(described_class.contains_arabic?('Hello')).to be(false) |
13 | 13 | end |
14 | 14 |
|
15 | 15 | it 'returns true for mixed Arabic/Latin text' do |
16 | | - expect(described_class.contains_arabic?('Hello مرحبا')).to be true |
| 16 | + expect(described_class.contains_arabic?('Hello مرحبا')).to be(true) |
17 | 17 | end |
18 | 18 |
|
19 | 19 | it 'returns false for empty string' do |
20 | | - expect(described_class.contains_arabic?('')).to be false |
| 20 | + expect(described_class.contains_arabic?('')).to be(false) |
21 | 21 | end |
22 | 22 | end |
23 | 23 |
|
24 | 24 | describe '.shape' do |
25 | | - it 'returns nil/empty unchanged' do |
| 25 | + it 'returns nil unchanged' do |
26 | 26 | expect(described_class.shape(nil)).to be_nil |
| 27 | + end |
| 28 | + |
| 29 | + it 'returns empty string unchanged' do |
27 | 30 | expect(described_class.shape('')).to eq('') |
28 | 31 | end |
29 | 32 |
|
|
33 | 36 |
|
34 | 37 | it 'converts Arabic characters to presentation forms' do |
35 | 38 | shaped = described_class.shape('مرحبا') |
36 | | - # All characters should be in the Arabic Presentation Forms range |
37 | | - shaped.codepoints.each do |cp| |
38 | | - expect(cp).to be_between(0xFE70, 0xFEFF) |
39 | | - .or be_between(0xFB50, 0xFDFF) |
40 | | - end |
| 39 | + expect(shaped.codepoints).to all( |
| 40 | + be_between(0xFE70, 0xFEFF).or(be_between(0xFB50, 0xFDFF)), |
| 41 | + ) |
41 | 42 | end |
42 | 43 |
|
43 | 44 | it 'shapes initial form correctly' do |
44 | | - # م at the start of مرحبا should be initial form (FEE3) |
45 | 45 | shaped = described_class.shape('مرحبا') |
46 | | - expect(shaped.codepoints.first).to eq(0xFEE3) # MEEM INITIAL |
| 46 | + expect(shaped.codepoints.first).to eq(0xFEE3) |
47 | 47 | end |
48 | 48 |
|
49 | 49 | it 'shapes final form correctly' do |
50 | | - # ا at the end of مرحبا should be final form (FE8E) |
51 | 50 | shaped = described_class.shape('مرحبا') |
52 | | - expect(shaped.codepoints.last).to eq(0xFE8E) # ALEF FINAL (via ALEF MAKSURA) |
| 51 | + expect(shaped.codepoints.last).to eq(0xFE8E) |
53 | 52 | end |
54 | 53 |
|
55 | 54 | it 'shapes medial form correctly' do |
56 | | - # ح in مرحبا should be medial form (FEA4) |
57 | 55 | shaped = described_class.shape('مرحبا') |
58 | | - expect(shaped.codepoints[2]).to eq(0xFEA3) # HAH MEDIAL |
| 56 | + expect(shaped.codepoints[2]).to eq(0xFEA3) |
59 | 57 | end |
60 | 58 |
|
61 | 59 | it 'shapes isolated characters correctly' do |
62 | | - shaped = described_class.shape('ء') # HAMZA - always isolated |
| 60 | + shaped = described_class.shape('ء') |
63 | 61 | expect(shaped.codepoints.first).to eq(0xFE80) |
64 | 62 | end |
65 | 63 |
|
66 | | - it 'handles right-joining characters (Alef, Dal, etc.)' do |
67 | | - # Alef only joins to the right |
68 | | - shaped = described_class.shape('با') # BEH + ALEF |
| 64 | + it 'handles right-joining characters' do |
| 65 | + shaped = described_class.shape('با') |
69 | 66 | cps = shaped.codepoints |
70 | | - expect(cps[0]).to eq(0xFE91) # BEH INITIAL |
71 | | - expect(cps[1]).to eq(0xFE8E) # ALEF FINAL |
| 67 | + expect(cps[0]).to eq(0xFE91) |
| 68 | + expect(cps[1]).to eq(0xFE8E) |
72 | 69 | end |
73 | 70 |
|
74 | 71 | it 'creates Lam-Alef ligatures' do |
75 | 72 | shaped = described_class.shape('لا') |
76 | | - expect(shaped.codepoints).to eq([0xFEFB]) # LAM-ALEF ISOLATED |
| 73 | + expect(shaped.codepoints).to eq([0xFEFB]) |
77 | 74 | end |
78 | 75 |
|
79 | 76 | it 'creates Lam-Alef ligature in final form when preceded' do |
80 | | - shaped = described_class.shape('بلا') # BEH + LAM + ALEF |
| 77 | + shaped = described_class.shape('بلا') |
81 | 78 | cps = shaped.codepoints |
82 | | - expect(cps[0]).to eq(0xFE91) # BEH INITIAL |
83 | | - expect(cps[1]).to eq(0xFEFC) # LAM-ALEF FINAL |
| 79 | + expect(cps[0]).to eq(0xFE91) |
| 80 | + expect(cps[1]).to eq(0xFEFC) |
84 | 81 | end |
85 | 82 |
|
86 | 83 | it 'creates Lam-Alef with Madda ligature' do |
87 | | - shaped = described_class.shape("ل\u0622") # LAM + ALEF WITH MADDA |
| 84 | + shaped = described_class.shape("\u0644\u0622") |
88 | 85 | expect(shaped.codepoints).to eq([0xFEF5]) |
89 | 86 | end |
90 | 87 |
|
91 | 88 | it 'preserves diacritical marks' do |
92 | | - text = "بِسْمِ" # with kasra and sukun |
93 | | - shaped = described_class.shape(text) |
94 | | - # Marks should still be present |
95 | | - marks = shaped.codepoints.select { |cp| (0x064B..0x065F).cover?(cp) } |
96 | | - expect(marks).not_to be_empty |
| 89 | + shaped = described_class.shape("\u0628\u0650\u0633\u0652\u0645\u0650") |
| 90 | + marks = shaped.codepoints.select { |codepoint| (0x064B..0x065F).cover?(codepoint) } |
| 91 | + expect(marks).to_not be_empty |
97 | 92 | end |
98 | 93 |
|
99 | 94 | it 'preserves spaces between words' do |
|
105 | 100 | shaped = described_class.shape('Hello مرحبا World') |
106 | 101 | expect(shaped).to include('Hello') |
107 | 102 | expect(shaped).to include('World') |
108 | | - # Arabic part should be shaped |
109 | | - expect(shaped).not_to include('م') # original meem should be replaced |
| 103 | + expect(shaped).to_not include('م') |
110 | 104 | end |
111 | 105 |
|
112 | | - it 'handles Tatweel (kashida)' do |
113 | | - shaped = described_class.shape("بـا") # BEH + TATWEEL + ALEF |
114 | | - cps = shaped.codepoints |
115 | | - expect(cps).to include(0x0640) # TATWEEL preserved |
| 106 | + it 'handles Tatweel' do |
| 107 | + shaped = described_class.shape("\u0628\u0640\u0627") |
| 108 | + expect(shaped.codepoints).to include(0x0640) |
116 | 109 | end |
117 | 110 |
|
118 | 111 | it 'shapes Farsi Yeh correctly' do |
119 | | - shaped = described_class.shape("\u06CC") # FARSI YEH isolated |
120 | | - expect(shaped.codepoints.first).to eq(0xFBFC) # FARSI YEH ISOLATED |
| 112 | + shaped = described_class.shape("\u06CC") |
| 113 | + expect(shaped.codepoints.first).to eq(0xFBFC) |
121 | 114 | end |
122 | 115 |
|
123 | | - it 'shapes Peh correctly (Urdu/Farsi)' do |
124 | | - shaped = described_class.shape("\u067E") # PEH isolated |
125 | | - expect(shaped.codepoints.first).to eq(0xFB56) # PEH ISOLATED |
| 116 | + it 'shapes Peh correctly' do |
| 117 | + shaped = described_class.shape("\u067E") |
| 118 | + expect(shaped.codepoints.first).to eq(0xFB56) |
126 | 119 | end |
127 | 120 |
|
128 | | - it 'shapes Gaf correctly (Farsi)' do |
129 | | - shaped = described_class.shape("\u06AF") # GAF isolated |
130 | | - expect(shaped.codepoints.first).to eq(0xFB92) # GAF ISOLATED |
| 121 | + it 'shapes Gaf correctly' do |
| 122 | + shaped = described_class.shape("\u06AF") |
| 123 | + expect(shaped.codepoints.first).to eq(0xFB92) |
131 | 124 | end |
132 | 125 | end |
133 | 126 | end |
0 commit comments