rbpdf 1.18.3 → 1.18.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +9 -0
- data/lib/rbpdf.rb +170 -127
- data/lib/rbpdf/version.rb +1 -1
- data/test/rbpdf_bidi_test.rb +237 -1
- data/test/rbpdf_content_test.rb +79 -0
- data/test/rbpdf_dom_test.rb +86 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5329616012db52c1743a298afb11aa835126a284
|
4
|
+
data.tar.gz: 6d92283c3fa55edaa59b68edab0b2db7f1311ae5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74738ca0557dbe52a46177277d58b92ce1dc4e590fea0cfb6c4711e94f657db4359fe455aab918aeb67d55353fd4044d6bea4de05eaa7c1189b22e7daa05d918
|
7
|
+
data.tar.gz: f29d02d42ac883a7781314deed127c67216fc780b9df7d742cefeb8b839fc7e896fc2638a9459f6eb1010eb3a4b5e478450d523e6a55a9b55f045914efda2000
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
1.18.4 2014-12-21
|
2
|
+
- utf8Bidi() Persion 0x200C(8204) and endedletter bug fixed.
|
3
|
+
- utf8Bidi() Bidirectional Algorithm X9/I1 rule BN(ZERO WIDTH NON-JOINER) bug fixed.
|
4
|
+
- utf8Bidi() Bidirectional Algorithm N1/N2 rule B/S/WS/ON bug fixed.
|
5
|
+
- utf8Bidi() Bidirectional Algorithm W2/W7 rule bug fixed.
|
6
|
+
- utf8Bidi() Bidirectional Algorithm N1/N2 rule multiple NIs bug fixed.
|
7
|
+
- RTL direction problem fixed. isRTLTextDir direction bug fixed.
|
8
|
+
- utf8Bidi() speed was improved.
|
9
|
+
|
1
10
|
1.18.3 2014-12-06
|
2
11
|
- fixed img and hr self html tag DOM problem.
|
3
12
|
- fixed HTML table problem in writeHTMLCell function.
|
data/lib/rbpdf.rb
CHANGED
@@ -989,15 +989,33 @@ class RBPDF
|
|
989
989
|
|
990
990
|
#
|
991
991
|
# Return the current temporary RTL status
|
992
|
-
# [@return boolean]
|
992
|
+
# [@return boolean] true: RTL, false: LTR
|
993
993
|
# [@access public]
|
994
994
|
# [@since 4.8.014 (2009-11-04)]
|
995
995
|
#
|
996
996
|
def isRTLTextDir()
|
997
|
-
|
997
|
+
if @tmprtl != false
|
998
|
+
return @tmprtl == 'R'
|
999
|
+
else
|
1000
|
+
return @rtl
|
1001
|
+
end
|
998
1002
|
end
|
999
1003
|
alias_method :is_rtl_text_dir, :isRTLTextDir
|
1000
1004
|
|
1005
|
+
#
|
1006
|
+
# Return the current text RTL status
|
1007
|
+
# [@return direction] 'R' : RTL, 'L' LTR
|
1008
|
+
# [@access protected]
|
1009
|
+
#
|
1010
|
+
def rtl_text_dir()
|
1011
|
+
if @tmprtl != false
|
1012
|
+
return @tmprtl # 'R' or 'L'
|
1013
|
+
else
|
1014
|
+
return @rtl ? 'R' : 'L'
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
protected :rtl_text_dir
|
1018
|
+
|
1001
1019
|
#
|
1002
1020
|
# Set the last cell height.
|
1003
1021
|
# [@param float :h] cell height.
|
@@ -2432,7 +2450,7 @@ class RBPDF
|
|
2432
2450
|
# [@since 1.2]
|
2433
2451
|
#
|
2434
2452
|
def GetStringWidth(s, fontname='', fontstyle='', fontsize=0, getarray=false)
|
2435
|
-
return GetArrStringWidth(utf8Bidi(UTF8StringToArray(s), s,
|
2453
|
+
return GetArrStringWidth(utf8Bidi(UTF8StringToArray(s), s, rtl_text_dir), fontname, fontstyle, fontsize, getarray)
|
2436
2454
|
end
|
2437
2455
|
alias_method :get_string_width, :GetStringWidth
|
2438
2456
|
|
@@ -3509,7 +3527,7 @@ class RBPDF
|
|
3509
3527
|
txt2 = UTF8ToLatin1(txt2)
|
3510
3528
|
else
|
3511
3529
|
unicode = UTF8StringToArray(txt) # array of UTF-8 unicode values
|
3512
|
-
unicode = utf8Bidi(unicode, '',
|
3530
|
+
unicode = utf8Bidi(unicode, '', rtl_text_dir)
|
3513
3531
|
if @@k_thai_topchars and @@k_thai_topchars == true
|
3514
3532
|
# ---- Fix for bug #2977340 "Incorrect Thai characters position arrangement" ----
|
3515
3533
|
# NOTE: this doesn't work with HTML justification
|
@@ -4078,7 +4096,7 @@ class RBPDF
|
|
4078
4096
|
lines = 1
|
4079
4097
|
sum = 0
|
4080
4098
|
chars = UTF8StringToArray(txt)
|
4081
|
-
chars = utf8Bidi(chars, txt,
|
4099
|
+
chars = utf8Bidi(chars, txt, rtl_text_dir)
|
4082
4100
|
charsWidth = GetArrStringWidth(chars, '', '', 0, true)
|
4083
4101
|
if @rtl
|
4084
4102
|
charsWidth.reverse!
|
@@ -4228,7 +4246,7 @@ class RBPDF
|
|
4228
4246
|
end
|
4229
4247
|
|
4230
4248
|
# check if string contains RTL text
|
4231
|
-
if arabic or
|
4249
|
+
if arabic or isRTLTextDir or (txt =~ @@k_re_pattern_rtl)
|
4232
4250
|
rtlmode = true
|
4233
4251
|
else
|
4234
4252
|
rtlmode = false
|
@@ -4303,7 +4321,7 @@ class RBPDF
|
|
4303
4321
|
startx = @x
|
4304
4322
|
tmparr = chars[j, i - j]
|
4305
4323
|
if rtlmode
|
4306
|
-
tmparr = utf8Bidi(tmparr, tmpstr,
|
4324
|
+
tmparr = utf8Bidi(tmparr, tmpstr, rtl_text_dir)
|
4307
4325
|
end
|
4308
4326
|
linew = GetArrStringWidth(tmparr)
|
4309
4327
|
tmparr = ''
|
@@ -4362,7 +4380,7 @@ class RBPDF
|
|
4362
4380
|
if ((@current_font['type'] == 'TrueTypeUnicode') or (@current_font['type'] == 'cidfont0')) and arabic
|
4363
4381
|
# with bidirectional algorithm some chars may be changed affecting the line length
|
4364
4382
|
# *** very slow ***
|
4365
|
-
l = GetArrStringWidth(utf8Bidi(chars[j,i-j], '',
|
4383
|
+
l = GetArrStringWidth(utf8Bidi(chars[j,i-j], '', rtl_text_dir))
|
4366
4384
|
else
|
4367
4385
|
l += GetCharWidth(c)
|
4368
4386
|
end
|
@@ -4385,7 +4403,7 @@ class RBPDF
|
|
4385
4403
|
startx = @x
|
4386
4404
|
tmparr = chars[j, i - j]
|
4387
4405
|
if rtlmode
|
4388
|
-
tmparr = utf8Bidi(tmparr, tmpstr,
|
4406
|
+
tmparr = utf8Bidi(tmparr, tmpstr, rtl_text_dir)
|
4389
4407
|
end
|
4390
4408
|
linew = GetArrStringWidth(tmparr)
|
4391
4409
|
tmparr = ''
|
@@ -4439,7 +4457,7 @@ class RBPDF
|
|
4439
4457
|
startx = @x
|
4440
4458
|
tmparr = chars[j, sep + endspace - j]
|
4441
4459
|
if rtlmode
|
4442
|
-
tmparr = utf8Bidi(tmparr, tmpstr,
|
4460
|
+
tmparr = utf8Bidi(tmparr, tmpstr, rtl_text_dir)
|
4443
4461
|
end
|
4444
4462
|
linew = GetArrStringWidth(tmparr)
|
4445
4463
|
tmparr = ''
|
@@ -4514,7 +4532,7 @@ class RBPDF
|
|
4514
4532
|
startx = @x
|
4515
4533
|
tmparr = chars[j, nb - j]
|
4516
4534
|
if rtlmode
|
4517
|
-
tmparr = utf8Bidi(tmparr, tmpstr,
|
4535
|
+
tmparr = utf8Bidi(tmparr, tmpstr, rtl_text_dir)
|
4518
4536
|
end
|
4519
4537
|
linew = GetArrStringWidth(tmparr)
|
4520
4538
|
tmparr = ''
|
@@ -5592,8 +5610,8 @@ protected
|
|
5592
5610
|
if @is_unicode
|
5593
5611
|
alias_b = escape(UTF8ToLatin1(@alias_nb_pages))
|
5594
5612
|
alias_bu = escape(UTF8ToLatin1('{' + @alias_nb_pages + '}'))
|
5595
|
-
alias_c = escape(utf8StrRev(@alias_nb_pages, false,
|
5596
|
-
alias_cu = escape(utf8StrRev('{' + @alias_nb_pages + '}', false,
|
5613
|
+
alias_c = escape(utf8StrRev(@alias_nb_pages, false, rtl_text_dir))
|
5614
|
+
alias_cu = escape(utf8StrRev('{' + @alias_nb_pages + '}', false, rtl_text_dir))
|
5597
5615
|
end
|
5598
5616
|
end
|
5599
5617
|
if @alias_num_page
|
@@ -5602,8 +5620,8 @@ protected
|
|
5602
5620
|
if @is_unicode
|
5603
5621
|
alias_pb = escape(UTF8ToLatin1(@alias_num_page))
|
5604
5622
|
alias_pbu = escape(UTF8ToLatin1('{' + @alias_num_page + '}'))
|
5605
|
-
alias_pc = escape(utf8StrRev(@alias_num_page, false,
|
5606
|
-
alias_pcu = escape(utf8StrRev('{' + @alias_num_page + '}', false,
|
5623
|
+
alias_pc = escape(utf8StrRev(@alias_num_page, false, rtl_text_dir))
|
5624
|
+
alias_pcu = escape(utf8StrRev('{' + @alias_num_page + '}', false, rtl_text_dir))
|
5607
5625
|
end
|
5608
5626
|
end
|
5609
5627
|
pagegroupnum = 0
|
@@ -5624,8 +5642,8 @@ protected
|
|
5624
5642
|
if @is_unicode
|
5625
5643
|
alias_gb = escape(UTF8ToLatin1(k))
|
5626
5644
|
alias_gbu = escape(UTF8ToLatin1('{' + k + '}'))
|
5627
|
-
alias_gc = escape(utf8StrRev(k.dup, false,
|
5628
|
-
alias_gcu = escape(utf8StrRev('{' + k + '}', false,
|
5645
|
+
alias_gc = escape(utf8StrRev(k.dup, false, rtl_text_dir))
|
5646
|
+
alias_gcu = escape(utf8StrRev('{' + k + '}', false, rtl_text_dir))
|
5629
5647
|
end
|
5630
5648
|
temppage = temppage.gsub(alias_gau, vu)
|
5631
5649
|
if @is_unicode
|
@@ -5644,8 +5662,8 @@ protected
|
|
5644
5662
|
if @is_unicode
|
5645
5663
|
alias_pgb = escape(UTF8ToLatin1(pk))
|
5646
5664
|
alias_pgbu = escape(UTF8ToLatin1('{' + pk + '}'))
|
5647
|
-
alias_pgc = escape(utf8StrRev(pk, false,
|
5648
|
-
alias_pgcu = escape(utf8StrRev('{' + pk + '}', false,
|
5665
|
+
alias_pgc = escape(utf8StrRev(pk, false, rtl_text_dir))
|
5666
|
+
alias_pgcu = escape(utf8StrRev('{' + pk + '}', false, rtl_text_dir))
|
5649
5667
|
end
|
5650
5668
|
temppage = temppage.gsub(alias_pgau, pvu)
|
5651
5669
|
if @is_unicode
|
@@ -7497,7 +7515,7 @@ protected
|
|
7497
7515
|
s = UTF8ToLatin1(s)
|
7498
7516
|
else
|
7499
7517
|
# Convert string to UTF-16BE and reverse RTL language
|
7500
|
-
s = utf8StrRev(s, false,
|
7518
|
+
s = utf8StrRev(s, false, rtl_text_dir)
|
7501
7519
|
end
|
7502
7520
|
end
|
7503
7521
|
return escape(s);
|
@@ -9048,7 +9066,7 @@ public
|
|
9048
9066
|
else
|
9049
9067
|
# P2. In each paragraph, find the first character of type L, AL, or R.
|
9050
9068
|
# P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero.
|
9051
|
-
|
9069
|
+
numchars.times do |i|
|
9052
9070
|
type = @@unicode[ta[i]]
|
9053
9071
|
if type == 'L'
|
9054
9072
|
pel = 0
|
@@ -9074,63 +9092,78 @@ public
|
|
9074
9092
|
|
9075
9093
|
# X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase.
|
9076
9094
|
# In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
|
9077
|
-
|
9078
|
-
|
9095
|
+
reg_KRP = /^(@@k_rle|@@k_lre|@@k_rlo|@@k_lro|@@k_pdf)$/
|
9096
|
+
reg_KR = /^(@@k_rle|@@k_lre|@@k_rlo|@@k_lro)$/
|
9097
|
+
numchars.times do |i|
|
9098
|
+
if ta[i] !~ reg_KRP
|
9099
|
+
# X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
|
9100
|
+
# a. Set the level of the current character to the current embedding level.
|
9101
|
+
# b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
|
9102
|
+
if dos != 'N'
|
9103
|
+
chardir = dos
|
9104
|
+
else
|
9105
|
+
chardir = @@unicode[ta[i]]
|
9106
|
+
chardir = 'L' if chardir.nil?
|
9107
|
+
end
|
9108
|
+
# stores string characters and other information
|
9109
|
+
chardata << {:char => ta[i], :level => cel, :type => chardir, :sor => sor, :eor => eor}
|
9110
|
+
next
|
9111
|
+
end
|
9112
|
+
|
9113
|
+
case ta[i]
|
9114
|
+
when @@k_rle
|
9079
9115
|
# X2. With each RLE, compute the least greater odd embedding level.
|
9080
9116
|
# a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
|
9081
9117
|
# b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
|
9082
9118
|
next_level = cel + (cel % 2) + 1
|
9083
9119
|
if next_level < 62
|
9084
|
-
remember
|
9120
|
+
remember << {:num => @@k_rle, :cel => cel, :dos => dos}
|
9085
9121
|
cel = next_level
|
9086
9122
|
dos = 'N'
|
9087
9123
|
sor = eor
|
9088
9124
|
eor = (cel % 2 == 1) ? 'R' : 'L'
|
9089
9125
|
end
|
9090
|
-
|
9126
|
+
when @@k_lre
|
9091
9127
|
# X3. With each LRE, compute the least greater even embedding level.
|
9092
9128
|
# a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
|
9093
9129
|
# b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
|
9094
9130
|
next_level = cel + 2 - (cel % 2)
|
9095
9131
|
if next_level < 62
|
9096
|
-
remember
|
9132
|
+
remember << {:num => @@k_lre, :cel => cel, :dos => dos}
|
9097
9133
|
cel = next_level
|
9098
9134
|
dos = 'N'
|
9099
9135
|
sor = eor
|
9100
9136
|
eor = (cel % 2 == 1) ? 'R' : 'L'
|
9101
9137
|
end
|
9102
|
-
|
9138
|
+
when @@k_rlo
|
9103
9139
|
# X4. With each RLO, compute the least greater odd embedding level.
|
9104
9140
|
# a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left.
|
9105
9141
|
# b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
|
9106
9142
|
next_level = cel + (cel % 2) + 1
|
9107
9143
|
if next_level < 62
|
9108
|
-
remember
|
9144
|
+
remember << {:num => @@k_rlo, :cel => cel, :dos => dos}
|
9109
9145
|
cel = next_level
|
9110
9146
|
dos = 'R'
|
9111
9147
|
sor = eor
|
9112
9148
|
eor = (cel % 2 == 1) ? 'R' : 'L'
|
9113
9149
|
end
|
9114
|
-
|
9150
|
+
when @@k_lro
|
9115
9151
|
# X5. With each LRO, compute the least greater even embedding level.
|
9116
9152
|
# a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right.
|
9117
9153
|
# b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
|
9118
9154
|
next_level = cel + 2 - (cel % 2)
|
9119
9155
|
if next_level < 62
|
9120
|
-
remember
|
9156
|
+
remember << {:num => @@k_lro, :cel => cel, :dos => dos}
|
9121
9157
|
cel = next_level
|
9122
9158
|
dos = 'L'
|
9123
9159
|
sor = eor
|
9124
9160
|
eor = (cel % 2 == 1) ? 'R' : 'L'
|
9125
9161
|
end
|
9126
|
-
|
9162
|
+
when @@k_pdf
|
9127
9163
|
# X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override.
|
9128
9164
|
if remember.length
|
9129
9165
|
last = remember.length - 1
|
9130
|
-
if
|
9131
|
-
(remember[last][:num] == @@k_lre) or
|
9132
|
-
(remember[last][:num] == @@k_rlo) or
|
9133
|
-
(remember[last][:num] == @@k_lro)
|
9166
|
+
if remember[last][:num] =~ reg_KR
|
9134
9167
|
match = remember.pop
|
9135
9168
|
cel = match[:cel]
|
9136
9169
|
dos = match[:dos]
|
@@ -9138,25 +9171,6 @@ public
|
|
9138
9171
|
eor = ((cel > match[:cel] ? cel : match[:cel]) % 2 == 1) ? 'R' : 'L'
|
9139
9172
|
end
|
9140
9173
|
end
|
9141
|
-
elsif (ta[i] != @@k_rle) and
|
9142
|
-
(ta[i] != @@k_lre) and
|
9143
|
-
(ta[i] != @@k_rlo) and
|
9144
|
-
(ta[i] != @@k_lro) and
|
9145
|
-
(ta[i] != @@k_pdf)
|
9146
|
-
# X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
|
9147
|
-
# a. Set the level of the current character to the current embedding level.
|
9148
|
-
# b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
|
9149
|
-
if dos != 'N'
|
9150
|
-
chardir = dos
|
9151
|
-
else
|
9152
|
-
if !@@unicode[ta[i]].nil?
|
9153
|
-
chardir = @@unicode[ta[i]]
|
9154
|
-
else
|
9155
|
-
chardir = 'L'
|
9156
|
-
end
|
9157
|
-
end
|
9158
|
-
# stores string characters and other information
|
9159
|
-
chardata.push :char => ta[i], :level => cel, :type => chardir, :sor => sor, :eor => eor
|
9160
9174
|
end
|
9161
9175
|
end # end for each char
|
9162
9176
|
|
@@ -9172,7 +9186,7 @@ public
|
|
9172
9186
|
# W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor.
|
9173
9187
|
prevlevel = -1 # track level changes
|
9174
9188
|
levcount = 0 # counts consecutive chars at the same level
|
9175
|
-
|
9189
|
+
numchars.times do |i|
|
9176
9190
|
if chardata[i][:type] == 'NSM'
|
9177
9191
|
if levcount
|
9178
9192
|
chardata[i][:type] = chardata[i][:sor]
|
@@ -9191,8 +9205,8 @@ public
|
|
9191
9205
|
# W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number.
|
9192
9206
|
prevlevel = -1
|
9193
9207
|
levcount = 0
|
9194
|
-
|
9195
|
-
if chardata[i][:
|
9208
|
+
numchars.times do |i|
|
9209
|
+
if chardata[i][:type] == 'EN'
|
9196
9210
|
levcount.downto(0) do |j|
|
9197
9211
|
if chardata[j][:type] == 'AL'
|
9198
9212
|
chardata[i][:type] = 'AN'
|
@@ -9210,7 +9224,7 @@ public
|
|
9210
9224
|
end
|
9211
9225
|
|
9212
9226
|
# W3. Change all ALs to R.
|
9213
|
-
|
9227
|
+
numchars.times do |i|
|
9214
9228
|
if chardata[i][:type] == 'AL'
|
9215
9229
|
chardata[i][:type] = 'R'
|
9216
9230
|
end
|
@@ -9219,7 +9233,7 @@ public
|
|
9219
9233
|
# W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type.
|
9220
9234
|
prevlevel = -1
|
9221
9235
|
levcount = 0
|
9222
|
-
|
9236
|
+
numchars.times do |i|
|
9223
9237
|
if (levcount > 0) and (i+1 < numchars) and (chardata[i+1][:level] == prevlevel)
|
9224
9238
|
if (chardata[i][:type] == 'ES') and (chardata[i-1][:type] == 'EN') and (chardata[i+1][:type] == 'EN')
|
9225
9239
|
chardata[i][:type] = 'EN'
|
@@ -9240,7 +9254,7 @@ public
|
|
9240
9254
|
# W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
|
9241
9255
|
prevlevel = -1
|
9242
9256
|
levcount = 0
|
9243
|
-
|
9257
|
+
numchars.times do |i|
|
9244
9258
|
if chardata[i][:type] == 'ET'
|
9245
9259
|
if (levcount > 0) and (chardata[i-1][:type] == 'EN')
|
9246
9260
|
chardata[i][:type] = 'EN'
|
@@ -9268,8 +9282,9 @@ public
|
|
9268
9282
|
# W6. Otherwise, separators and terminators change to Other Neutral.
|
9269
9283
|
prevlevel = -1
|
9270
9284
|
levcount = 0
|
9271
|
-
|
9272
|
-
|
9285
|
+
reg_ET_ES_CS = /^(ET|ES|CS)$/
|
9286
|
+
numchars.times do |i|
|
9287
|
+
if chardata[i][:type] =~ reg_ET_ES_CS
|
9273
9288
|
chardata[i][:type] = 'ON'
|
9274
9289
|
end
|
9275
9290
|
if chardata[i][:level] != prevlevel
|
@@ -9283,8 +9298,8 @@ public
|
|
9283
9298
|
# W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L.
|
9284
9299
|
prevlevel = -1
|
9285
9300
|
levcount = 0
|
9286
|
-
|
9287
|
-
if chardata[i][:
|
9301
|
+
numchars.times do |i|
|
9302
|
+
if chardata[i][:type] == 'EN'
|
9288
9303
|
levcount.downto(0) do |j|
|
9289
9304
|
if chardata[j][:type] == 'L'
|
9290
9305
|
chardata[i][:type] = 'L'
|
@@ -9304,45 +9319,62 @@ public
|
|
9304
9319
|
# N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries.
|
9305
9320
|
prevlevel = -1
|
9306
9321
|
levcount = 0
|
9307
|
-
|
9308
|
-
|
9309
|
-
|
9310
|
-
|
9311
|
-
|
9312
|
-
|
9313
|
-
|
9314
|
-
|
9315
|
-
|
9316
|
-
|
9317
|
-
|
9318
|
-
|
9319
|
-
|
9320
|
-
|
9321
|
-
|
9322
|
-
|
9323
|
-
|
9324
|
-
|
9325
|
-
|
9326
|
-
|
9327
|
-
|
9328
|
-
|
9329
|
-
|
9330
|
-
|
9331
|
-
|
9332
|
-
|
9333
|
-
|
9334
|
-
|
9335
|
-
|
9336
|
-
|
9337
|
-
|
9338
|
-
|
9339
|
-
|
9322
|
+
reg_NI = /^(B|S|WS|ON)$/
|
9323
|
+
reg_R_EN_AN = /^(R|EN|AN)$/
|
9324
|
+
reg_EN_AN = /^(EN|AN)$/
|
9325
|
+
ni = nil
|
9326
|
+
numchars.times do |i|
|
9327
|
+
if (chardata[i][:type] =~ reg_NI)
|
9328
|
+
if (levcount > 0) and (i+1 < numchars) and (chardata[i+1][:level] == prevlevel)
|
9329
|
+
if !ni.nil? and ni > i
|
9330
|
+
next_non_space_char = chardata[ni][:type]
|
9331
|
+
else
|
9332
|
+
ni = chardata[i+1..-1].index {|item| item[:type] !~ reg_NI}
|
9333
|
+
unless ni.nil?
|
9334
|
+
ni += i+1
|
9335
|
+
next_non_space_char = chardata[ni][:type]
|
9336
|
+
end
|
9337
|
+
end
|
9338
|
+
if (chardata[i-1][:type] == 'L') and (next_non_space_char == 'L')
|
9339
|
+
chardata[i][:type] = 'L'
|
9340
|
+
elsif ((chardata[i-1][:type] == 'R') and (next_non_space_char =~ reg_R_EN_AN) or
|
9341
|
+
(chardata[i-1][:type] =~ reg_EN_AN) and (next_non_space_char == 'R'))
|
9342
|
+
chardata[i][:type] = 'R'
|
9343
|
+
else
|
9344
|
+
# N2. Any remaining neutrals take the embedding direction
|
9345
|
+
chardata[i][:type] = chardata[i][:sor]
|
9346
|
+
end
|
9347
|
+
elsif (levcount == 0) and (i+1 < numchars) and (chardata[i+1][:level] == prevlevel)
|
9348
|
+
ni = chardata[i+1..-1].index {|item| item[:type] !~ reg_NI}
|
9349
|
+
unless ni.nil?
|
9350
|
+
ni += i+1
|
9351
|
+
next_non_space_char = chardata[ni][:type]
|
9352
|
+
end
|
9353
|
+
# first char
|
9354
|
+
if (chardata[i][:sor] == 'L') and (next_non_space_char == 'L')
|
9355
|
+
chardata[i][:type] = 'L'
|
9356
|
+
elsif ((chardata[i][:sor] == 'R') and (next_non_space_char =~ reg_R_EN_AN) or
|
9357
|
+
(chardata[i][:sor] =~ reg_EN_AN) and (next_non_space_char == 'R'))
|
9358
|
+
chardata[i][:type] = 'R'
|
9359
|
+
else
|
9360
|
+
# N2. Any remaining neutrals take the embedding direction
|
9361
|
+
chardata[i][:type] = chardata[i][:sor]
|
9362
|
+
end
|
9363
|
+
elsif (levcount > 0) and ((i+1 == numchars) or ((i+1 < numchars) and (chardata[i+1][:level] != prevlevel)))
|
9364
|
+
# last char
|
9365
|
+
if (chardata[i-1][:type] == 'L') and (chardata[i][:eor] == 'L')
|
9366
|
+
chardata[i][:type] = 'L'
|
9367
|
+
elsif ((chardata[i-1][:type] == 'R') and (chardata[i][:eor] =~ reg_R_EN_AN) or
|
9368
|
+
(chardata[i-1][:type] =~ reg_EN_AN) and (chardata[i][:eor] == 'R'))
|
9369
|
+
chardata[i][:type] = 'R'
|
9370
|
+
else
|
9371
|
+
# N2. Any remaining neutrals take the embedding direction
|
9372
|
+
chardata[i][:type] = chardata[i][:sor]
|
9373
|
+
end
|
9374
|
+
else
|
9340
9375
|
# N2. Any remaining neutrals take the embedding direction
|
9341
9376
|
chardata[i][:type] = chardata[i][:sor]
|
9342
9377
|
end
|
9343
|
-
elsif chardata[i][:type] == 'N'
|
9344
|
-
# N2. Any remaining neutrals take the embedding direction
|
9345
|
-
chardata[i][:type] = chardata[i][:sor]
|
9346
9378
|
end
|
9347
9379
|
if chardata[i][:level] != prevlevel
|
9348
9380
|
levcount = 0
|
@@ -9354,19 +9386,26 @@ public
|
|
9354
9386
|
|
9355
9387
|
# I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels.
|
9356
9388
|
# I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
|
9357
|
-
|
9389
|
+
prevlevel = -1
|
9390
|
+
reg_L_AN_EN = /^(L|AN|EN)$/
|
9391
|
+
reg_AN_EN = /^(AN|EN)$/
|
9392
|
+
|
9393
|
+
numchars.times do |i|
|
9358
9394
|
odd = chardata[i][:level] % 2
|
9359
|
-
if odd == 1
|
9360
|
-
if
|
9395
|
+
if odd == 1 # I2.
|
9396
|
+
if chardata[i][:type] =~ reg_L_AN_EN
|
9361
9397
|
chardata[i][:level] += 1
|
9362
9398
|
end
|
9363
|
-
else
|
9399
|
+
else # I1.
|
9364
9400
|
if chardata[i][:type] == 'R'
|
9365
9401
|
chardata[i][:level] += 1
|
9366
|
-
elsif
|
9402
|
+
elsif chardata[i][:type] == 'BN' and prevlevel != -1
|
9403
|
+
chardata[i][:level] = prevlevel
|
9404
|
+
elsif chardata[i][:type] =~ reg_AN_EN
|
9367
9405
|
chardata[i][:level] += 2
|
9368
9406
|
end
|
9369
9407
|
end
|
9408
|
+
prevlevel = chardata[i][:level]
|
9370
9409
|
maxlevel = [chardata[i][:level],maxlevel].max
|
9371
9410
|
end
|
9372
9411
|
|
@@ -9375,13 +9414,14 @@ public
|
|
9375
9414
|
# 2. Paragraph separators,
|
9376
9415
|
# 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
|
9377
9416
|
# 4. Any sequence of white space characters at the end of the line.
|
9378
|
-
|
9379
|
-
|
9417
|
+
reg_B_S = /^(B|S)$/
|
9418
|
+
numchars.times do |i|
|
9419
|
+
if chardata[i][:type] =~ reg_B_S
|
9380
9420
|
chardata[i][:level] = pel
|
9381
9421
|
elsif chardata[i][:type] == 'WS'
|
9382
9422
|
j = i+1
|
9383
9423
|
while j < numchars
|
9384
|
-
if (
|
9424
|
+
if (chardata[j][:type] =~ reg_B_S) or
|
9385
9425
|
((j == numchars-1) and (chardata[j][:type] == 'WS'))
|
9386
9426
|
chardata[i][:level] = pel
|
9387
9427
|
break
|
@@ -9402,16 +9442,18 @@ public
|
|
9402
9442
|
laaletter = false
|
9403
9443
|
charAL = []
|
9404
9444
|
x = 0
|
9405
|
-
|
9406
|
-
|
9407
|
-
|
9445
|
+
numchars.times do |i|
|
9446
|
+
c = chardata[i][:char]
|
9447
|
+
if (@@unicode[c] == 'AL') or (c == 32) or (c == 8204) # Unicode Character 'ZERO WIDTH NON-JOINER' (U+200C)
|
9448
|
+
charAL[x] = chardata[i].dup
|
9408
9449
|
charAL[x][:i] = i
|
9409
9450
|
chardata[i][:x] = x
|
9410
9451
|
x += 1
|
9411
9452
|
end
|
9412
9453
|
end
|
9413
9454
|
numAL = x
|
9414
|
-
|
9455
|
+
reg_AL_NSM = /^(AL|NSM)$/
|
9456
|
+
numchars.times do |i|
|
9415
9457
|
thischar = chardata[i]
|
9416
9458
|
if i > 0
|
9417
9459
|
prevchar = chardata[i-1]
|
@@ -9449,8 +9491,8 @@ public
|
|
9449
9491
|
laaletter = false
|
9450
9492
|
end
|
9451
9493
|
if (prevchar != false) and (nextchar != false) and
|
9452
|
-
(
|
9453
|
-
(
|
9494
|
+
(@@unicode[prevchar[:char]] =~ reg_AL_NSM) and
|
9495
|
+
(@@unicode[nextchar[:char]] =~ reg_AL_NSM) and
|
9454
9496
|
(nextchar[:type] == thischar[:type]) and
|
9455
9497
|
(nextchar[:char] != 1567)
|
9456
9498
|
# medial
|
@@ -9466,7 +9508,7 @@ public
|
|
9466
9508
|
end
|
9467
9509
|
end
|
9468
9510
|
elsif (nextchar != false) and
|
9469
|
-
(
|
9511
|
+
(@@unicode[nextchar[:char]] =~ reg_AL_NSM) and
|
9470
9512
|
(nextchar[:type] == thischar[:type]) and
|
9471
9513
|
(nextchar[:char] != 1567)
|
9472
9514
|
if !arabicarr[thischar[:char]].nil? and !arabicarr[thischar[:char]][2].nil?
|
@@ -9474,7 +9516,7 @@ public
|
|
9474
9516
|
chardata2[i][:char] = arabicarr[thischar[:char]][2]
|
9475
9517
|
end
|
9476
9518
|
elsif ((prevchar != false) and
|
9477
|
-
(
|
9519
|
+
(@@unicode[prevchar[:char]] =~ reg_AL_NSM) and
|
9478
9520
|
(prevchar[:type] == thischar[:type])) or
|
9479
9521
|
((nextchar != false) and (nextchar[:char] == 1567))
|
9480
9522
|
# final
|
@@ -9516,7 +9558,7 @@ public
|
|
9516
9558
|
# Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
|
9517
9559
|
#
|
9518
9560
|
cw = @current_font['cw']
|
9519
|
-
|
9561
|
+
(numchars-1).times do |i|
|
9520
9562
|
if (chardata2[i][:char] == 1617) and !@@diacritics[chardata2[i+1][:char]].nil?
|
9521
9563
|
# check if the subtitution font is defined on current font
|
9522
9564
|
unless cw[@@diacritics[chardata2[i+1][:char]]].nil?
|
@@ -9544,14 +9586,15 @@ public
|
|
9544
9586
|
ordarray = []
|
9545
9587
|
revarr = []
|
9546
9588
|
onlevel = false
|
9547
|
-
|
9589
|
+
numchars.times do |i|
|
9548
9590
|
if chardata[i][:level] >= j
|
9549
9591
|
onlevel = true
|
9550
|
-
|
9592
|
+
um = @@unicode_mirror[chardata[i][:char]]
|
9593
|
+
if um
|
9551
9594
|
# L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true.
|
9552
|
-
chardata[i][:char] =
|
9595
|
+
chardata[i][:char] = um
|
9553
9596
|
end
|
9554
|
-
revarr
|
9597
|
+
revarr << chardata[i]
|
9555
9598
|
else
|
9556
9599
|
if onlevel
|
9557
9600
|
revarr.reverse!
|
@@ -9559,7 +9602,7 @@ public
|
|
9559
9602
|
revarr = []
|
9560
9603
|
onlevel = false
|
9561
9604
|
end
|
9562
|
-
ordarray
|
9605
|
+
ordarray << chardata[i]
|
9563
9606
|
end
|
9564
9607
|
end
|
9565
9608
|
if onlevel
|
@@ -9570,7 +9613,7 @@ public
|
|
9570
9613
|
end
|
9571
9614
|
|
9572
9615
|
ordarray = []
|
9573
|
-
|
9616
|
+
numchars.times do |i|
|
9574
9617
|
ordarray.push chardata[i][:char]
|
9575
9618
|
end
|
9576
9619
|
|
@@ -14124,8 +14167,8 @@ public
|
|
14124
14167
|
if @is_unicode
|
14125
14168
|
alias_b = escape(UTF8ToLatin1(k))
|
14126
14169
|
alias_bu = escape(UTF8ToLatin1(ku))
|
14127
|
-
alias_c = escape(utf8StrRev(k, false,
|
14128
|
-
alias_cu = escape(utf8StrRev(ku, false,
|
14170
|
+
alias_c = escape(utf8StrRev(k, false, rtl_text_dir))
|
14171
|
+
alias_cu = escape(utf8StrRev(ku, false, rtl_text_dir))
|
14129
14172
|
end
|
14130
14173
|
if n >= page
|
14131
14174
|
np = n + numpages
|
@@ -14226,8 +14269,8 @@ public
|
|
14226
14269
|
if @is_unicode
|
14227
14270
|
alias_b = escape(UTF8ToLatin1(k))
|
14228
14271
|
alias_bu = escape(UTF8ToLatin1(ku))
|
14229
|
-
alias_c = escape(utf8StrRev(k, false,
|
14230
|
-
alias_cu = escape(utf8StrRev(ku, false,
|
14272
|
+
alias_c = escape(utf8StrRev(k, false, rtl_text_dir))
|
14273
|
+
alias_cu = escape(utf8StrRev(ku, false, rtl_text_dir))
|
14231
14274
|
end
|
14232
14275
|
if n >= page
|
14233
14276
|
np = n + numpages
|
data/lib/rbpdf/version.rb
CHANGED
data/test/rbpdf_bidi_test.rb
CHANGED
@@ -12,6 +12,42 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
12
12
|
def cache_utf8_string_to_array(str)
|
13
13
|
@cache_utf8_string_to_array[str]
|
14
14
|
end
|
15
|
+
def rtl_text_dir
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
test "RTL test" do
|
21
|
+
pdf = MYPDF.new
|
22
|
+
|
23
|
+
# LTR
|
24
|
+
rtl = pdf.get_rtl
|
25
|
+
assert_equal rtl, false
|
26
|
+
rtl = pdf.is_rtl_text_dir
|
27
|
+
assert_equal rtl, false
|
28
|
+
rtl = pdf.rtl_text_dir
|
29
|
+
assert_equal rtl, 'L'
|
30
|
+
|
31
|
+
pdf.set_temp_rtl('rtl')
|
32
|
+
rtl = pdf.is_rtl_text_dir
|
33
|
+
assert_equal rtl, true
|
34
|
+
rtl = pdf.rtl_text_dir
|
35
|
+
assert_equal rtl, 'R'
|
36
|
+
|
37
|
+
# RTL
|
38
|
+
pdf.set_rtl(true)
|
39
|
+
rtl = pdf.get_rtl
|
40
|
+
assert_equal rtl, true
|
41
|
+
rtl = pdf.is_rtl_text_dir
|
42
|
+
assert_equal rtl, true
|
43
|
+
rtl = pdf.rtl_text_dir
|
44
|
+
assert_equal rtl, 'R'
|
45
|
+
|
46
|
+
pdf.set_temp_rtl('ltr')
|
47
|
+
rtl = pdf.is_rtl_text_dir
|
48
|
+
assert_equal rtl, false
|
49
|
+
rtl = pdf.rtl_text_dir
|
50
|
+
assert_equal rtl, 'L'
|
15
51
|
end
|
16
52
|
|
17
53
|
test "Bidi" do
|
@@ -65,6 +101,99 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
65
101
|
assert_equal [0x61, 0x62, 0x63, 0x5ea, 0x5d9, 0x5e8, 0x5d1, 0x5e2], ary_str
|
66
102
|
end
|
67
103
|
|
104
|
+
test "Bidi ascii space test" do
|
105
|
+
pdf = MYPDF.new
|
106
|
+
|
107
|
+
ascii_str = "abc def"
|
108
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
109
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66]
|
110
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
111
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
112
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
113
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
114
|
+
|
115
|
+
ascii_str = "abc def"
|
116
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
117
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x20, 0x64, 0x65, 0x66]
|
118
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
119
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
120
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
121
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
122
|
+
|
123
|
+
ascii_str = "abc "
|
124
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
125
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x20]
|
126
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
127
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
128
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
129
|
+
assert_equal ary_ucs4_2, [0x20, 0x20, 0x61, 0x62, 0x63]
|
130
|
+
|
131
|
+
ascii_str = "abc_def"
|
132
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
133
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x5f, 0x64, 0x65, 0x66]
|
134
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
135
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
136
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
137
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
138
|
+
end
|
139
|
+
|
140
|
+
test "Bidi ascii numeric space test" do
|
141
|
+
pdf = MYPDF.new
|
142
|
+
|
143
|
+
ascii_str = "abc 123 def"
|
144
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
145
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x31, 0x32, 0x33, 0x20, 0x64, 0x65, 0x66]
|
146
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
147
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
148
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
149
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
150
|
+
|
151
|
+
ascii_str = "abc_123_def"
|
152
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
153
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x5f, 0x31, 0x32, 0x33, 0x5f, 0x64, 0x65, 0x66]
|
154
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
155
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
156
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
157
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
158
|
+
end
|
159
|
+
|
160
|
+
test "Bidi ascii colon test" do
|
161
|
+
pdf = MYPDF.new
|
162
|
+
|
163
|
+
ascii_str = "abc:def"
|
164
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
165
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x3a, 0x64, 0x65, 0x66]
|
166
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
167
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
168
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
169
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
170
|
+
|
171
|
+
ascii_str = "abc: def"
|
172
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
173
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x3a, 0x20, 0x64, 0x65, 0x66]
|
174
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
175
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
176
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
177
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
178
|
+
|
179
|
+
ascii_str = "abc : def"
|
180
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
181
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x3a, 0x20, 0x64, 0x65, 0x66]
|
182
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
183
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
184
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
185
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
186
|
+
|
187
|
+
ascii_str = "abc :: def"
|
188
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str))
|
189
|
+
assert_equal ary_ucs4_1, [0x61, 0x62, 0x63, 0x20, 0x20, 0x3a, 0x3a, 0x20, 0x20, 0x64, 0x65, 0x66]
|
190
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'R')
|
191
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
192
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(ascii_str), '', 'L')
|
193
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
194
|
+
end
|
195
|
+
|
196
|
+
|
68
197
|
test "Bidi arabic test" do
|
69
198
|
pdf = MYPDF.new
|
70
199
|
|
@@ -98,7 +227,108 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
98
227
|
assert_equal [0xfea9], ary_ucs4
|
99
228
|
|
100
229
|
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_arabic_str_1))
|
101
|
-
assert_equal [
|
230
|
+
assert_equal [0xfead, 0xfeed, 0xfea9], ary_ucs4
|
231
|
+
end
|
232
|
+
|
233
|
+
test "Bidi Persian Sunday test" do
|
234
|
+
pdf = MYPDF.new
|
235
|
+
|
236
|
+
utf8_persian_str_1 = "\xdb\x8c"
|
237
|
+
utf8_persian_str_2 = "\xdb\x8c\xda\xa9"
|
238
|
+
utf8_persian_str_3 = "\xdb\x8c\xda\xa9\xe2\x80\x8c"
|
239
|
+
utf8_persian_str_4 = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4"
|
240
|
+
utf8_persian_str_5 = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86"
|
241
|
+
utf8_persian_str_6 = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8"
|
242
|
+
utf8_persian_str_7 = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87" # Sunday
|
243
|
+
|
244
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_1))
|
245
|
+
assert_equal ary_ucs4, [0xfbfc]
|
246
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_2))
|
247
|
+
assert_equal ary_ucs4, [0xfb8f, 0xfbfe]
|
248
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_3))
|
249
|
+
assert_equal ary_ucs4, [0x200C, 0xfb8f, 0xfbfe]
|
250
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_4))
|
251
|
+
assert_equal ary_ucs4, [0xfeb5, 0x200C, 0xfb8f, 0xfbfe]
|
252
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_5))
|
253
|
+
assert_equal ary_ucs4, [0xfee6, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe]
|
254
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_6))
|
255
|
+
assert_equal ary_ucs4, [0xfe90, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe]
|
256
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_7))
|
257
|
+
assert_equal ary_ucs4, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe]
|
258
|
+
end
|
259
|
+
|
260
|
+
test "Bidi Persian Sunday forcertl test" do
|
261
|
+
pdf = MYPDF.new
|
262
|
+
utf8_persian_str_sunday = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
263
|
+
|
264
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_sunday), '', 'R')
|
265
|
+
assert_equal ary_ucs4_1, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe]
|
266
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_sunday), '', 'L')
|
267
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
268
|
+
end
|
269
|
+
|
270
|
+
test "Bidi Persian Monday test" do
|
271
|
+
pdf = MYPDF.new
|
272
|
+
|
273
|
+
utf8_persian_str_1 = "\xd8\xaf"
|
274
|
+
utf8_persian_str_2 = "\xd8\xaf\xd9\x88"
|
275
|
+
utf8_persian_str_3 = "\xd8\xaf\xd9\x88\xd8\xb4"
|
276
|
+
utf8_persian_str_4 = "\xd8\xaf\xd9\x88\xd8\xb4\xd9\x86"
|
277
|
+
utf8_persian_str_5 = "\xd8\xaf\xd9\x88\xd8\xb4\xd9\x86\xd8\xa8"
|
278
|
+
utf8_persian_str_6 = "\xd8\xaf\xd9\x88\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87" # Monday
|
279
|
+
|
280
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_1))
|
281
|
+
assert_equal ary_ucs4, [0xfea9]
|
282
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_2))
|
283
|
+
assert_equal ary_ucs4, [0xfeed, 0xfea9]
|
284
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_3))
|
285
|
+
assert_equal ary_ucs4, [0xfeb5, 0xfeed, 0xfea9]
|
286
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_4))
|
287
|
+
assert_equal ary_ucs4, [0xfee6, 0xfeb7, 0xfeed, 0xfea9]
|
288
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_5))
|
289
|
+
assert_equal ary_ucs4, [0xfe90, 0xfee8, 0xfeb7, 0xfeed, 0xfea9]
|
290
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_6))
|
291
|
+
assert_equal ary_ucs4, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0xfeed, 0xfea9]
|
292
|
+
end
|
293
|
+
|
294
|
+
test "Bidi Persian Monday forcertl test" do
|
295
|
+
pdf = MYPDF.new
|
296
|
+
utf8_persian_str_monday = "\xd8\xaf\xd9\x88\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
297
|
+
|
298
|
+
ary_ucs4_1 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_monday), '', 'R')
|
299
|
+
assert_equal ary_ucs4_1, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0xfeed, 0xfea9]
|
300
|
+
ary_ucs4_2 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_monday), '', 'L')
|
301
|
+
assert_equal ary_ucs4_2, ary_ucs4_1
|
302
|
+
end
|
303
|
+
|
304
|
+
test "Bidi Persian and English test" do
|
305
|
+
pdf = MYPDF.new
|
306
|
+
|
307
|
+
utf8_persian_str_sunday = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
308
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_sunday + ' abc'))
|
309
|
+
assert_equal ary_ucs4, [0x61, 0x62, 0x63, 0x20, # 'abc '
|
310
|
+
0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe] # Sunday
|
311
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_sunday + ' abc'), '', 'R')
|
312
|
+
assert_equal ary_ucs4, [0x61, 0x62, 0x63, 0x20, # 'abc '
|
313
|
+
0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe] # Sunday
|
314
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray(utf8_persian_str_sunday + ' abc'), '', 'L')
|
315
|
+
assert_equal ary_ucs4, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe, # Sunday
|
316
|
+
0x20, 0x61, 0x62, 0x63] # 'abc '
|
317
|
+
end
|
318
|
+
|
319
|
+
test "Bidi English and Persian test" do
|
320
|
+
pdf = MYPDF.new
|
321
|
+
|
322
|
+
utf8_persian_str_sunday = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
323
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray('abc ' + utf8_persian_str_sunday))
|
324
|
+
assert_equal ary_ucs4, [0x61, 0x62, 0x63, 0x20, # 'abc '
|
325
|
+
0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe] # Sunday
|
326
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray('abc ' + utf8_persian_str_sunday), '', 'L')
|
327
|
+
assert_equal ary_ucs4, [0x61, 0x62, 0x63, 0x20, # 'abc '
|
328
|
+
0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe] # Sunday
|
329
|
+
ary_ucs4 = pdf.utf8Bidi(pdf.UTF8StringToArray('abc ' + utf8_persian_str_sunday), '', 'R')
|
330
|
+
assert_equal ary_ucs4, [0xfeea, 0xfe92, 0xfee8, 0xfeb7, 0x200C, 0xfb8f, 0xfbfe, # Sunday
|
331
|
+
0x20, 0x61, 0x62, 0x63] # 'abc '
|
102
332
|
end
|
103
333
|
|
104
334
|
test "Bidi date test" do
|
@@ -128,4 +358,10 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
128
358
|
rtn = pdf.cache_utf8_string_to_array('1234')
|
129
359
|
assert_equal rtn, [0x31, 0x32, 0x33, 0x34]
|
130
360
|
end
|
361
|
+
|
362
|
+
test "UniArrSubString test" do
|
363
|
+
pdf = RBPDF.new
|
364
|
+
str = pdf.uni_arr_sub_string(['a', 'b', 'c', ' ', 'd', 'e', 'f'])
|
365
|
+
assert_equal str, 'abc def'
|
366
|
+
end
|
131
367
|
end
|
data/test/rbpdf_content_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: ASCII-8BIT
|
1
2
|
require 'test_helper'
|
2
3
|
|
3
4
|
class RbpdfPageTest < ActiveSupport::TestCase
|
@@ -112,6 +113,84 @@ class RbpdfPageTest < ActiveSupport::TestCase
|
|
112
113
|
assert_equal content[12], '340.88 141.17 370.62 158.34 392.04 183.86 c' # 8/9 circle
|
113
114
|
assert_equal content[13], '413.45 209.38 425.20 241.65 425.20 274.96 c' # 9/9 circle
|
114
115
|
assert_equal content[14], 'S'
|
116
|
+
end
|
117
|
+
|
118
|
+
test "write content test" do
|
119
|
+
pdf = MYPDF.new
|
120
|
+
pdf.add_page()
|
121
|
+
page = pdf.get_page
|
122
|
+
assert_equal 1, page
|
123
|
+
|
124
|
+
content = []
|
125
|
+
line = pdf.write(0, "abc def")
|
126
|
+
contents = pdf.getPageBuffer(page)
|
127
|
+
contents.each_line {|line| content.push line.chomp }
|
128
|
+
assert_equal content.length, 22
|
129
|
+
assert_equal content[21], "BT 31.19 801.84 Td 0 Tr 0.00 w [(abc def)] TJ ET"
|
130
|
+
end
|
131
|
+
|
132
|
+
test "write content RTL test" do
|
133
|
+
pdf = MYPDF.new
|
134
|
+
pdf.set_rtl(true)
|
135
|
+
pdf.add_page()
|
136
|
+
page = pdf.get_page
|
137
|
+
assert_equal 1, page
|
138
|
+
|
139
|
+
content = []
|
140
|
+
line = pdf.write(0, "abc def")
|
141
|
+
contents = pdf.getPageBuffer(page)
|
142
|
+
contents.each_line {|line| content.push line.chomp }
|
143
|
+
assert_equal content.length, 22
|
144
|
+
assert_equal content[21], "BT 524.73 801.84 Td 0 Tr 0.00 w [(abc def)] TJ ET"
|
145
|
+
end
|
146
|
+
|
147
|
+
test "write Persian Sunday content test" do
|
148
|
+
pdf = MYPDF.new
|
149
|
+
pdf.set_font('dejavusans', '', 18)
|
150
|
+
pdf.add_page()
|
151
|
+
page = pdf.get_page
|
152
|
+
assert_equal 1, page
|
115
153
|
|
154
|
+
utf8_persian_str_sunday = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
155
|
+
content = []
|
156
|
+
line = pdf.write(0, utf8_persian_str_sunday)
|
157
|
+
contents = pdf.getPageBuffer(page)
|
158
|
+
|
159
|
+
contents.each_line {|line| content.push line.chomp }
|
160
|
+
assert_equal content.length, 22
|
161
|
+
assert_equal content[21], "BT 31.19 796.06 Td 0 Tr 0.00 w [(\xFE\xEA\xFE\x92\xFE\xE8\xFE\xB7 \f\xFB\x8F\xFB\xFE)] TJ ET"
|
162
|
+
|
163
|
+
pdf.set_rtl(true)
|
164
|
+
line = pdf.write(0, utf8_persian_str_sunday)
|
165
|
+
contents = pdf.getPageBuffer(page)
|
166
|
+
|
167
|
+
contents.each_line {|line| content.push line.chomp }
|
168
|
+
assert_equal content.length, 46
|
169
|
+
assert_equal content[45], "BT 507.38 796.06 Td 0 Tr 0.00 w [(\xFE\xEA\xFE\x92\xFE\xE8\xFE\xB7 \f\xFB\x8F\xFB\xFE)] TJ ET"
|
170
|
+
end
|
171
|
+
|
172
|
+
test "write English and Persian Sunday content test" do
|
173
|
+
pdf = MYPDF.new
|
174
|
+
pdf.set_font('dejavusans', '', 18)
|
175
|
+
pdf.add_page()
|
176
|
+
page = pdf.get_page
|
177
|
+
assert_equal 1, page
|
178
|
+
|
179
|
+
utf8_persian_str_sunday = "\xdb\x8c\xda\xa9\xe2\x80\x8c\xd8\xb4\xd9\x86\xd8\xa8\xd9\x87"
|
180
|
+
content = []
|
181
|
+
line = pdf.write(0, 'abc def ' + utf8_persian_str_sunday)
|
182
|
+
contents = pdf.getPageBuffer(page)
|
183
|
+
|
184
|
+
contents.each_line {|line| content.push line.chomp }
|
185
|
+
assert_equal content.length, 22
|
186
|
+
assert_equal content[21], "BT 31.19 796.06 Td 0 Tr 0.00 w [(\x00a\x00b\x00c\x00 \x00d\x00e\x00f\x00 \xFE\xEA\xFE\x92\xFE\xE8\xFE\xB7 \f\xFB\x8F\xFB\xFE)] TJ ET"
|
187
|
+
|
188
|
+
pdf.set_rtl(true)
|
189
|
+
line = pdf.write(0, 'abc def ' + utf8_persian_str_sunday)
|
190
|
+
contents = pdf.getPageBuffer(page)
|
191
|
+
|
192
|
+
contents.each_line {|line| content.push line.chomp }
|
193
|
+
assert_equal content.length, 46
|
194
|
+
assert_equal content[45], "BT 434.73 796.06 Td 0 Tr 0.00 w [(\xFE\xEA\xFE\x92\xFE\xE8\xFE\xB7 \f\xFB\x8F\xFB\xFE\x00 \x00a\x00b\x00c\x00 \x00d\x00e\x00f)] TJ ET"
|
116
195
|
end
|
117
196
|
end
|
data/test/rbpdf_dom_test.rb
CHANGED
@@ -8,6 +8,9 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
8
8
|
def openHTMLTagHandler(dom, key, cell)
|
9
9
|
super
|
10
10
|
end
|
11
|
+
def get_temp_rtl
|
12
|
+
@tmprtl
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
test "Dom Basic" do
|
@@ -179,6 +182,89 @@ class RbpdfTest < ActiveSupport::TestCase
|
|
179
182
|
assert_equal dom1, dom2
|
180
183
|
end
|
181
184
|
|
185
|
+
test "Dom HTMLTagHandler DIR RTL test" do
|
186
|
+
pdf = MYPDF.new
|
187
|
+
pdf.add_page
|
188
|
+
temprtl = pdf.get_temp_rtl
|
189
|
+
assert_equal temprtl, false
|
190
|
+
|
191
|
+
# LTR, ltr
|
192
|
+
htmlcontent = '<p dir="ltr">HTML Example</p>'
|
193
|
+
dom = pdf.getHtmlDomArray(htmlcontent)
|
194
|
+
dom = pdf.openHTMLTagHandler(dom, 1, false)
|
195
|
+
|
196
|
+
assert_equal dom[1]['tag'], true
|
197
|
+
assert_equal dom[1]['opening'], true
|
198
|
+
assert_equal dom[1]['value'], 'p'
|
199
|
+
assert_equal dom[1]['attribute']['dir'], 'ltr'
|
200
|
+
|
201
|
+
temprtl = pdf.get_temp_rtl
|
202
|
+
assert_equal temprtl, false
|
203
|
+
|
204
|
+
# LTR, rtl
|
205
|
+
htmlcontent = '<p dir="rtl">HTML Example</p>'
|
206
|
+
dom = pdf.getHtmlDomArray(htmlcontent)
|
207
|
+
dom = pdf.openHTMLTagHandler(dom, 1, false)
|
208
|
+
assert_equal dom.length, 4
|
209
|
+
|
210
|
+
assert_equal dom[1]['tag'], true
|
211
|
+
assert_equal dom[1]['opening'], true
|
212
|
+
assert_equal dom[1]['value'], 'p'
|
213
|
+
assert_equal dom[1]['attribute']['dir'], 'rtl'
|
214
|
+
|
215
|
+
temprtl = pdf.get_temp_rtl
|
216
|
+
assert_equal temprtl, 'R'
|
217
|
+
|
218
|
+
# LTR, ltr
|
219
|
+
htmlcontent = '<p dir="ltr">HTML Example</p>'
|
220
|
+
dom = pdf.getHtmlDomArray(htmlcontent)
|
221
|
+
dom = pdf.openHTMLTagHandler(dom, 1, false)
|
222
|
+
|
223
|
+
assert_equal dom[1]['tag'], true
|
224
|
+
assert_equal dom[1]['opening'], true
|
225
|
+
assert_equal dom[1]['value'], 'p'
|
226
|
+
assert_equal dom[1]['attribute']['dir'], 'ltr'
|
227
|
+
|
228
|
+
temprtl = pdf.get_temp_rtl
|
229
|
+
assert_equal temprtl, false
|
230
|
+
end
|
231
|
+
|
232
|
+
test "Dom HTMLTagHandler DIR LTR test" do
|
233
|
+
pdf = MYPDF.new
|
234
|
+
pdf.add_page
|
235
|
+
temprtl = pdf.get_temp_rtl
|
236
|
+
assert_equal temprtl, false
|
237
|
+
pdf.set_rtl(true)
|
238
|
+
|
239
|
+
# RTL, ltr
|
240
|
+
htmlcontent = '<p dir="ltr">HTML Example</p>'
|
241
|
+
dom = pdf.getHtmlDomArray(htmlcontent)
|
242
|
+
dom = pdf.openHTMLTagHandler(dom, 1, false)
|
243
|
+
assert_equal dom.length, 4
|
244
|
+
|
245
|
+
assert_equal dom[1]['tag'], true
|
246
|
+
assert_equal dom[1]['opening'], true
|
247
|
+
assert_equal dom[1]['value'], 'p'
|
248
|
+
assert_equal dom[1]['attribute']['dir'], 'ltr'
|
249
|
+
|
250
|
+
temprtl = pdf.get_temp_rtl
|
251
|
+
assert_equal temprtl, 'L'
|
252
|
+
|
253
|
+
# RTL, rtl
|
254
|
+
htmlcontent = '<p dir="rtl">HTML Example</p>'
|
255
|
+
dom = pdf.getHtmlDomArray(htmlcontent)
|
256
|
+
dom = pdf.openHTMLTagHandler(dom, 1, false)
|
257
|
+
assert_equal dom.length, 4
|
258
|
+
|
259
|
+
assert_equal dom[1]['tag'], true
|
260
|
+
assert_equal dom[1]['opening'], true
|
261
|
+
assert_equal dom[1]['value'], 'p'
|
262
|
+
assert_equal dom[1]['attribute']['dir'], 'rtl'
|
263
|
+
|
264
|
+
temprtl = pdf.get_temp_rtl
|
265
|
+
assert_equal temprtl, false
|
266
|
+
end
|
267
|
+
|
182
268
|
test "Dom HTMLTagHandler img test" do
|
183
269
|
pdf = MYPDF.new
|
184
270
|
pdf.add_page
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbpdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.18.
|
4
|
+
version: 1.18.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NAITOH Jun
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|