twitter_cldr 5.1.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +5 -5
- data/lib/twitter_cldr.rb +1 -0
- data/lib/twitter_cldr/resources.rb +2 -8
- data/lib/twitter_cldr/resources/loader.rb +6 -4
- data/lib/twitter_cldr/resources/locales_resources_importer.rb +0 -1
- data/lib/twitter_cldr/resources/segment_rules_importer.rb +202 -0
- data/lib/twitter_cldr/resources/segment_tests_importer.rb +3 -1
- data/lib/twitter_cldr/segmentation.rb +10 -8
- data/lib/twitter_cldr/segmentation/break_iterator.rb +15 -11
- data/lib/twitter_cldr/segmentation/category_table.rb +56 -0
- data/lib/twitter_cldr/segmentation/cursor.rb +10 -5
- data/lib/twitter_cldr/segmentation/metadata.rb +20 -0
- data/lib/twitter_cldr/segmentation/null_suppressions.rb +18 -0
- data/lib/twitter_cldr/segmentation/rule_set.rb +23 -79
- data/lib/twitter_cldr/segmentation/state_machine.rb +125 -0
- data/lib/twitter_cldr/segmentation/state_table.rb +46 -0
- data/lib/twitter_cldr/segmentation/status_table.rb +30 -0
- data/lib/twitter_cldr/segmentation/suppressions.rb +79 -0
- data/lib/twitter_cldr/shared/caser.rb +1 -1
- data/lib/twitter_cldr/shared/locale.rb +6 -2
- data/lib/twitter_cldr/version.rb +1 -1
- data/resources/shared/segments/rules/el/sentence.yml +723 -0
- data/resources/shared/segments/rules/en-US-POSIX/word.yml +527 -0
- data/resources/shared/segments/rules/ja/line.yml +964 -0
- data/resources/shared/segments/rules/ja/word.yml +527 -0
- data/resources/shared/segments/rules/root/grapheme.yml +463 -0
- data/resources/shared/segments/rules/root/line.yml +964 -0
- data/resources/shared/segments/rules/root/sentence.yml +723 -0
- data/resources/shared/segments/rules/root/word.yml +527 -0
- data/resources/shared/segments/rules/zh-Hant/line.yml +964 -0
- data/resources/shared/segments/rules/zh/line.yml +964 -0
- data/resources/shared/segments/suppressions/de/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/en/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/es/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/fr/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/it/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/pt/sentence.yml +5 -0
- data/resources/shared/segments/suppressions/ru/sentence.yml +5 -0
- data/resources/shared/segments/tests/grapheme_break_test.yml +603 -0
- data/resources/shared/segments/tests/line_break_test.yml +7348 -0
- data/resources/uli/segments/de.yml +5 -230
- data/resources/uli/segments/en.yml +3 -154
- data/resources/uli/segments/es.yml +5 -145
- data/resources/uli/segments/fr.yml +5 -68
- data/resources/uli/segments/it.yml +3 -48
- data/resources/uli/segments/pt.yml +5 -173
- data/resources/uli/segments/ru.yml +3 -10
- data/spec/segmentation/rule_set_spec.rb +54 -27
- metadata +29 -9
- data/lib/twitter_cldr/resources/uli.rb +0 -12
- data/lib/twitter_cldr/resources/uli/segment_exceptions_importer.rb +0 -59
- data/lib/twitter_cldr/segmentation/parser.rb +0 -71
- data/lib/twitter_cldr/segmentation/rule.rb +0 -79
- data/lib/twitter_cldr/segmentation/rule_set_builder.rb +0 -142
- data/resources/shared/segments/segments_root.yml +0 -869
- data/spec/segmentation/parser_spec.rb +0 -104
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b616d55c343da67733837c0f1549329d895ea3758011b4c5dd8c90c3c631f53a
|
4
|
+
data.tar.gz: 3717867c2412adcc7a95ff1dfbe032e1754ade3cc005b4445d1f8ff644048b06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f82323e912a622930f192a2ffe8b742ce1378feff847a082e04b7ea0feb5df215faa183861e31a35e69bc966c6222d0182689cdc5264de69263acbc60acce8ff
|
7
|
+
data.tar.gz: dc11c5d5e3ab6cc0f2cf3a6073686f7167ac6621252a0b6bf4c7f0b1eb53ae7134507aa0d66e5c0c57e7abc9b689a6438032b4982abe766b9c8550b6df0139b8
|
data/Rakefile
CHANGED
@@ -155,6 +155,11 @@ namespace :update do
|
|
155
155
|
TwitterCldr::Resources::CollationTestsImporter.new.import
|
156
156
|
end
|
157
157
|
|
158
|
+
desc 'Import text segmentation rules'
|
159
|
+
task :segment_rules do
|
160
|
+
TwitterCldr::Resources::SegmentRulesImporter.new.import
|
161
|
+
end
|
162
|
+
|
158
163
|
desc 'Import (generate) bidi tests (should be executed using JRuby 1.7 in 1.9 mode)'
|
159
164
|
task :bidi_tests do
|
160
165
|
TwitterCldr::Resources::BidiTestImporter.new.import
|
@@ -195,11 +200,6 @@ namespace :update do
|
|
195
200
|
TwitterCldr::Resources::TransformTestsImporter.new.import
|
196
201
|
end
|
197
202
|
|
198
|
-
desc 'Import segment exceptions'
|
199
|
-
task :segment_exceptions do
|
200
|
-
TwitterCldr::Resources::Uli::SegmentExceptionsImporter.new.import
|
201
|
-
end
|
202
|
-
|
203
203
|
desc 'Import segment tests'
|
204
204
|
task :segment_tests do
|
205
205
|
TwitterCldr::Resources::SegmentTestsImporter.new.import
|
data/lib/twitter_cldr.rb
CHANGED
@@ -22,6 +22,7 @@ module TwitterCldr
|
|
22
22
|
autoload :NumberFormatsImporter, 'twitter_cldr/resources/number_formats_importer'
|
23
23
|
autoload :PostalCodesImporter, 'twitter_cldr/resources/postal_codes_importer'
|
24
24
|
autoload :Properties, 'twitter_cldr/resources/properties'
|
25
|
+
autoload :SegmentRulesImporter, 'twitter_cldr/resources/segment_rules_importer'
|
25
26
|
autoload :RbnfTestImporter, 'twitter_cldr/resources/rbnf_test_importer'
|
26
27
|
autoload :ReadmeRenderer, 'twitter_cldr/resources/readme_renderer'
|
27
28
|
autoload :RegexpAstGenerator, 'twitter_cldr/resources/regexp_ast_generator'
|
@@ -37,7 +38,6 @@ module TwitterCldr
|
|
37
38
|
autoload :UnicodeDataImporter, 'twitter_cldr/resources/unicode_data_importer'
|
38
39
|
autoload :UnicodeFileParser, 'twitter_cldr/resources/unicode_file_parser'
|
39
40
|
autoload :UnicodePropertyAliasesImporter, 'twitter_cldr/resources/unicode_property_aliases_importer'
|
40
|
-
autoload :Uli, 'twitter_cldr/resources/uli'
|
41
41
|
autoload :ValidityDataImporter, 'twitter_cldr/resources/validity_data_importer'
|
42
42
|
|
43
43
|
class << self
|
@@ -60,6 +60,7 @@ module TwitterCldr
|
|
60
60
|
NumberFormatsImporter,
|
61
61
|
PostalCodesImporter,
|
62
62
|
RbnfTestImporter,
|
63
|
+
SegmentRulesImporter,
|
63
64
|
SegmentTestsImporter,
|
64
65
|
TailoringImporter,
|
65
66
|
TerritoriesImporter,
|
@@ -74,12 +75,6 @@ module TwitterCldr
|
|
74
75
|
]
|
75
76
|
end
|
76
77
|
|
77
|
-
def uli_importer_classes
|
78
|
-
@uli_importer_classes ||= [
|
79
|
-
Uli::SegmentExceptionsImporter
|
80
|
-
]
|
81
|
-
end
|
82
|
-
|
83
78
|
def property_importer_classes
|
84
79
|
@property_importer_classes ||= [
|
85
80
|
Properties::AgePropertyImporter,
|
@@ -107,7 +102,6 @@ module TwitterCldr
|
|
107
102
|
def importer_classes
|
108
103
|
@importer_classes ||=
|
109
104
|
standard_importer_classes +
|
110
|
-
uli_importer_classes +
|
111
105
|
property_importer_classes
|
112
106
|
end
|
113
107
|
|
@@ -73,6 +73,12 @@ module TwitterCldr
|
|
73
73
|
nil
|
74
74
|
end
|
75
75
|
|
76
|
+
def resource_file_path(path)
|
77
|
+
file = File.join(*path.map(&:to_s))
|
78
|
+
file << '.yml' unless file.end_with?('.yml')
|
79
|
+
file
|
80
|
+
end
|
81
|
+
|
76
82
|
private
|
77
83
|
|
78
84
|
def locale_resource_path(locale, resource_name)
|
@@ -85,10 +91,6 @@ module TwitterCldr
|
|
85
91
|
end
|
86
92
|
end
|
87
93
|
|
88
|
-
def resource_file_path(path)
|
89
|
-
"#{File.join(*path.map(&:to_s))}.yml"
|
90
|
-
end
|
91
|
-
|
92
94
|
def load_resource(path, merge_custom = true)
|
93
95
|
base = YAML.load(read_resource_file(path))
|
94
96
|
custom_path = File.join("custom", path)
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2012 Twitter, Inc
|
4
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'nokogiri'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
module TwitterCldr
|
12
|
+
module Resources
|
13
|
+
|
14
|
+
class SegmentRulesImporter < Importer
|
15
|
+
|
16
|
+
# @TODO: moar boundary types
|
17
|
+
BOUNDARY_TYPES = {
|
18
|
+
'word' => 'word',
|
19
|
+
'sentence' => 'sentence',
|
20
|
+
'grapheme' => 'grapheme',
|
21
|
+
'line' => 'line' # loose, normal, strict
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
TYPES_TO_ATTRS = {
|
25
|
+
'word' => 'WordBreak',
|
26
|
+
'sentence' => 'SentenceBreak',
|
27
|
+
'grapheme' => 'GraphemeClusterBreak',
|
28
|
+
'line' => 'LineBreak'
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
Locale = TwitterCldr::Shared::Locale
|
32
|
+
|
33
|
+
StateTable = TwitterCldr::Segmentation::StateTable
|
34
|
+
StatusTable = TwitterCldr::Segmentation::StatusTable
|
35
|
+
CategoryTable = TwitterCldr::Segmentation::CategoryTable
|
36
|
+
|
37
|
+
requirement :icu, Versions.icu_version
|
38
|
+
requirement :cldr, Versions.cldr_version
|
39
|
+
output_path File.join('shared', 'segments')
|
40
|
+
ruby_engine :jruby
|
41
|
+
|
42
|
+
def execute
|
43
|
+
each_locale do |locale, doc|
|
44
|
+
BOUNDARY_TYPES.each do |kind, icu_kind|
|
45
|
+
seg = doc.xpath(
|
46
|
+
"//ldml/segmentations/segmentation[@type=\"#{TYPES_TO_ATTRS[kind]}\"]"
|
47
|
+
)
|
48
|
+
|
49
|
+
rule_data = rule_data_for(icu_kind, locale, seg)
|
50
|
+
|
51
|
+
unless rule_data.empty?
|
52
|
+
output_dir = File.join(output_path, 'rules', locale)
|
53
|
+
output_file = File.join(output_dir, "#{kind}.yml")
|
54
|
+
FileUtils.mkdir_p(output_dir)
|
55
|
+
File.write(output_file, YAML.dump(rule_data))
|
56
|
+
end
|
57
|
+
|
58
|
+
suppressions = suppressions_for(icu_kind, locale, seg)
|
59
|
+
|
60
|
+
unless suppressions.empty?
|
61
|
+
output_dir = File.join(output_path, 'suppressions', locale)
|
62
|
+
output_file = File.join(output_dir, "#{kind}.yml")
|
63
|
+
FileUtils.mkdir_p(output_dir)
|
64
|
+
File.write(output_file, YAML.dump(suppressions))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def each_locale
|
73
|
+
return to_enum(__method__) unless block_given?
|
74
|
+
|
75
|
+
pattern = File.join(requirements[:cldr].common_path, 'segments', '*.xml')
|
76
|
+
|
77
|
+
Dir.glob(pattern).each do |file, ret|
|
78
|
+
locale = File.basename(file).chomp('.xml').tr('_', '-')
|
79
|
+
yield locale, Nokogiri::XML(File.read(file))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def rule_data_for(kind, locale, doc)
|
84
|
+
vars = doc.xpath('variables/variable')
|
85
|
+
rules = doc.xpath('segmentRules/rule')
|
86
|
+
result = {}
|
87
|
+
|
88
|
+
unless vars.empty? && rules.empty?
|
89
|
+
result.merge!(encode_rbbi_data(rbbi_data_for(kind, locale)))
|
90
|
+
end
|
91
|
+
|
92
|
+
result
|
93
|
+
end
|
94
|
+
|
95
|
+
def suppressions_for(kind, locale, doc)
|
96
|
+
suppressions = doc.xpath('suppressions/suppression').map(&:text)
|
97
|
+
return {} if suppressions.empty?
|
98
|
+
|
99
|
+
encode_suppressions(suppressions)
|
100
|
+
end
|
101
|
+
|
102
|
+
def encode_rbbi_data(data)
|
103
|
+
{
|
104
|
+
metadata: metadata_from(data.fHeader),
|
105
|
+
forward_table: StateTable.new(data.fFTable.fTable.to_a, data.fFTable.fFlags).dump16,
|
106
|
+
backward_table: StateTable.new(data.fRTable.fTable.to_a, data.fRTable.fFlags).dump16,
|
107
|
+
status_table: StatusTable.new(data.fStatusTable.to_a).dump,
|
108
|
+
category_table: encode_trie(data.fTrie), # this really isn't a trie
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def metadata_from(header)
|
113
|
+
{ category_count: header.fCatCount }
|
114
|
+
end
|
115
|
+
|
116
|
+
def encode_suppressions(suppressions)
|
117
|
+
forwards_trie = TwitterCldr::Utils::Trie.new
|
118
|
+
backwards_trie = TwitterCldr::Utils::Trie.new
|
119
|
+
|
120
|
+
suppressions.each do |suppression|
|
121
|
+
forwards_trie.add(suppression.codepoints, true)
|
122
|
+
backwards_trie.add(suppression.reverse.codepoints, true)
|
123
|
+
end
|
124
|
+
|
125
|
+
{
|
126
|
+
forwards_trie: Marshal.dump(forwards_trie),
|
127
|
+
backwards_trie: Marshal.dump(backwards_trie)
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def encode_trie(trie)
|
132
|
+
arr = [].tap do |results|
|
133
|
+
iter = trie.iterator
|
134
|
+
|
135
|
+
while iter.hasNext
|
136
|
+
range = iter.next
|
137
|
+
results << range_to_a(range)
|
138
|
+
|
139
|
+
# this should be the last entry, but for some reason ICU returns
|
140
|
+
# one more out-of-order range past the Unicode max
|
141
|
+
break if range.endCodePoint == 0x10FFFF
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# @TODO: Distinguish between the 16- and 32-bit flavors
|
146
|
+
CategoryTable.new(arr).dump16.strip
|
147
|
+
end
|
148
|
+
|
149
|
+
def range_to_a(range)
|
150
|
+
[range.startCodePoint, range.endCodePoint, range.value]
|
151
|
+
end
|
152
|
+
|
153
|
+
def rbbi_data_for(kind, locale)
|
154
|
+
bundle = bundle_for(ulocale_class.new(locale))
|
155
|
+
brkf_name = bundle.getStringWithFallback("boundaries/#{kind}")
|
156
|
+
buffer = icu_binary.getData("#{brkiter_name}/#{brkf_name}")
|
157
|
+
rbbi_data_wrapper.get(buffer)
|
158
|
+
end
|
159
|
+
|
160
|
+
def bundle_for(locale)
|
161
|
+
@bundle ||= resource_bundle.getBundleInstance(brkiter_base_name, locale, locale_root)
|
162
|
+
end
|
163
|
+
|
164
|
+
def brkiter_name
|
165
|
+
@brkiter_name ||= icu_data.const_get(:ICU_BRKITR_NAME)
|
166
|
+
end
|
167
|
+
|
168
|
+
def brkiter_base_name
|
169
|
+
@brkiter_base_name ||= icu_data.const_get(:ICU_BRKITR_BASE_NAME)
|
170
|
+
end
|
171
|
+
|
172
|
+
def locale_root
|
173
|
+
@locale_root ||= resource_bundle.const_get(:OpenType).const_get(:LOCALE_ROOT)
|
174
|
+
end
|
175
|
+
|
176
|
+
def rbbi_data_wrapper
|
177
|
+
@rbbi_data_wrapper ||= requirements[:icu].get_class('com.ibm.icu.impl.RBBIDataWrapper')
|
178
|
+
end
|
179
|
+
|
180
|
+
def icu_binary
|
181
|
+
@icu_binary ||= requirements[:icu].get_class('com.ibm.icu.impl.ICUBinary')
|
182
|
+
end
|
183
|
+
|
184
|
+
def icu_data
|
185
|
+
@icu_data ||= requirements[:icu].get_class('com.ibm.icu.impl.ICUData')
|
186
|
+
end
|
187
|
+
|
188
|
+
def resource_bundle
|
189
|
+
@bundle_class ||= requirements[:icu].get_class('com.ibm.icu.impl.ICUResourceBundle')
|
190
|
+
end
|
191
|
+
|
192
|
+
def ulocale_class
|
193
|
+
@ulocale_class ||= requirements[:icu].get_class('com.ibm.icu.util.ULocale')
|
194
|
+
end
|
195
|
+
|
196
|
+
def output_path
|
197
|
+
params[:output_path]
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -11,7 +11,9 @@ module TwitterCldr
|
|
11
11
|
|
12
12
|
TEST_FILES = [
|
13
13
|
'ucd/auxiliary/WordBreakTest.txt',
|
14
|
-
'ucd/auxiliary/SentenceBreakTest.txt'
|
14
|
+
'ucd/auxiliary/SentenceBreakTest.txt',
|
15
|
+
'ucd/auxiliary/GraphemeBreakTest.txt',
|
16
|
+
'ucd/auxiliary/LineBreakTest.txt'
|
15
17
|
]
|
16
18
|
|
17
19
|
requirement :unicode, Versions.unicode_version, TEST_FILES
|
@@ -5,13 +5,15 @@
|
|
5
5
|
|
6
6
|
module TwitterCldr
|
7
7
|
module Segmentation
|
8
|
-
autoload :BreakIterator,
|
9
|
-
autoload :
|
10
|
-
autoload :Cursor,
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :
|
8
|
+
autoload :BreakIterator, 'twitter_cldr/segmentation/break_iterator'
|
9
|
+
autoload :CategoryTable, 'twitter_cldr/segmentation/category_table'
|
10
|
+
autoload :Cursor, 'twitter_cldr/segmentation/cursor'
|
11
|
+
autoload :Metadata, 'twitter_cldr/segmentation/metadata'
|
12
|
+
autoload :NullSuppressions, 'twitter_cldr/segmentation/null_suppressions'
|
13
|
+
autoload :RuleSet, 'twitter_cldr/segmentation/rule_set'
|
14
|
+
autoload :StateMachine, 'twitter_cldr/segmentation/state_machine'
|
15
|
+
autoload :StateTable, 'twitter_cldr/segmentation/state_table'
|
16
|
+
autoload :StatusTable, 'twitter_cldr/segmentation/status_table'
|
17
|
+
autoload :Suppressions, 'twitter_cldr/segmentation/suppressions'
|
16
18
|
end
|
17
19
|
end
|
@@ -25,29 +25,33 @@ module TwitterCldr
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def each_grapheme_cluster(str, &block)
|
28
|
-
|
29
|
-
|
28
|
+
rule_set = rule_set_for('grapheme')
|
29
|
+
each_boundary(rule_set, str, &block)
|
30
30
|
end
|
31
31
|
|
32
32
|
def each_line(str, &block)
|
33
|
-
|
34
|
-
|
33
|
+
rule_set = rule_set_for('line')
|
34
|
+
each_boundary(rule_set, str, &block)
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def each_boundary(rule_set, str)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
else
|
45
|
-
to_enum(__method__, rule_set, str)
|
40
|
+
return to_enum(__method__, rule_set, str) unless block_given?
|
41
|
+
|
42
|
+
rule_set.each_boundary(str).each_cons(2) do |start, stop|
|
43
|
+
yield str[start...stop], start, stop
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
49
47
|
def rule_set_for(boundary_type)
|
50
|
-
RuleSet.
|
48
|
+
rule_set_cache[boundary_type] ||= RuleSet.create(
|
49
|
+
locale, boundary_type, options
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def rule_set_cache
|
54
|
+
@rule_set_cache ||= {}
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2012 Twitter, Inc
|
4
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module TwitterCldr
|
9
|
+
module Segmentation
|
10
|
+
class CategoryTable
|
11
|
+
PACK_FMT_16 = 'NNn'.freeze
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def load16(data)
|
15
|
+
data = Base64.decode64(data)
|
16
|
+
|
17
|
+
new(
|
18
|
+
(0...data.size).step(10).map do |i|
|
19
|
+
data[i...(i + 10)].unpack(PACK_FMT_16)
|
20
|
+
end
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :values
|
26
|
+
|
27
|
+
def initialize(values)
|
28
|
+
@values = values
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(codepoint)
|
32
|
+
find(codepoint)[2]
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump16
|
36
|
+
data = ''.b.tap do |result|
|
37
|
+
values.each do |vals|
|
38
|
+
result << vals.pack(PACK_FMT_16)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Base64.encode64(data)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def find(codepoint)
|
48
|
+
values.bsearch do |entry|
|
49
|
+
next -1 if codepoint < entry[0]
|
50
|
+
next 1 if codepoint > entry[1]
|
51
|
+
0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|