uniprop 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +31 -0
- data/README.md +29 -0
- data/Rakefile +12 -0
- data/lib/resources/metadata.json +19899 -0
- data/lib/resources/settings.rb +120 -0
- data/lib/uniprop/consts.rb +31 -0
- data/lib/uniprop/downloader.rb +262 -0
- data/lib/uniprop/dsl.rb +53 -0
- data/lib/uniprop/efficient_elements.rb +40 -0
- data/lib/uniprop/errors.rb +31 -0
- data/lib/uniprop/inspects.rb +122 -0
- data/lib/uniprop/metadata_generator.rb +403 -0
- data/lib/uniprop/metadata_processor.rb +673 -0
- data/lib/uniprop/metadata_validator.rb +282 -0
- data/lib/uniprop/propdata.rb +293 -0
- data/lib/uniprop/unicode_elements.rb +998 -0
- data/lib/uniprop/unicode_manager.rb +277 -0
- data/lib/uniprop/unihanprop.rb +91 -0
- data/lib/uniprop/uniinteger.rb +16 -0
- data/lib/uniprop/unistring.rb +34 -0
- data/lib/uniprop/utils.rb +542 -0
- data/lib/uniprop/value_group.rb +276 -0
- data/lib/uniprop/version.rb +5 -0
- data/lib/uniprop.rb +29 -0
- data/sig/uniprop.rbs +4 -0
- data/uniprop.gemspec +39 -0
- metadata +75 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
module UniProp
|
2
|
+
class UnicodeManager
|
3
|
+
attr_reader :prop_data
|
4
|
+
|
5
|
+
def initialize(prop_data)
|
6
|
+
@prop_data = prop_data
|
7
|
+
end
|
8
|
+
|
9
|
+
# @param [String] version バージョン名
|
10
|
+
# @return [VersionManager]
|
11
|
+
def version_manager(version)
|
12
|
+
prop_data.version_manager(version)
|
13
|
+
end
|
14
|
+
|
15
|
+
# version_nameのメタデータを検証
|
16
|
+
# @param [String] version_name
|
17
|
+
def validate_metadata(version_name)
|
18
|
+
prop_data.find_version(version_name).version_metadata.version_metadata_validator.run_all_validations
|
19
|
+
end
|
20
|
+
|
21
|
+
# initialize時に指定したメタデータを使用し、メタデータを作成
|
22
|
+
# @param [Pathname] file_path メタデータを生成するパス
|
23
|
+
# @param [String] using_version_name 生成に使用するバージョン名
|
24
|
+
# @param [String] generated_version_name 生成するバージョン名
|
25
|
+
def generate_metadata(file_path, using_version_name, generated_version_name)
|
26
|
+
prop_data.generate_metadata(
|
27
|
+
file_path,
|
28
|
+
prop_data.find_efficient_version(using_version_name),
|
29
|
+
prop_data.find_version(generated_version_name)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
# メタデータに含まれる全バージョンの全プロパティ名を取得
|
34
|
+
# @return [Array<String>]
|
35
|
+
def properties
|
36
|
+
@properties ||= prop_data.version_managers
|
37
|
+
.map { _1.properties }
|
38
|
+
.reduce([], :|)
|
39
|
+
end
|
40
|
+
|
41
|
+
# codepointでpropertyのプロパティ値としてvalueが定義されているバージョン名をすべて取得
|
42
|
+
# @param [String] property プロパティ名
|
43
|
+
# @param [String] char 検索する1文字
|
44
|
+
# @param [String] value プロパティ値
|
45
|
+
def versions_of(property, char, value)
|
46
|
+
warn "Versions prior to 4.0-Update are not included in the results because the metadata does not exist."
|
47
|
+
prop_data.version_managers
|
48
|
+
.filter { _1.has_value?(property, char.ord, value)}
|
49
|
+
.map { _1.version.version_name }
|
50
|
+
end
|
51
|
+
|
52
|
+
# text_changed_codepointsの処理に加え、エイリアスの判定を実行し、値が変更されたコードポイントを取得
|
53
|
+
# @param [String] property
|
54
|
+
# @param [String] version1
|
55
|
+
# @param [String] version2
|
56
|
+
# @return [Array<Integer>]
|
57
|
+
def value_changed_codepoints(property, version1, version2)
|
58
|
+
pm1 = version_manager(version1).property_manager(property)
|
59
|
+
pm2 = version_manager(version2).property_manager(property)
|
60
|
+
vm2 = version_manager(version2)
|
61
|
+
|
62
|
+
# 文字列は変更されているが、別エイリアスに表記が変更されただけのコードポイントを判別
|
63
|
+
# 例: "Y"のエイリアスとして"Yes", "T", "True"、"N"のエイリアスとして"No", "F", "False"が存在する時、
|
64
|
+
# ["Y", "N"] -> ["False", "True"]が表記の変更だけで、値は変わっていないことを検出する手順
|
65
|
+
# ["Y", "N"]の各値のエイリアスを求め、["Yes", "T", "True", "N", "No", "F", "False"]の配列を生成
|
66
|
+
# ["False", "True"]から["Yes", "T", "True", "N", "No", "F", "False"]を引き、結果がemptyであれば値の変更は無いと判別
|
67
|
+
result = []
|
68
|
+
text_changed_codepoints(property, version1, version2).each do |cp|
|
69
|
+
values1 = pm1.values_of(cp)
|
70
|
+
values2 = pm2.values_of(cp)
|
71
|
+
|
72
|
+
values1 = values1.class==Array ? values1 : [values1]
|
73
|
+
values2 = values2.class==Array ? values2 : [values2]
|
74
|
+
|
75
|
+
values1_aliases = values1.map { vm2.value_aliases(property, _1) }
|
76
|
+
.flatten
|
77
|
+
|
78
|
+
result << cp if !(values2-values1_aliases).empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
result
|
82
|
+
end
|
83
|
+
|
84
|
+
# version1で値が定義済みのコードポイントのうち、version2では他の値が定義されているものを取得
|
85
|
+
# version2の方が新しい場合、version1から変更された値のみが取得される。version1の方が新しい場合、version2で追加された値も取得される。
|
86
|
+
# @note 単にデータファイルの文字が異なるコードポイントを取得するだけで、エイリアスの判定は行わない(例: Ageプロパティのプロパティ値5.0はエイリアスとしてV5_0を持つが、5.0とV5_0は別の値とみなす)
|
87
|
+
# @param [String] property
|
88
|
+
# @param [String] version1
|
89
|
+
# @param [String] version2
|
90
|
+
# @return [Array<Integer>]
|
91
|
+
def text_changed_codepoints(property, version1, version2)
|
92
|
+
pvg1 = version_manager(version1).property_manager(property).property_value_group
|
93
|
+
pvg2 = version_manager(version2).property_manager(property).property_value_group
|
94
|
+
|
95
|
+
result = []
|
96
|
+
# Blockプロパティのように、多くのコードポイントに同じ値が定義されるプロパティが存在
|
97
|
+
# そのため、すべてのコードポイントの値を比較するのではなく、一度値ごとのコードポイントをまとめた方が効率的
|
98
|
+
pvg1.values_to_codepoints.each do |values, cps1|
|
99
|
+
cps2 = pvg2.values_to_codepoints[values].to_a
|
100
|
+
diff_cps = cps1 - cps2
|
101
|
+
result << diff_cps if !diff_cps.empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
result.flatten
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class VersionManager
|
109
|
+
attr_reader :version
|
110
|
+
|
111
|
+
# versionに含まれる情報を取得するためのオブジェクトを作成
|
112
|
+
# @param [EfficientVersion] version
|
113
|
+
def initialize(version)
|
114
|
+
@version = version
|
115
|
+
end
|
116
|
+
|
117
|
+
# PropertyManagerオブジェクトを作成
|
118
|
+
# @param [String] property_name
|
119
|
+
# @return [PropertyManager]
|
120
|
+
def property_manager(property_name)
|
121
|
+
@property_managers ||= []
|
122
|
+
pm = @property_managers.find { _1.property.has_alias?(property_name) }
|
123
|
+
return pm if pm
|
124
|
+
|
125
|
+
pm = PropertyManager.new(version.find_property(property_name))
|
126
|
+
@property_managers << pm
|
127
|
+
pm
|
128
|
+
end
|
129
|
+
|
130
|
+
# propertyプロパティのcodepointのプロパティ値を取得
|
131
|
+
# @param [String] property 検索するプロパティ名
|
132
|
+
# @param [String] 1文字の文字列
|
133
|
+
# @return [String/Array<String>] プロパティ値が1つの場合String、2つ以上の場合Array<String>
|
134
|
+
def values_of(property, char)
|
135
|
+
property_manager(property).values_of(char.ord)
|
136
|
+
end
|
137
|
+
|
138
|
+
# propertyプロパティが値としてvalueを持つコードポイントを取得
|
139
|
+
# @param [String] property プロパティ名
|
140
|
+
# @param [String] value プロパティ値
|
141
|
+
# @return [Array<Integer>]
|
142
|
+
def codepoints_of(property, value)
|
143
|
+
property_manager(property).property_value_group.value_including_codepoints(value)
|
144
|
+
end
|
145
|
+
|
146
|
+
# propertyがcodepointでプロパティ値としてvalueを持つか判定
|
147
|
+
# @param [String] property プロパティ名
|
148
|
+
# @param [Integer] codepoint
|
149
|
+
# @param [String] value プロパティ値
|
150
|
+
def has_value?(property, codepoint, value)
|
151
|
+
codepoints_of(property, value).include?(codepoint)
|
152
|
+
end
|
153
|
+
|
154
|
+
# codepointでvalueを取るプロパティを取得
|
155
|
+
# @param [String] char 1文字の文字列
|
156
|
+
# @param [String] value プロパティ値
|
157
|
+
# @return [Array<String>] プロパティ名
|
158
|
+
def properties_of(char, value)
|
159
|
+
properties.filter { has_value?(_1, char.ord, value) }
|
160
|
+
end
|
161
|
+
|
162
|
+
# バージョン内の全プロパティ名を取得
|
163
|
+
# @return [Array<String>]
|
164
|
+
def properties
|
165
|
+
# VersionMetaData#property_namesにはUniHanのプロパティが含まれないため、EffcientVersion#propertiesから取得
|
166
|
+
@properties ||= version.properties.map { _1.longest_alias }
|
167
|
+
end
|
168
|
+
|
169
|
+
# propertyをエイリアスに持つプロパティがバージョン内に存在するか確認
|
170
|
+
# @param [String] property
|
171
|
+
def has_property?(property)
|
172
|
+
version.has_property?(property)
|
173
|
+
end
|
174
|
+
|
175
|
+
# propertyにデフォルト値以外の値が割り当てられているコードポイントを取得
|
176
|
+
# @param [String] property
|
177
|
+
# @return [Array<Integer>]
|
178
|
+
def assigned_codepoints(property)
|
179
|
+
property_manager(property).property_value_group.codepoints
|
180
|
+
end
|
181
|
+
|
182
|
+
# propertyのプロパティ値の中のvalueのエイリアスを全て取得
|
183
|
+
# @note propertyが値としてvalueを持たない場合や、プロパティが列挙型でない場合、空の配列が帰る
|
184
|
+
# @param [String] property プロパティ名
|
185
|
+
# @param [String] value プロパティ値
|
186
|
+
# @return [Array<String>]
|
187
|
+
def value_aliases(property, value)
|
188
|
+
return [] if !version.has_property?(property)
|
189
|
+
prop = version.find_property(property)
|
190
|
+
|
191
|
+
if prop.has_property_value?(value)
|
192
|
+
prop.find_property_value(value).uncanonicaled_aliases
|
193
|
+
else
|
194
|
+
[]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class PropertyManager
|
200
|
+
attr_reader :property, :version_metadata, :property_value_group, :version
|
201
|
+
|
202
|
+
# propertyに関する情報を取得するためのオブジェクトを作成
|
203
|
+
# @note VersionまたはEfficientVersionはpropertyのProperty#versionが使用されるため、Version/EfficientVersionの使用したい方でPropertyオブジェクトを生成しpropertyとして使用する
|
204
|
+
# @param [Property] property
|
205
|
+
def initialize(property)
|
206
|
+
@property = property
|
207
|
+
@version = @property.version
|
208
|
+
@version_metadata = @version.version_metadata
|
209
|
+
@property_value_group = @version.prop_data.property_metadata.find_version_property_metadata(@version).find_property_data(@property).property_value_group
|
210
|
+
end
|
211
|
+
|
212
|
+
# @return [Set<String>]
|
213
|
+
def values_of(codepoint)
|
214
|
+
value = property_value_group.values_of(codepoint)
|
215
|
+
|
216
|
+
if !value || value.empty?
|
217
|
+
# 値が存在しない(nil)場合や、値が記述されていない(空文字列)の場合、missingを使用
|
218
|
+
missing_value(codepoint)
|
219
|
+
else
|
220
|
+
value
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# codepointのmissingを取得
|
225
|
+
# @param [Integer/String] codepoint
|
226
|
+
# @return [String]
|
227
|
+
def missing_value(codepoint)
|
228
|
+
if codepoint.class==String
|
229
|
+
codepoint = UniPropUtils::CodepointConverter.str_to_int(codepoint)
|
230
|
+
end
|
231
|
+
|
232
|
+
raw_missing_val = raw_missing_value(codepoint)
|
233
|
+
|
234
|
+
case raw_missing_val
|
235
|
+
when "<codepoint>" then codepoint.to_s(16).upcase
|
236
|
+
when "<script>" then
|
237
|
+
if @script || version.has_property?("Script")
|
238
|
+
@script ||= PropertyManager.new(version.find_property("Script"))
|
239
|
+
return @script.missing_value(codepoint)
|
240
|
+
else
|
241
|
+
return raw_missing_val
|
242
|
+
end
|
243
|
+
else raw_missing_val
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# codepointのmissingを取得。<codepoint>などの特殊な値もそのまま返される
|
248
|
+
# @param [Integer/String] codepoint
|
249
|
+
# @return [String]
|
250
|
+
def raw_missing_value(codepoint)
|
251
|
+
if codepoint.class==String
|
252
|
+
codepoint = UniPropUtils::CodepointConverter.str_to_int(codepoint)
|
253
|
+
end
|
254
|
+
|
255
|
+
if version_metadata.property_missing_defs(property)
|
256
|
+
version_metadata.property_missing_defs(property).reverse_each do |missing_def|
|
257
|
+
if missing_def[:codepoint_range].include?(codepoint)
|
258
|
+
return missing_def[:missing_value]
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
nil
|
263
|
+
end
|
264
|
+
|
265
|
+
# value1とvalue2が同じプロパティ値を表すエイリアスであるかを判定
|
266
|
+
# @param [String] value1
|
267
|
+
# @param [String] value2
|
268
|
+
def same_value?(value1, value2)
|
269
|
+
# Propertyがproperty_valuesを1つ以上持つとき、そのプロパティの値はPropertyValueAliasesに記述されており、エイリアスが存在する可能性がある
|
270
|
+
if property.property_values.size >= 1 && property.has_property_value?(value1) && property.has_property_value?(value2)
|
271
|
+
property.find_property_value(value1) == property.find_property_value(value2)
|
272
|
+
else
|
273
|
+
value1 == value2
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module UniProp
|
2
|
+
class UnihanProp
|
3
|
+
attr_reader :unihan_files, :version
|
4
|
+
|
5
|
+
# @param [Set<PropFile>] unihan_files UnihanのPropFileオブジェクト
|
6
|
+
def initialize(unihan_files)
|
7
|
+
@unihan_files = unihan_files
|
8
|
+
|
9
|
+
versions = @unihan_files.map { _1.version }.uniq
|
10
|
+
if versions.size <= 1
|
11
|
+
@version = versions[0]
|
12
|
+
else
|
13
|
+
raise VersionDifferentError, "All versions of files in unihan_files should be the same."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# unihan_filesに含まれるすべてのPropFileのshaped_linesを連結したオブジェクトを取得
|
18
|
+
# @return [Array<Array<String>>]
|
19
|
+
def shaped_lines
|
20
|
+
@shaped_lines ||= unihan_files.map { _1.shaped_lines }
|
21
|
+
.reject { _1.empty? || !_1 }
|
22
|
+
.reduce([], :+)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Unihanに含まれるプロパティ名を取得
|
26
|
+
# @note Unihanのファイルは必ず2列目にプロパティ名が記述されている
|
27
|
+
# @return [Set<String>]
|
28
|
+
def property_names
|
29
|
+
@property_names ||= shaped_lines.map { _1[1] }
|
30
|
+
.reject { !_1 }
|
31
|
+
.to_set
|
32
|
+
end
|
33
|
+
|
34
|
+
# Unihanに含まれるプロパティを取得
|
35
|
+
# @return [Set<Property>]
|
36
|
+
def unihan_properties
|
37
|
+
return @unihan_properties if @unihan_properties
|
38
|
+
|
39
|
+
@unihan_properties = Set.new
|
40
|
+
return if !version
|
41
|
+
|
42
|
+
property_names.each do |property_name|
|
43
|
+
if version.has_property?(property_name)
|
44
|
+
# Unihanのプロパティの一部はPropertyAliases.txtにも記述されている
|
45
|
+
# PropertyAliasesの方がプロパティのエイリアスなど、掲載されている情報が多いため、PropertyAliasesの記述を優先して使用
|
46
|
+
@unihan_properties << version.find_property(property_name)
|
47
|
+
else
|
48
|
+
@unihan_properties << UniProp::Property.new(version, property_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@unihan_properties
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Hash<String,Array<String>>]
|
56
|
+
def property_name_to_shaped_lines
|
57
|
+
return @property_nameto_shaped_lines if @property_name_to_shaped_lines
|
58
|
+
@property_name_to_shaped_lines = shaped_lines.group_by { _1[1] }
|
59
|
+
@property_name_to_shaped_lines.delete(nil)
|
60
|
+
@property_name_to_shaped_lines
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Hash<Property,Array<String>>]
|
64
|
+
def property_to_shaped_lines
|
65
|
+
return @property_to_shaped_lines if @property_to_shaped_lines
|
66
|
+
|
67
|
+
@property_to_shaped_lines = Hash.new
|
68
|
+
|
69
|
+
property_name_to_shaped_lines.each do |property_name, lines|
|
70
|
+
if version.has_unihan_property?(property_name)
|
71
|
+
prop = version.find_unihan_property(property_name)
|
72
|
+
@property_to_shaped_lines[prop] = lines
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@property_to_shaped_lines
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [UnihanValueGroup]
|
80
|
+
def unihan_value_group(property)
|
81
|
+
return @property_to_unihan_value_group[property] if @property_to_unihan_value_group && @property_to_unihan_value_group[property]
|
82
|
+
|
83
|
+
@property_to_unihan_value_group ||= {}
|
84
|
+
|
85
|
+
unihan_value_group = UnihanValueGroup.new(property, property_to_shaped_lines[property])
|
86
|
+
|
87
|
+
@property_to_unihan_value_group[property] = unihan_value_group
|
88
|
+
@property_to_unihan_value_group[property]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module UniInteger
|
2
|
+
refine Integer do
|
3
|
+
# selfをU+xxxx形式の文字列に変換
|
4
|
+
def to_cp
|
5
|
+
"U+%04X" % self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
refine Range do
|
10
|
+
def to_cp
|
11
|
+
if first.class==Integer && last.class==Integer
|
12
|
+
"#{"U+%04X" % first}..#{"%04X" % last}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module UniString
|
2
|
+
class PropSearch
|
3
|
+
attr_reader :codepoint
|
4
|
+
|
5
|
+
# @param [Integer] codepoint
|
6
|
+
def initialize(codepoint)
|
7
|
+
@codepoint = codepoint
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method, *args, &block)
|
11
|
+
property = method.to_s
|
12
|
+
version = args[0] || latest_version
|
13
|
+
UniProp::version(version).values_of(property, codepoint)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
refine String do
|
18
|
+
# @param [String] version
|
19
|
+
# @param [String] property
|
20
|
+
def prop_value(version, property)
|
21
|
+
UniProp::version(version).values_of(property, ord)
|
22
|
+
end
|
23
|
+
|
24
|
+
def prop
|
25
|
+
if size == 1
|
26
|
+
@prop_search ||= PropSearch.new(ord)
|
27
|
+
else
|
28
|
+
raise(SizeError, "The size of String must be 1.")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class SizeError < StandardError; end
|
34
|
+
end
|