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,282 @@
|
|
1
|
+
module UniProp
|
2
|
+
class MetaDataValidator
|
3
|
+
attr_reader :metadata
|
4
|
+
|
5
|
+
# @param [MetaData] metadata
|
6
|
+
def initialize(metadata)
|
7
|
+
@metadata = metadata
|
8
|
+
end
|
9
|
+
|
10
|
+
# メタデータが記述されているバージョンすべてで検証を実行
|
11
|
+
def validate
|
12
|
+
metadata.prop_data.versions.each do |version|
|
13
|
+
if version.has_version_metadata?
|
14
|
+
version.version_metadata.version_metadata_validator.run_all_validations
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class VersionMetaDataValidator
|
21
|
+
attr_reader :version_metadata, :version
|
22
|
+
|
23
|
+
def initialize(version_metadata)
|
24
|
+
@version_metadata = version_metadata
|
25
|
+
@version = @version_metadata.version
|
26
|
+
|
27
|
+
# validate_files_shortage, validate_files_excessでは、実際のキャッシュとメタデータを照らし合わせて検証を行う必要があるため、@versionはEfficientVersionではなくVersionでなければならない。
|
28
|
+
if @version.class != Version
|
29
|
+
raise TypeError, "The argument must be a VersionMetaData object associated with Version object (not EfficientVersion)"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# 全ての検証を実行
|
34
|
+
def run_all_validations
|
35
|
+
puts "== validation results for version #{version.version_name} =="
|
36
|
+
validate_files_shortage(reconfirm: true)
|
37
|
+
validate_files_excess(reconfirm: false)
|
38
|
+
validate_properties_shortage
|
39
|
+
validate_properties_excess
|
40
|
+
validate_row_perfection
|
41
|
+
validate_column_perfection
|
42
|
+
validate_type
|
43
|
+
|
44
|
+
if version.has_unihan?
|
45
|
+
validate_unihan_properties_shortage
|
46
|
+
validate_unihan_properties_excess
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# メタデータの記述が不足しているファイルを取得
|
51
|
+
# @return [Set<PropFile>]
|
52
|
+
def metadata_insufficient_files
|
53
|
+
return @metadata_insufficient_files if @metadata_insufficient_files
|
54
|
+
|
55
|
+
@metadata_insufficient_files = version.files.reject{_1.is_meta_file?} - version_metadata.actual_propfiles
|
56
|
+
|
57
|
+
@metadata_insufficient_files
|
58
|
+
end
|
59
|
+
|
60
|
+
# メタデータ内で記述が不足しているファイルを標準出力に出力
|
61
|
+
def validate_files_shortage(reconfirm: false)
|
62
|
+
version.files(reconfirm: reconfirm, reload: reconfirm) if reconfirm
|
63
|
+
|
64
|
+
if metadata_insufficient_files.empty?
|
65
|
+
puts "All files are described in the metadata"
|
66
|
+
else
|
67
|
+
puts "Files that are not described in the metadata"
|
68
|
+
metadata_insufficient_files.each { puts "・#{_1.basename_prefix}" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# メタデータ内に余分に記述されたファイル(実際には存在しないにも関わらず、メタデータに記述されたファイル)を標準出力に出力
|
73
|
+
def validate_files_excess(reconfirm: false)
|
74
|
+
version.files(reconfirm: reconfirm, reload: reconfirm) if reconfirm
|
75
|
+
|
76
|
+
nonexist_files = version_metadata.propfile_names.filter { !version.has_file?(_1) }
|
77
|
+
|
78
|
+
if nonexist_files.empty?
|
79
|
+
puts "There are no excessive files in the metadata."
|
80
|
+
else
|
81
|
+
puts "Files that are described in the metadata even though it does not actually exist"
|
82
|
+
nonexist_files.each { puts "・#{_1}" }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# メタデータ内で記述が不足しているプロパティを標準出力に出力
|
87
|
+
def validate_properties_shortage
|
88
|
+
metadata_insufficient_properties = version.properties - version_metadata.actual_properties
|
89
|
+
|
90
|
+
if metadata_insufficient_properties.empty?
|
91
|
+
puts "All properties are described in the metadata"
|
92
|
+
else
|
93
|
+
puts "Properties that not described in the metadata"
|
94
|
+
metadata_insufficient_properties.each { puts "・#{_1.longest_alias}" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# メタデータ内に余分に記述されたプロパティ(実際には存在しないにも関わらず、メタデータに記述されたプロパティ)を標準出力に出力
|
99
|
+
def validate_properties_excess
|
100
|
+
nonexist_props = version_metadata.property_names
|
101
|
+
.reject { _1=="" || _1=="codepoint" }
|
102
|
+
.reject { version.has_property?(_1) }
|
103
|
+
|
104
|
+
if nonexist_props.empty?
|
105
|
+
puts "There are no excessive properties in the metadata."
|
106
|
+
else
|
107
|
+
puts "Properties that's described in the metadata even though it does not actually exist"
|
108
|
+
nonexist_props.each { puts "・#{_1}" }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# information_containing_rangesのうち、block_rangesに含まれていない範囲を返す
|
113
|
+
# @param [Array<Range<Integer>>] block_ranges
|
114
|
+
# @param [Array<Range<Integer>>] information_containing_ranges
|
115
|
+
# @return [Array<Range<Integer>>]
|
116
|
+
def metadata_insufficient_ranges(block_ranges, information_containing_ranges)
|
117
|
+
result = information_containing_ranges
|
118
|
+
block_ranges.each do |block_range|
|
119
|
+
pre_result = result
|
120
|
+
result = []
|
121
|
+
pre_result.each { result.concat(UniPropUtils::RangeProcessor.cut_internal(_1, block_range.begin, block_range.end)) }
|
122
|
+
end
|
123
|
+
result
|
124
|
+
end
|
125
|
+
|
126
|
+
# 各PropFileの、メタデータに記述されていない行の範囲を取得
|
127
|
+
# @return [Hash<PropFile,Array<Range>]
|
128
|
+
def propfile_to_metadata_insufficient_ranges
|
129
|
+
return @propfile_to_metadata_insufficient_ranges if @propfile_to_metadata_insufficient_ranges
|
130
|
+
|
131
|
+
@propfile_to_metadata_insufficient_ranges = Hash.new { |hash,key| hash[key]=[] }
|
132
|
+
|
133
|
+
version_metadata.propfile_metadatas.each do |propfile_metadata|
|
134
|
+
propfile = propfile_metadata.propfile
|
135
|
+
|
136
|
+
@propfile_to_metadata_insufficient_ranges[propfile] = metadata_insufficient_ranges(propfile_metadata.property_written_ranges, propfile.information_containing_ranges)
|
137
|
+
end
|
138
|
+
|
139
|
+
@propfile_to_metadata_insufficient_ranges
|
140
|
+
end
|
141
|
+
|
142
|
+
# メタデータに記述されていない行の範囲が存在するファイルを標準出力に出力(Unihan, メタデータが記述されていないファイルを除く)
|
143
|
+
def validate_row_perfection
|
144
|
+
if propfile_to_metadata_insufficient_ranges.all? { _2.empty? }
|
145
|
+
puts "There are no files for which a file name is described in the metadata but for which this information is missing."
|
146
|
+
else
|
147
|
+
puts "Ranges where metadata is missing in propfiles"
|
148
|
+
propfile_to_metadata_insufficient_ranges.each do |propfile, insufficient_ranges|
|
149
|
+
if !insufficient_ranges.empty?
|
150
|
+
puts "・#{propfile.basename_prefix}"
|
151
|
+
|
152
|
+
insufficient_ranges.each do |range|
|
153
|
+
if range.size==1
|
154
|
+
puts "\t#{range.begin}"
|
155
|
+
else
|
156
|
+
puts "\t#{range.begin} to #{range.end}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# 実際の列数とメタデータに記述されている列数に違いがあるファイルを標準出力に出力
|
165
|
+
def validate_column_perfection
|
166
|
+
error_logs = []
|
167
|
+
version_metadata.propfile_metadatas.each do |propfile_metadata|
|
168
|
+
propfile_metadata.blocks.each_with_index do |block, block_no|
|
169
|
+
metadata_col_size = block.content.size
|
170
|
+
actual_col_size = propfile_metadata.propfile.max_column_size(block.range)
|
171
|
+
|
172
|
+
if metadata_col_size != actual_col_size
|
173
|
+
error_logs << "#{propfile_metadata.propfile.basename_prefix} (in block #{block_no})\n\tmetadata column size: #{metadata_col_size}\n\tactual column size: #{actual_col_size}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
if error_logs.empty?
|
179
|
+
puts "There are no difference in column size between the metadata and the actual description in all files"
|
180
|
+
else
|
181
|
+
puts "Files that the number of columns differs between the metadata and the actual description"
|
182
|
+
error_logs.each { puts _1 }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# validate_typeで出力するための理想の型の名称を取得
|
187
|
+
# @param [Property] prop
|
188
|
+
# @return [String]
|
189
|
+
def expected_type(prop)
|
190
|
+
type = prop.property_value_type
|
191
|
+
|
192
|
+
case type
|
193
|
+
when :string, :numeric
|
194
|
+
return type
|
195
|
+
when :binary, :catalog, :enumerated
|
196
|
+
return "#{type} (#{prop.longest_alias})"
|
197
|
+
when :miscellaneous
|
198
|
+
return prop.miscellaneous_format
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# メタデータと実際のファイルで、記述されているべき値の型に違いがある箇所を出力
|
203
|
+
MismatchPosition = Struct.new(:propfile, :column, :expected_type, :row_ranges)
|
204
|
+
def validate_type
|
205
|
+
# 違いがある箇所を検出
|
206
|
+
mismatches = []
|
207
|
+
|
208
|
+
version_metadata.propfile_metadatas.each do |propfile_metadata|
|
209
|
+
propfile = propfile_metadata.propfile
|
210
|
+
|
211
|
+
propfile_metadata.blocks.each do |block|
|
212
|
+
block.content.each_with_index do |prop, col|
|
213
|
+
# 列の値がArrayを使用して記述されている場合、検証をスキップする
|
214
|
+
next if !prop || prop.class==Array
|
215
|
+
|
216
|
+
mismatch_row_ranges = UniPropUtils::RangeProcessor.sub(
|
217
|
+
block.range,
|
218
|
+
propfile.verbose_property_value_type_match_ranges(col, prop)
|
219
|
+
)
|
220
|
+
|
221
|
+
if !mismatch_row_ranges.empty?
|
222
|
+
mismatches << MismatchPosition.new(propfile, col, expected_type(prop), mismatch_row_ranges)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# 検出結果を出力
|
229
|
+
if mismatches.empty?
|
230
|
+
puts "In all blocks in the metadata, the type of the property described in the block matches the type of the values in the actual file."
|
231
|
+
else
|
232
|
+
mismatches.each do |mismatch|
|
233
|
+
puts "According to the metadata, column #{mismatch.column} in #{mismatch.propfile.basename_prefix} should be #{mismatch.expected_type} value, but the following line is wrong."
|
234
|
+
|
235
|
+
mismatch.row_ranges.each do |range|
|
236
|
+
if range.size==1
|
237
|
+
puts "\t#{range.begin}"
|
238
|
+
else
|
239
|
+
puts "\t#{range.begin} to #{range.end}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# メタデータに記述が不足しているUnihanプロパティを出力
|
247
|
+
def validate_unihan_properties_shortage
|
248
|
+
metadata_insufficient_properties = []
|
249
|
+
|
250
|
+
version.unihanprop.unihan_properties.each do |prop|
|
251
|
+
if version_metadata.unihan_property_names.all? { !prop.has_alias?(_1) }
|
252
|
+
metadata_insufficient_properties << prop
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
if metadata_insufficient_properties.empty?
|
257
|
+
puts "All Unihan properties are described in the metadata"
|
258
|
+
else
|
259
|
+
puts "Unihan properties that's not described in the metadata"
|
260
|
+
metadata_insufficient_properties.each { puts "・#{_1.longest_alias}" }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# メタデータ内に余分に記述されたUnihanプロパティ(実際には存在しないにも関わらず、メタデータに記述されたUnihanプロパティ)を出力
|
265
|
+
def validate_unihan_properties_excess
|
266
|
+
nonexist_prop_names = []
|
267
|
+
|
268
|
+
version_metadata.unihan_property_names.each do |prop_name|
|
269
|
+
if version.unihanprop.unihan_properties.all? { !_1.has_alias?(prop_name) }
|
270
|
+
nonexist_prop_names << prop_name
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
if nonexist_prop_names.empty?
|
275
|
+
puts "There are no excessive Unihan properties in the metadata."
|
276
|
+
else
|
277
|
+
puts "Unihan properties that's described in the metadata even though it does not actually exist"
|
278
|
+
nonexist_prop_names.each { puts "・#{_1}" }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,293 @@
|
|
1
|
+
module UniProp
|
2
|
+
class PropData
|
3
|
+
attr_reader :excluded_extensions, :excluded_directories, :excluded_files, :metadata_path
|
4
|
+
attr_accessor :cache_path, :settings
|
5
|
+
|
6
|
+
# @note VersionMetaDataRecreator#output_metadata_revising_hintsなど、2つ以上のメタデータを使用して処理を行う場合がある。そのような場合に対応するため、PropDataは1つのsettings.rbと1つのメタデータを使用し、Unicodeのファイル全体を扱うためのクラスとした。
|
7
|
+
def initialize(settings_path, metadata_path=nil)
|
8
|
+
@settings = Settings.new(settings_path)
|
9
|
+
cache_path_str = ENV["UniPropCache"] || @settings.cache_path
|
10
|
+
@cache_path = Pathname.new(cache_path_str).cleanpath.expand_path
|
11
|
+
@metadata_path = metadata_path
|
12
|
+
end
|
13
|
+
|
14
|
+
# unicode.orgから存在するバージョンの一覧を取得し、それを元にVersionオブジェクトを作成する
|
15
|
+
# @note メタデータが紐づけられていればその情報を使用し、紐づけられていなければUnicode.orgから情報を取得
|
16
|
+
# @param [Boolean] update trueの場合バージョン一覧を再取得
|
17
|
+
# @return [Set<Version>]
|
18
|
+
def versions(update: false)
|
19
|
+
return @versions if @versions && !update
|
20
|
+
|
21
|
+
@versions = Set.new
|
22
|
+
|
23
|
+
if has_metadata?
|
24
|
+
metadata.version_names(update_metadata: true, confirm: update).each { @versions << Version.new(self, _1) }
|
25
|
+
else
|
26
|
+
UniPropUtils::DownloaderWrapper.get_version_names.each { @versions << Version.new(self, _1) }
|
27
|
+
end
|
28
|
+
|
29
|
+
@versions
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [EfficientVersion]
|
33
|
+
def find_efficient_version(version_name)
|
34
|
+
weight = Version.name_to_weight(version_name)
|
35
|
+
@weight_to_efficient_version ||= {}
|
36
|
+
return @weight_to_efficient_version[weight] if @weight_to_efficient_version[weight]
|
37
|
+
|
38
|
+
if metadata.version_names.map { Version.name_to_weight(_1) }.include?(weight)
|
39
|
+
@weight_to_efficient_version[weight] = EfficientVersion.new(self, version_name)
|
40
|
+
else
|
41
|
+
raise VersionNotMatchedError, "version #{version_name} is not exists"
|
42
|
+
end
|
43
|
+
|
44
|
+
@weight_to_efficient_version[weight]
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param [String] version_name
|
48
|
+
# @param [Boolean] reconfirm trueの場合、version_nameに対応するバージョンが見つからない時にバージョン一覧を取得する
|
49
|
+
# @return [Version]
|
50
|
+
def find_version(version_name, reconfirm: true)
|
51
|
+
parsed_version_name = Version.parse(version_name)
|
52
|
+
|
53
|
+
versions.each do |version|
|
54
|
+
if version.major == parsed_version_name[:major] && version.minor == parsed_version_name[:minor] && version.tiny == parsed_version_name[:tiny]
|
55
|
+
return version
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# 一致するバージョンが見つからなかった場合
|
60
|
+
if reconfirm
|
61
|
+
versions(update: true) # バージョン一覧を更新
|
62
|
+
find_version(version_name, reconfirm: false)
|
63
|
+
else
|
64
|
+
raise VersionNotMatchedError
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# vesionsのうち、最も古いバージョンを取得
|
69
|
+
# @return [Version]
|
70
|
+
def oldest_version
|
71
|
+
versions.sort_by { _1.weight } .first
|
72
|
+
end
|
73
|
+
|
74
|
+
# versionsのうち、最も新しいバージョンを取得
|
75
|
+
# @return [Version]
|
76
|
+
def latest_version
|
77
|
+
versions.sort_by { _1.weight } .last
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Metadata]
|
81
|
+
# @raise [MetaDataNotFoundError] PropDataのinitialize時にmetadata_pathを指定していない場合に発生
|
82
|
+
def metadata
|
83
|
+
return @metadata if @metadata
|
84
|
+
|
85
|
+
if metadata_path
|
86
|
+
@metadata = MetaData.new(self, metadata_path)
|
87
|
+
return @metadata
|
88
|
+
else
|
89
|
+
raise(MetaDataNotFoundError, "This PropData object doesn't have metadata path.")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [EfficientMetadata]
|
94
|
+
# @raise [MetaDataNotFoundError] PropDataのinitialize時にmetadata_pathを指定していない場合に発生
|
95
|
+
def efficient_metadata
|
96
|
+
return @efficient_metadata if @efficient_metadata
|
97
|
+
|
98
|
+
if metadata_path
|
99
|
+
@efficient_metadata = EfficientMetaData.new(self, metadata_path)
|
100
|
+
return @efficient_metadata
|
101
|
+
else
|
102
|
+
raise(MetaDataNotFoundError, "This PropData object doesn't have metadata path.")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# PropDataがメタデータに紐づけられているかを判定
|
107
|
+
def has_metadata?
|
108
|
+
!!metadata rescue false
|
109
|
+
end
|
110
|
+
|
111
|
+
# version1とversion2の間で、ファイル名(basename_prefix)が同じPropFileのハッシュを作成
|
112
|
+
# @param [Version] version1 キーとされるバージョン
|
113
|
+
# @param [Version] version2 値とされるバージョン
|
114
|
+
# @return [Hash<PropFile, PropFile>]
|
115
|
+
def file_correspondence(version1, version2)
|
116
|
+
return @file_correspondences[version1][version2] if @file_correspondences&&@file_correspondences[version1]&&@file_correspondences[version1][version2]
|
117
|
+
|
118
|
+
propfile_to_same_name_propfile = {}
|
119
|
+
version1.files.each do |f1|
|
120
|
+
version2.files.each do |f2|
|
121
|
+
if Alias.canonical(f1.basename_prefix)==Alias.canonical(f2.basename_prefix)
|
122
|
+
propfile_to_same_name_propfile[f1] = f2
|
123
|
+
break # 1つのバージョン内にbasename_prefixが同じファイルは2つ以上無いので、1つ見つかった段階でbreakする
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@file_correspondences ||= {}
|
129
|
+
@file_correspondences[version1] ||= {}
|
130
|
+
@file_correspondences[version1][version2] = propfile_to_same_name_propfile
|
131
|
+
|
132
|
+
@file_correspondences[version1][version2]
|
133
|
+
end
|
134
|
+
|
135
|
+
# metadata_pathのファイルをnew_metadataの内容に上書き
|
136
|
+
# @param [Array/Hash] new_metadata JSONとして解釈できるオブジェクト
|
137
|
+
# @raise [MetaDataNotFoundError] PropDataがメタデータに関連付けられていない場合に発生
|
138
|
+
def update_metadata(new_metadata)
|
139
|
+
if metadata_path && metadata_path.exist?
|
140
|
+
metadata_path.write(JSON.pretty_generate(new_metadata))
|
141
|
+
else
|
142
|
+
raise MetaDataNotFoundError
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [UnicodeManager]
|
147
|
+
def unicode_manager
|
148
|
+
@unicode_manager ||= UnicodeManager.new(self)
|
149
|
+
end
|
150
|
+
|
151
|
+
# @param [String] version_name
|
152
|
+
# @return [VersionManager]
|
153
|
+
def version_manager(version_name)
|
154
|
+
vm = version_managers.find { _1.version.weight==Version.name_to_weight(version_name) }
|
155
|
+
|
156
|
+
vm || raise(MetaDataNotFoundError, "MetaData for #{version_name} is not found.")
|
157
|
+
end
|
158
|
+
|
159
|
+
# メタデータに含まれる全バージョンのVersionManagerを作成
|
160
|
+
# @return [Array<VersionManager>]
|
161
|
+
def version_managers
|
162
|
+
return @version_managers if @version_managers
|
163
|
+
|
164
|
+
@version_managers = metadata.version_names
|
165
|
+
.filter { metadata.has_raw_version_metadata?(_1) }
|
166
|
+
.map { find_efficient_version(_1) }
|
167
|
+
.map { VersionManager.new(_1) }
|
168
|
+
|
169
|
+
@version_managers
|
170
|
+
end
|
171
|
+
|
172
|
+
# @param [Pathname] path
|
173
|
+
# @note pathが指定されていない場合、メタデータの先頭にproperty_をつけたファイルを使用
|
174
|
+
# @return [PropertyMetadata]
|
175
|
+
# @raise [MetaDataNotFoundError] pathが指定されているがそのpathが存在しない場合に発生
|
176
|
+
def property_metadata(path=nil)
|
177
|
+
return @property_metadata if @property_metadata
|
178
|
+
|
179
|
+
select_path = !!path
|
180
|
+
path ||= metadata_path.parent / ("property_"+metadata_path.basename.to_s)
|
181
|
+
|
182
|
+
if !path.exist?
|
183
|
+
if select_path
|
184
|
+
raise MetaDataNotFoundError, "#{path} is not found."
|
185
|
+
else
|
186
|
+
path.write([])
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
@property_metadata = PropertyMetaData.new(self, path)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# 設定ファイルから値を取得するためのクラス
|
195
|
+
class Settings
|
196
|
+
attr_reader :setting_names
|
197
|
+
|
198
|
+
# @param [Pathname] path 設定ファイルの絶対パス
|
199
|
+
def initialize(path)
|
200
|
+
require path
|
201
|
+
@setting_names = {
|
202
|
+
downloader_settings: DOWNLOADER_SETTINGS,
|
203
|
+
files_information: FILES_INFORMATION,
|
204
|
+
properties_information: PROPERTIES_INFORMATION
|
205
|
+
}
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param [Symbol] setting_name 検索する設定項目名
|
209
|
+
# @param [String] version 検索するバージョン名
|
210
|
+
# @note version==nilの場合、デフォルト値を取得
|
211
|
+
# @param [keys] 検索を行う経路
|
212
|
+
def search(setting_name, version, *keys)
|
213
|
+
if version
|
214
|
+
result = setting_names.dig(setting_name, version.to_sym, *keys)
|
215
|
+
return result if result
|
216
|
+
end
|
217
|
+
setting_names.dig(setting_name, :default, *keys)
|
218
|
+
end
|
219
|
+
|
220
|
+
# @param [String] version
|
221
|
+
# @return [Pathname]
|
222
|
+
def cache_path(version=nil)
|
223
|
+
search(:downloader_settings, version, :cache_path)
|
224
|
+
end
|
225
|
+
|
226
|
+
# @param [String] version
|
227
|
+
# @return [Array<String>]
|
228
|
+
def excluded_extensions(version=nil)
|
229
|
+
search(:downloader_settings, version, :excluded_extensions)
|
230
|
+
end
|
231
|
+
|
232
|
+
# @param [String] version
|
233
|
+
# @return [Array<String>]
|
234
|
+
def excluded_directories(version=nil)
|
235
|
+
search(:downloader_settings, version, :excluded_directories)
|
236
|
+
end
|
237
|
+
|
238
|
+
# @param [String] version
|
239
|
+
# @return [Array<String>]
|
240
|
+
def excluded_files(version=nil)
|
241
|
+
search(:downloader_settings, version, :excluded_files)
|
242
|
+
end
|
243
|
+
|
244
|
+
# @param [String] version
|
245
|
+
# @return [Array<String>]
|
246
|
+
def included_files(version=nil)
|
247
|
+
search(:downloader_settings, version, :included_files)
|
248
|
+
end
|
249
|
+
|
250
|
+
# @param [String] version
|
251
|
+
# @return [Boolean]
|
252
|
+
def unicode_beta(version=nil)
|
253
|
+
search(:downloader_settings, version, :unicode_beta)
|
254
|
+
end
|
255
|
+
|
256
|
+
# @param [String] version
|
257
|
+
# @param [String] file
|
258
|
+
# @return [Hash<Symbol,String>]
|
259
|
+
def file_format(version, file)
|
260
|
+
# 優先順位
|
261
|
+
# (1) version, fileが両方一致する結果にマッチ
|
262
|
+
result = search(:files_information, version, :file_formats).find { _1[:file_name]==file }
|
263
|
+
|
264
|
+
# (2) defaultの中でfileが一致する結果にマッチ
|
265
|
+
result ||= search(:files_information, nil, :file_formats).find { _1[:file_name]==file }
|
266
|
+
|
267
|
+
# (3) default_file_formatを取得
|
268
|
+
result ||= search(:files_information, nil, :default_file_format)
|
269
|
+
result
|
270
|
+
end
|
271
|
+
|
272
|
+
# @param [String] version
|
273
|
+
# @return [Hash<Symbol,String>]
|
274
|
+
def unihan_file_format(version=nil)
|
275
|
+
search(:files_information, version, :unihan_file_format)
|
276
|
+
end
|
277
|
+
|
278
|
+
# @param [String] version
|
279
|
+
# @param [String] property
|
280
|
+
# @return [Hash<Symbol,Object>?]
|
281
|
+
def miscellaneous_format(version, property)
|
282
|
+
# 優先順位
|
283
|
+
# (1) version, propertyが両方マッチ
|
284
|
+
result = search(:properties_information, version, :miscellaneous_formats).find { _1[:property_name]==property }
|
285
|
+
|
286
|
+
# (2) defaultのうち、propertyがマッチ
|
287
|
+
result ||= search(:properties_information, nil, :miscellaneous_formats).find { _1[:property_name]==property }
|
288
|
+
|
289
|
+
# (2)までにマッチする値が存在しない場合、nilをそのまま返す
|
290
|
+
result
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|