Module: QueryStream::DataResolver
- Defined in:
- lib/query_stream/data_resolver.rb
Overview
データファイル探索・読み込みモジュール
Constant Summary collapse
- EXTENSIONS =
サポートする拡張子(優先順位順)
%w[.yml .yaml .json].freeze
- YAML_PERMITTED_CLASSES =
YAML.safe_load_file で許可するクラス Symbol: symbolize_names: true のために必要 Time/Date/DateTime: 日付/時刻を含む実用データに対応
[Symbol, Time, Date, DateTime].freeze
Class Method Summary collapse
-
.find_with_extensions(base_name, data_dir) ⇒ String?
指定名ですべての拡張子を試行する.
-
.load_records(file_path) ⇒ Array<Hash>
レコード群をファイルから読み込む.
-
.normalize_records(records, file_path) ⇒ Array<Hash>
読み込み結果をレコード配列へ正規化する。.
-
.resolve(source_name, data_dir) ⇒ String?
データファイルのパスを解決する 指定名そのまま → 複数形(末尾に s を付与)→ 単数形の順で探索する.
Class Method Details
.find_with_extensions(base_name, data_dir) ⇒ String?
指定名ですべての拡張子を試行する
126 127 128 129 130 131 132 |
# File 'lib/query_stream/data_resolver.rb', line 126 def find_with_extensions(base_name, data_dir) EXTENSIONS.each do |ext| path = File.join(data_dir, "#{base_name}#{ext}") return path if File.exist?(path) end nil end |
.load_records(file_path) ⇒ Array<Hash>
レコード群をファイルから読み込む
YAML は safe_load_file で読み込み、!ruby/object 等の危険なタグを
QueryStream::DataLoadError に変換して呼び出し元に通知する。
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/query_stream/data_resolver.rb', line 69 def load_records(file_path) records = case File.extname(file_path).downcase when '.json' JSON.parse(File.read(file_path, encoding: 'utf-8'), symbolize_names: true) else YAML.safe_load_file(file_path, permitted_classes: YAML_PERMITTED_CLASSES, aliases: true, symbolize_names: true) end normalize_records(records, file_path) rescue Psych::DisallowedClass => e raise DataLoadError.new( "データファイルに許可されていないクラス/タグが含まれています: #{e.} (#{file_path})", file_path: file_path, cause_error: e ) rescue Psych::SyntaxError => e raise DataLoadError.new( "データファイルの YAML 構文エラー: #{e.} (#{file_path})", file_path: file_path, cause_error: e ) rescue JSON::ParserError => e raise DataLoadError.new( "データファイルの JSON 構文エラー: #{e.} (#{file_path})", file_path: file_path, cause_error: e ) end |
.normalize_records(records, file_path) ⇒ Array<Hash>
読み込み結果をレコード配列へ正規化する。
常に配列を返すのが本メソッドの契約である。 空のデータファイルは YAML が
nil を返すため、素通しすると呼び出し先(TemplateCompiler)が
undefined method 'any?' for nil で落ちる——データを空にしただけの著者に
NoMethodError を見せることになる。
配列でもハッシュでもない中身(先頭が文字列や数値だけの YAML)は、 レコード群として解釈しようがないので DataLoadError で理由を伝える。
108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/query_stream/data_resolver.rb', line 108 def normalize_records(records, file_path) case records when nil then [] when Hash then [records] when Array then records else raise DataLoadError.new( "データファイルはレコードの配列(またはハッシュ 1 件)である必要があります" \ "(#{records.class} が入っています): #{file_path}", file_path: file_path ) end end |
.resolve(source_name, data_dir) ⇒ String?
データファイルのパスを解決する 指定名そのまま → 複数形(末尾に s を付与)→ 単数形の順で探索する
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/query_stream/data_resolver.rb', line 42 def resolve(source_name, data_dir) # そのまま試行 found = find_with_extensions(source_name, data_dir) return found if found # 複数形を試行(単数形→複数形: book → books) found = find_with_extensions("#{source_name}s", data_dir) return found if found # 単数形を試行(複数形→単数形: books → book) singular = Singularize.call(source_name) if singular != source_name found = find_with_extensions(singular, data_dir) return found if found end nil end |