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

Class Method Details

.find_with_extensions(base_name, data_dir) ⇒ String?

指定名ですべての拡張子を試行する

Parameters:

  • base_name (String)

    拡張子なしファイル名

  • data_dir (String)

    データディレクトリ

Returns:

  • (String, nil)

    見つかったファイルパス、または nil



103
104
105
106
107
108
109
# File 'lib/query_stream/data_resolver.rb', line 103

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` に変換して呼び出し元に通知する。

Parameters:

  • file_path (String)

    データファイルパス

Returns:

  • (Array<Hash>)

    レコード群(シンボルキー)

Raises:

  • (DataLoadError)

    YAML/JSON の構文エラー、許可されていないクラス等



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
97
# 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

  records = [records] if records.is_a?(Hash)
  records
rescue Psych::DisallowedClass => e
  raise DataLoadError.new(
    "データファイルに許可されていないクラス/タグが含まれています: #{e.message} (#{file_path})",
    file_path: file_path, cause_error: e
  )
rescue Psych::SyntaxError => e
  raise DataLoadError.new(
    "データファイルの YAML 構文エラー: #{e.message} (#{file_path})",
    file_path: file_path, cause_error: e
  )
rescue JSON::ParserError => e
  raise DataLoadError.new(
    "データファイルの JSON 構文エラー: #{e.message} (#{file_path})",
    file_path: file_path, cause_error: e
  )
end

.resolve(source_name, data_dir) ⇒ String?

データファイルのパスを解決する指定名そのまま → 複数形(末尾に s を付与)→ 単数形の順で探索する

Parameters:

  • source_name (String)

    データ名(単数形または複数形)

  • data_dir (String)

    データディレクトリ

Returns:

  • (String, nil)

    見つかったファイルパス、または nil



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