query-stream 1.2.2 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3f3bc788221f5c37fb1327f132501ec5fe4607e97f3e673ddbc2a32dfeeb188
4
- data.tar.gz: 9111b6651c0596097399b9ffb46f8acea17928dd572f3a7af38ef167ddd6a037
3
+ metadata.gz: 399e9fb8aea90ac45fa0d7837c9891c7db5785b2bd81f6976c697eaa1d92f35c
4
+ data.tar.gz: 6587887f665b0a6ffde78dc029e2988bd647debcd92f0740766805b273f2ea61
5
5
  SHA512:
6
- metadata.gz: 792bbe4684efb730c7d1f122ecdf6cff9dfbaa484254f7bf9830b47790978cba0a5150939845975e07fdd2ac9d24e464a66b2f17ee7085e4e8097f041fecb105
7
- data.tar.gz: e3de3485e7fdb0f5bdb9d8f728ee2742387540c342f82a27765b80282d9dff1b337a680f419467440fdfbf9b201dfc27414d43110f0f37864e097de36d4f1c04
6
+ metadata.gz: 47693f041e99aa59784a2d50a55fca8d1aa50c18798a16862a946a5c6ed1faedeafbc89a4fa2113d80fb793d2ef97d031a2e578ba64ab695f42e2ae3c946013a
7
+ data.tar.gz: '095ed49dca369ea7420c037ddf95d77bbf2833b85d5b9a312393f31694632ee9744b6bfc319dfdabd55b5025fcd82f9921d0d2e80b3d988a407145e2902b3132'
data/CHANGELOG.md ADDED
@@ -0,0 +1,181 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+
9
+ ### Planned
10
+ - パフォーマンス最適化
11
+ - 追加のテンプレートスタイル
12
+
13
+ ## [1.4.0] - 2026-08-07
14
+
15
+ ### Removed
16
+ - **`QueryStream.logger` と `Configuration#logger` を削除した** (`query_stream.rb`, `configuration.rb`, `query-stream.gemspec`): 下記の `logger.error` 撤去により、gem 内でロガーを読む箇所がゼロになった。設定できるのに何も起きない項目は、利用者に「ログ出力を制御できる」という誤った期待を持たせるだけなので残さない。`logger` gem への依存も外した。
17
+ - **破壊的変更**: `config.logger = ...` を書いているコードは削除が必要(設定しても何も起きないため、消すだけでよい)。
18
+ - 唯一の利用者である vivlio-starter は `QueryStream.configure` 自体を使っておらず、影響は無い。
19
+
20
+ ### Changed
21
+ - **`UnknownKeyError` を構造化例外にし、gem 内に最後まで残っていた `logger.error` を撤去した** (`errors.rb`, `template_compiler.rb`): 1.1.0 で `logger.error`、1.2.0 で `logger.warn` を廃したが、`TemplateCompiler` がテンプレートのキーを検証する 2 箇所にだけ `logger.error` が残っており、「gem 内のログ出力を全廃した」という設計が最後まで通っていなかった。`UnknownKeyError` は属性を 1 つも持たなかったため、**呼び出し元は「利用できるキーの一覧」を受け取れず**、gem が直接吐くログに頼るしかなかったのが原因である。`key_path` / `available_keys` / `template_path` / `location` を持たせ、ログ出力を削除した。これで呼び出し元は「もしかして `=title`?」のような案内を自前で組み立てられる。
22
+ - `location`(記法が書かれた原稿の位置)と `template_path`(打ち間違いがある雛形の位置)は別物として持つ。**直すのは雛形**なので、記法の位置だけでは著者はファイルを開けない。
23
+ - `TemplateCompiler.render` に `template_path:` キーワードを追加した(任意・既定 `nil`)。
24
+ - **必要な Ruby を 4.0 以上から 3.4 以上へ緩めた** (`query-stream.gemspec`): Ruby 4.0 固有の機能は使っていない。Prism のバージョン指定パースで全 14 ファイルを解析したところ 4.0.0 / 3.4.0 / 3.3.0 いずれも構文エラー 0 件で、実際の下限を決めていたのは `it`(暗黙ブロック引数・16 箇所)**単独**だった。`it` は 3.3 でも構文エラーにならず「`it` というメソッドの呼び出し」として通り、実行時に `NameError` になる——静的解析では見つからないので、Ruby 3.4.10 で実走して全テスト通過を確認している。コード変更はゼロ(gemspec 1 行のみ)。
25
+
26
+ ### Fixed
27
+ - **壊れた入力で生の例外が外へ漏れていたのを直した**: いずれも「著者が用意した原稿・データが壊れている」という正当に起こりうる状況で、`QueryStream::Error` 系ではない例外が呼び出し元へ届いていた。呼び出し元は例外型で扱いを分けるため、生の `ArgumentError` / `NoMethodError` が出ると「どのファイルのどこが悪いか」を著者へ案内できない。
28
+ - **空のデータファイルで `NoMethodError`** (`data_resolver.rb`): YAML が `nil` を返すのを素通ししており、`TemplateCompiler` が `undefined method 'any?' for nil` で落ちていた。`load_records` は**常に配列を返す**契約に正規化した(`@return [Array<Hash>]` という既存の記述に実装を合わせた形)。レコードの配列でもハッシュでもない中身(スカラーだけの YAML)は、何が入っていたかを添えて `DataLoadError` にする。
29
+ - **不正な UTF-8 を含む原稿で `ArgumentError`** (`query_stream.rb`): `String#match?` も `lstrip` も不正バイト列に対して `invalid byte sequence in UTF-8` を投げるため、原稿に 1 バイトの壊れが混ざっただけで展開が丸ごと止まっていた。読めない行は**本文としてそのまま返す**。scrub して通す設計は採らない——gem が黙ってバイト列を書き換えると、著者が気付けない形で本文が変わる。
30
+ - **`scan` に本文を渡すと `ArgumentError` / `Errno::EISDIR`** (`query_stream.rb`): `scan` はパスと本文の両方を受け取る API なのに、引数を無条件で `File.exist?` へ渡していた。NUL バイトを含む本文で `path name contains null byte`、ディレクトリ名で `File.exist?` が true を返し `File.read` が `Errno::EISDIR` になっていた。パスとして成立しうる形(NUL・改行を含まず `MAX_PATH_BYTES` 以下で、かつ `File.file?`)だけを読み、判定自体の失敗も本文扱いに倒す。
31
+
32
+ ### Added
33
+ - **堅牢性テストを整備した** (`test/robustness/`): 「正しく使ったとき正しく動くか」を見る既存のユニットテストとは別に、**想定外の入力・環境に対する振る舞い**を固定する 27 件を追加。守る不変条件は「gem の外へ出てよい例外は `QueryStream::Error` の系統だけ」。上記 3 件の修正はいずれもこのテストを書く過程で見つかったもの。
34
+ - `data_file_safety_test.rb` — `!ruby/object` 等の危険なタグ・壊れた YAML/JSON・空ファイル・レコードでない中身
35
+ - `broken_encoding_test.rb` — 不正な UTF-8 を含む原稿。**バイト列を書き換えずに返す**ことまで固定
36
+ - `scan_input_test.rb` — `scan` のパス/本文判定(NUL・改行・超長入力・ディレクトリ)
37
+ - `missing_source_test.rb` — データ/テンプレート不在時の例外属性と、1 行の失敗で全体を止めないこと。**当てずっぽうの hint を返さない**ことも固定
38
+ - `unreadable_file_test.rb` — 権限エラーは `DataLoadError` へ包まず `Errno::EACCES` のまま伝える(環境の問題とデータの問題は直し方が違うため)
39
+
40
+ ## [1.3.0] - 2026-07-12
41
+
42
+ ### Added
43
+ - **`post_render` 後段フィルタコールバックを追加** (`lib/query_stream.rb`, `lib/query_stream/configuration.rb`): 1 記法の展開結果を、コンテキスト付きで呼び出し元へ通す汎用フックを新設。`QueryStream.render` / `render_query` に `post_render:` キーワードを追加し、`Configuration#post_render` からも指定できる。コールバックは `(text, context)` を受け取り、`context` は `source`(記法の論理名)・`data_file`(単複解決後の実パス)・`data_dir`・`template_path`・`query`・`location` を含む。戻り値が String ならそれを、String 以外(nil 含む)なら元の展開結果を採用する。gem 自身は用途を規定せず、画像パス解決などの呼び出し元固有の後処理を委譲できる。コールバック内の例外は握り潰さず伝播する(`render` の既存 rescue は `QueryStream::Error` のみ捕捉するため、それ以外の後処理例外の扱いは呼び出し元の責務)。
44
+
45
+ ## [1.2.2] - 2026-04-26
46
+
47
+ ### Fixed
48
+ - **アンダースコア付き複合名の単数形変換が誤る問題を修正** (`lib/query_stream/singularize.rb`): `physics_books` が `physic_books` に変換されていた問題を修正。アンダースコアで分割し、末尾から複数形セグメントを探して単数化するよう変更。`people` は不規則変化として優先処理。`physics_books` → `physics_book`、`books_nested` → `book_nested` が正しく変換されるようになった。
49
+
50
+ ## [1.2.1] - 2026-04-20
51
+
52
+ ### Security
53
+ - **`DataResolver.load_records` を `YAML.safe_load_file` に移行** (`lib/query_stream/data_resolver.rb`):
54
+ 従来は `YAML.load_file(file_path, symbolize_names: true)` を使用しており、Psych のバージョンや将来のアップデートで `!ruby/object` などの Ruby オブジェクトタグが受理されてしまう可能性があった。
55
+ `permitted_classes: [Symbol, Time, Date, DateTime]` と `aliases: true` を明示的に指定する `YAML.safe_load_file` に置き換え、安全性を Psych バージョン非依存にした。
56
+ これにより悪意のあるデータファイル(`!ruby/object:Kernel {}` 等)を読み込ませて任意コード実行を試みる攻撃ベクトルを明示的に塞いだ。
57
+ なお Symbol が許可されているため `symbolize_names: true` の挙動は従来どおり維持される。
58
+
59
+ ### Added
60
+ - **`QueryStream::DataLoadError` 新規例外クラス** (`lib/query_stream/errors.rb`):
61
+ `Psych::DisallowedClass` / `Psych::SyntaxError` / `JSON::ParserError` を呼び出し元に優しいメッセージ付きの `DataLoadError` に変換する。
62
+ `file_path` と `cause_error` 属性を持ち、呼び出し元で詳細なログ出力や i18n が可能。
63
+
64
+ ### Tests
65
+ - **セキュリティテスト 7 件を追加** (`test/query_stream_test.rb`):
66
+ - `!ruby/object:Object {}` を含む YAML は `DataLoadError` で拒否
67
+ - `!ruby/struct:Point` / `!ruby/hash:MyCustomHash` も同様に拒否
68
+ - Symbol / Time / Date / DateTime は正常に読み込める
69
+ - YAML / JSON 構文エラーは `DataLoadError` に変換される
70
+ - 通常の YAML anchor / alias は正常に展開される(DoS 耐性の副次確認)
71
+
72
+ ## [1.2.0] - 2026-04-19
73
+
74
+ ### Fixed
75
+ - **`NoResultWarning` / `AmbiguousQueryWarning` を構造化例外に変更し、gem 内の `logger.warn` 呼び出しを全廃** (`lib/query_stream.rb`, `lib/query_stream/errors.rb`): 1.1.0 で `logger.error` は廃止されていたが、`render_query` の一件検索分岐に `logger.warn("一件検索で該当なし(…): …")` / `logger.warn("一件検索で複数件ヒット(…): …")` が残存しており、呼び出し元(vivlio-starter 等)が `⚠️` プレフィックスや i18n を付与できない問題があった。`NoResultWarning` / `AmbiguousQueryWarning` に `query` / `location` (ambiguous は `count` も)属性を追加し、`logger.warn` 呼び出しを削除。新たに `QueryStream.render` / `render_query` に `on_warning:` コールバックを追加し、警告情報を構造化例外として呼び出し元へ委譲する。これにより gem 内のログ出力が完全になくなり、メッセージ構成・ログ出力・i18n はすべて呼び出し元の責務となった。
76
+
77
+ ## [1.1.0] - 2026-04-13
78
+
79
+ ### Fixed
80
+
81
+ - **`TemplateNotFoundError` / `DataNotFoundError` を構造化例外に変更** (`lib/query_stream.rb`, `lib/query_stream/errors.rb`):
82
+ 従来は `render_query` 内で `logger.error` によるログ出力を行ってから例外を raise していた。
83
+ これでは呼び出し元がメッセージフォーマットや言語(i18n)を制御できないため、
84
+ gem 内のログ出力を廃止し、例外クラスに `template_path`, `query`, `location`, `hint`
85
+ (`DataNotFoundError` は `expected_path`, `query`, `location`)の属性を追加。
86
+ メッセージ構成・ログ出力・i18n はすべて呼び出し元の責務とした。
87
+
88
+ - **`render` 内で展開エラーをキャッチして後続の記法を継続展開するよう変更** (`lib/query_stream.rb`):
89
+ 従来は1行の展開失敗で `render` 全体が中断されていた。
90
+ `render_query` の呼び出しを `rescue Error` で囲み、失敗した行は元の記法のまま残して
91
+ 後続の QueryStream 記法の展開を継続するよう修正。
92
+ `on_error` コールバックを追加し、エラー情報を呼び出し元に通知できるようにした。
93
+
94
+ - **`Singularize` で `People`(大文字)が `person` に変換されない問題を修正** (`lib/query_stream/singularize.rb`):
95
+ `people` パターンの正規表現に `/i` フラグを追加し、大文字小文字を問わず変換できるようにした。
96
+
97
+ ## [1.0.0] - 2026-03-21
98
+
99
+ ### 🎉 最初のメジャーリリース
100
+
101
+ QueryStream 1.0.0 としてリリース!YAML/JSON データファイルとテンプレートファイルを組み合わせて、テキストコンテンツ内の QueryStream 記法を展開する汎用 Ruby ライブラリが完成しました。
102
+
103
+ ### ✅ 実績と品質保証
104
+ - **vivlio-starter** プロジェクトで実稼働実績
105
+ - **109 テストケース**、**395 アサーション**で網羅的品質保証
106
+ - **VFM フェンス記法** 完全対応と実用性検証
107
+
108
+ ### 🚀 主要機能
109
+ - QueryStream 記法の完全実装(源泉・抽出・ソート・件数・スタイル)
110
+ - VFM フェンス記法対応(`:::{.class-name}` 〜 `:::`)
111
+ - テンプレートコンパイラ(変数展開、画像記法、ネスト値アクセス)
112
+ - 高度なデータ処理(フィルタリング、ソート、単数形化)
113
+ - 柔軟な設定システム
114
+
115
+ ### 📚 ドキュメント整備
116
+ - 詳細な README と具体例
117
+ - 完全な CHANGELOG
118
+ - vivlio-style での実装例
119
+
120
+ ### 🔧 技術的特徴
121
+ - **Ruby 4.0+** モダン開発標準準拠
122
+ - **Semantic Versioning** 準拠
123
+ - 後方互換性保証
124
+
125
+ ## [0.3.0] - 2026-03-21
126
+
127
+ ### Added
128
+ - VFM フェンス記法対応 (`:::{.class-name}` 〜 `:::`)
129
+ - フェンス行が動的行を囲んでいる場合、フェンス行も repeating 範囲に含めて各レコードごとに反復出力
130
+ - `{.book-card}`, `{.person-card}` 等の任意 VFM クラス名に汎用的に対応
131
+ - フェンス記法関連のテストケースを追加 (12件)
132
+ - ファイルドキュメントに VFM フェンス記法対応の説明を追加
133
+
134
+ ### Changed
135
+ - `TemplateCompiler` に `FENCE_OPEN_PATTERN` / `FENCE_CLOSE_PATTERN` 定数を追加
136
+ - `classify_lines` で `:fence_open` / `:fence_close` タイプを認識
137
+ - `expand_fence_range` メソッドを新設し、repeating 範囲の拡張ロジックを実装
138
+
139
+ ### Fixed
140
+ - QueryStream と vivlio-starter の VFM フェンス記法の相性問題を解決
141
+ - フェンス行が一度しか出力されず、全レコードが1つのフェンスに押し込まれる問題を修正
142
+
143
+ ## [0.2.0] - Previous Release
144
+
145
+ ### Added
146
+ - 複数スタイル対応 (`:full`, `:table` 等)
147
+ - 高度なフィルタリング機能(範囲指定、不等値比較)
148
+ - パフォーマンス最適化
149
+ - エラーハンドリングの改善
150
+
151
+ ## [0.1.0] - Initial Release
152
+
153
+ ### Added
154
+ - 基本的な QueryStream 記法の実装
155
+ - 源泉指定 (`= books`)
156
+ - フィルタリング (`tags=ruby`, `condition=晴`)
157
+ - ソート (`-title`, `+date`)
158
+ - 件数制限 (`5`)
159
+ - スタイル指定 (`:full`)
160
+ - テンプレートコンパイラ機能
161
+ - 変数展開 (`= title`, `= author`)
162
+ - 画像記法の展開 (`![](cover)`)
163
+ - ネストされた値へのアクセス (`= author.name`)
164
+ - テーブル記法対応
165
+ - データフィルタリングとソート機能
166
+ - 等値フィルタ (`tags=ruby`)
167
+ - AND/OR 条件 (`tags=ruby && beginner`, `tags=ruby, javascript`)
168
+ - 比較演算子 (`>=`, `<=`, `>`, `<`, `!=`)
169
+ - データリゾルバー
170
+ - YAML/JSON ファイルの自動探索
171
+ - 複数形→単数形の自動テンプレート解決
172
+ - 単数形化ユーティリティ (Singularize)
173
+ - 英語の複数形パターン対応
174
+ - 不規則名詞 (people → person)
175
+ - 設定システム
176
+ - データディレクトリ、テンプレートディレクトリの設定
177
+ - ロガー設定
178
+ - エラー処理
179
+ - データファイル不在エラー
180
+ - テンプレートファイル不在エラー
181
+ - 不明キーエラー
data/README.md CHANGED
@@ -13,6 +13,8 @@ gem 'query-stream'
13
13
  bundle install
14
14
  ```
15
15
 
16
+ Ruby 3.4 以上が必要です。
17
+
16
18
  ## 基本的な使い方
17
19
 
18
20
  ```ruby
@@ -20,9 +22,11 @@ require 'query_stream'
20
22
 
21
23
  # テキスト内の QueryStream 記法を展開
22
24
  source = File.read('contents/05-references.md')
23
- result = QueryStream.render(source)
25
+ result = QueryStream.render(source, data_dir: 'data', templates_dir: 'templates')
24
26
  ```
25
27
 
28
+ `data_dir` / `templates_dir` は後述の `configure` で既定値を決めておけば省略できます。
29
+
26
30
  ## QueryStream 記法
27
31
 
28
32
  ```
@@ -106,10 +110,66 @@ QueryStream.configure do |config|
106
110
  config.data_dir = 'data'
107
111
  config.templates_dir = 'templates'
108
112
  config.default_format = :md
109
- config.logger = Logger.new($stdout)
113
+ config.post_render = ->(text, context) { text }
114
+ end
115
+ ```
116
+
117
+ ## エラー・警告の扱い
118
+
119
+ **この gem はメッセージを組み立てません。** どう表示するか、どの言語で出すか、そもそもログに残すかは、すべて呼び出し元が決めます。そのため展開時の出来事は、構造化された例外としてコールバックへ渡されます。
120
+
121
+ ```ruby
122
+ QueryStream.render(
123
+ content,
124
+ data_dir: 'data',
125
+ templates_dir: 'templates',
126
+ source_filename: 'chapter.md', # 位置情報(location)の表示に使います
127
+ on_error: ->(e) { }, # 展開失敗。その行は元の記法のまま残ります
128
+ on_warning: ->(w) { }, # 一件検索の該当なし/複数ヒット
129
+ post_render: ->(text, ctx) { } # 展開結果の後処理
130
+ )
131
+ ```
132
+
133
+ **1 行の失敗で全体は止まりません。** 失敗した行は元の記法のまま残り、後続の記法は展開され続けます。
134
+
135
+ | 例外クラス | 属性 |
136
+ |:---|:---|
137
+ | `TemplateNotFoundError` | `template_path`, `query`, `location`, `hint` |
138
+ | `DataNotFoundError` | `expected_path`, `query`, `location` |
139
+ | `DataLoadError` | `file_path`, `cause_error` |
140
+ | `UnknownKeyError` | `key_path`, `available_keys`, `template_path`, `location` |
141
+ | `NoResultWarning` | `query`, `location` |
142
+ | `AmbiguousQueryWarning` | `query`, `location`, `count` |
143
+
144
+ 前 4 つは `QueryStream::Error`、後 2 つは `QueryStream::Warning` を継承します。**gem の外へ出る例外はこの 2 系統だけ**です。壊れた YAML も、不正な UTF-8 を含む原稿も、生の `ArgumentError` や `NoMethodError` にはなりません。
145
+
146
+ たとえば `UnknownKeyError` は「使えるキーの一覧」と「直すべき雛形のパス」まで持って届くので、呼び出し元で打ち間違いの案内を組み立てられます。`location` は記法が書かれた原稿の位置、`template_path` は直す雛形の位置で、**直すのは雛形のほう**です。
147
+
148
+ ```ruby
149
+ on_error: lambda do |e|
150
+ next unless e.is_a?(QueryStream::UnknownKeyError)
151
+
152
+ keys = e.available_keys.map(&:to_s)
153
+ near = DidYouMean::SpellChecker.new(dictionary: keys).correct(e.key_path.split('.').first).first
154
+ puts "#{e.location} もしかして =#{near}?(#{e.template_path} / 使えるキー: #{keys.join(', ')})"
155
+ end
156
+ ```
157
+
158
+ 例外はファイル権限のみ扱いが異なり、`Errno::EACCES` のまま伝わります。環境の問題(`chmod` で直る)とデータの問題(中身を直す)は、対処が違うためです。
159
+
160
+ ### `post_render`
161
+
162
+ 展開結果を、その出どころの情報つきで受け取れます。gem 側は用途を規定しないので、画像パスの解決など固有の後処理を差し込めます。
163
+
164
+ ```ruby
165
+ post_render: lambda do |text, context|
166
+ # context: source, data_file, data_dir, template_path, query, location
167
+ MyImageResolver.rewrite(text, context)
110
168
  end
111
169
  ```
112
170
 
171
+ 戻り値が `String` ならそれを、そうでなければ元の展開結果を採用します。
172
+
113
173
  ## ライセンス
114
174
 
115
175
  MIT License
data/RELEASE_NOTE.md ADDED
@@ -0,0 +1,61 @@
1
+ # QueryStream リリースノート
2
+
3
+ YAML / JSON のデータファイルとテンプレートを組み合わせて、文章中の 1 行記法を展開する Ruby ライブラリです。使い方は [README](README.md)、網羅的な変更履歴は [CHANGELOG](CHANGELOG.md) をご覧ください。
4
+
5
+ 新しい版から順に並べています。
6
+
7
+ ---
8
+
9
+ ## 1.4.0 — 2026-08-07
10
+
11
+ **細かな不具合修正が中心のリリースです。** いずれも「著者が用意した原稿やデータが壊れている」という、実際に起こりうる場面で想定外の例外が漏れていた問題です。
12
+
13
+ - **空のデータファイルで落ちなくなりました。** 空 YAML は例外ではなく空配列として扱います。レコードでない中身(スカラーだけの YAML など)は、何が入っていたかを添えて `DataLoadError` で知らせます
14
+ - **壊れた文字が 1 バイト混ざっただけで展開が止まらなくなりました。** 読めない行は本文としてそのまま返します。gem が黙ってバイト列を書き換える(scrub する)設計は採っていません
15
+ - **`scan` に本文を渡しても落ちなくなりました。** パスと本文の両方を受け取る API なのに、引数を無条件でファイルとして開こうとしていました
16
+ - **`UnknownKeyError` が「使えるキーの一覧」と「直すべき雛形のパス」を持って届くようになりました。** これまでこの例外だけ属性が無く、キーの候補は gem が直接吐くログにしか出ていませんでした。`key_path` / `available_keys` / `template_path` / `location` を持たせ、**gem 内に最後まで残っていた `logger.error` を撤去**しています。呼び出し元は「もしかして `=title`?」のような案内を自前で組み立てられます
17
+ - **必要な Ruby を 4.0 以上から 3.4 以上へ緩めました**(コード変更はゼロ、gemspec 1 行のみ)
18
+
19
+ **破壊的変更が 1 つあります。** `QueryStream.logger` と `config.logger` を削除しました。上記の撤去で gem 内にロガーを読む箇所が無くなり、設定できるのに何も起きない項目になったためです。`config.logger = ...` と書いている箇所があれば、消してください(設定しても何も起きないので、消すだけで済みます)。`logger` gem への依存も外しました。
20
+
21
+ あわせて、これらを二度と起こさないための**堅牢性テスト 27 件**を `test/robustness/` に追加しました。守る約束は 1 つ、**gem の外へ出てよい例外は `QueryStream::Error` の系統だけ**です。呼び出し元は例外の型で扱いを分けるため、生の `ArgumentError` が出ると「どのファイルのどこが悪いか」を著者へ案内できません。上の 3 件は、このテストを書く過程で見つかりました。
22
+
23
+ ただし権限エラーだけは `Errno::EACCES` のまま伝えます。**環境の問題(`chmod` で直る)とデータの問題(中身を直す)は対処が違う**ためです。
24
+
25
+ ## 1.3.0 — 2026-07-12
26
+
27
+ - **`post_render` 後段フィルタを追加しました。** 1 記法の展開結果を、コンテキスト付きで呼び出し元へ渡す汎用フックです。`context` には `source` / `data_file` / `data_dir` / `template_path` / `query` / `location` が入ります
28
+ - gem 自身は用途を規定しません。画像パス解決などの呼び出し元固有の後処理を、gem に固有知識を持ち込まずに差し込めます
29
+
30
+ ## 1.2.2 — 2026-04-26
31
+
32
+ - **`physics_books` が `physic_books` になる単数形変換の誤りを修正しました。** アンダースコアで分割し、末尾から複数形セグメントを探して単数化します(`physics_books` → `physics_book`、`books_nested` → `book_nested`)
33
+
34
+ ## 1.2.1 — 2026-04-20
35
+
36
+ - **データファイルの読み込みを `YAML.safe_load_file` へ移行しました(セキュリティ)。** `permitted_classes: [Symbol, Time, Date, DateTime]` を明示し、`!ruby/object:Kernel {}` のような Ruby オブジェクトタグを読ませて任意コード実行を狙う経路を塞いでいます。安全性が Psych のバージョンに依存しなくなりました
37
+ - **`DataLoadError` を追加しました。** `Psych::DisallowedClass` / `Psych::SyntaxError` / `JSON::ParserError` を、`file_path` と `cause_error` を持つ例外に変換します
38
+
39
+ ## 1.2.0 — 2026-04-19
40
+
41
+ - **警告の `logger.warn` を全廃し、`on_warning:` コールバックで呼び出し元へ委譲しました。** `NoResultWarning` / `AmbiguousQueryWarning` に `query` / `location`(後者は `count` も)を持たせています
42
+ - これにより、`⚠️` の付け方も i18n も呼び出し元で決められるようになりました
43
+
44
+ > **補足**: このとき `TemplateCompiler` が `UnknownKeyError` を投げる経路にだけ `logger.error` が残っていました。1.4.0 で撤去し、**gem 内のログ出力はここで本当にゼロになりました**(設定項目 `config.logger` も同時に削除)。
45
+
46
+ ## 1.1.0 — 2026-04-13
47
+
48
+ - **エラーを構造化例外へ移行しました。** `TemplateNotFoundError` に `template_path` / `query` / `location` / `hint`、`DataNotFoundError` に `expected_path` / `query` / `location` を持たせ、gem 内の `logger.error` を廃止しました
49
+ - **1 行の展開失敗で全体が止まる問題を修正しました。** 失敗した行は元の記法のまま残し、後続の展開を続けます。`on_error:` コールバックで通知します
50
+ - **`People`(大文字)が `person` に変換されない問題を修正しました**
51
+
52
+ ## 1.0.0 — 2026-03-21
53
+
54
+ 最初のメジャーリリースです。
55
+
56
+ - QueryStream 記法の完全実装(源泉・抽出条件・ソート・件数・スタイル)
57
+ - VFM フェンス記法対応(`:::{.book-card}` 〜 `:::`)。各レコードが個別のフェンスで囲まれて展開されます
58
+ - テンプレートコンパイラ(変数展開・画像記法・ネスト値アクセス・表記法)
59
+ - データリゾルバ(YAML / JSON の自動探索、複数形→単数形のテンプレート解決)
60
+ - フィルタリング(等値・AND / OR・比較演算子)とソート
61
+ - 設定システム(`data_dir` / `templates_dir` / `default_format` / `logger`)
@@ -17,6 +17,7 @@ module QueryStream
17
17
 
18
18
  options do
19
19
  option '--version', 'Print version and exit'
20
+ option '--help', 'Print this message and exit'
20
21
  end
21
22
 
22
23
  # コマンド実行
@@ -28,12 +29,19 @@ module QueryStream
28
29
  end
29
30
  end
30
31
 
31
- private
32
-
33
- def print_usage
34
- puts self.class.description
35
- puts "Usage: query-stream [options]"
36
- puts " --version Print version and exit"
32
+ # 使い方を表示する。
33
+ #
34
+ # public かつ `output:` を受ける形でなければならない。Samovar は引数の解析に
35
+ # 失敗すると、外から `error.command.print_usage(output: output)` を呼んで
36
+ # 使い方を出そうとする。private に置いていた頃は、そこで
37
+ # `private method 'print_usage' called` の NoMethodError になり、
38
+ # **`--help` と未知の引数がスタックトレースで落ちていた**。
39
+ # @param output [IO] 出力先(Samovar からはエラー出力が渡される)
40
+ def print_usage(output: $stdout)
41
+ output.puts self.class.description
42
+ output.puts 'Usage: query-stream [options]'
43
+ output.puts ' --version Print version and exit'
44
+ output.puts ' --help Print this message and exit'
37
45
  end
38
46
  end
39
47
  end
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
-
5
3
  # ================================================================
6
4
  # File: lib/query_stream/configuration.rb
7
5
  # ================================================================
8
6
  # 責務:
9
7
  # QueryStream のグローバル設定を管理する。
10
- # data_dir, templates_dir, default_format, logger の4項目。
8
+ # data_dir, templates_dir, default_format, post_render の4項目。
9
+ #
10
+ # ログ出力の設定は持たない。gem 自身がログを出さないためである
11
+ # (失敗はすべて構造化例外として on_error / on_warning へ渡す)。
11
12
  # ================================================================
12
13
 
13
14
  module QueryStream
@@ -22,14 +23,16 @@ module QueryStream
22
23
  # @return [Symbol] スタイル省略時のデフォルト出力形式(:md / :html / :json)
23
24
  attr_accessor :default_format
24
25
 
25
- # @return [Logger] ログ出力先
26
- attr_accessor :logger
26
+ # 1 記法の展開結果を、コンテキスト付きで呼び出し元へ通す後段フィルタ。
27
+ # gem 自身は用途を規定しない(画像パス解決など呼び出し元固有の後処理を担わせる)。
28
+ # @return [Proc, nil] (text, context) -> String。String 以外を返した場合は元の展開結果を採用する
29
+ attr_accessor :post_render
27
30
 
28
31
  def initialize
29
32
  @data_dir = 'data'
30
33
  @templates_dir = 'templates'
31
34
  @default_format = :md
32
- @logger = Logger.new($stdout)
35
+ @post_render = nil
33
36
  end
34
37
  end
35
38
  end
@@ -77,8 +77,7 @@ module QueryStream
77
77
  symbolize_names: true)
78
78
  end
79
79
 
80
- records = [records] if records.is_a?(Hash)
81
- records
80
+ normalize_records(records, file_path)
82
81
  rescue Psych::DisallowedClass => e
83
82
  raise DataLoadError.new(
84
83
  "データファイルに許可されていないクラス/タグが含まれています: #{e.message} (#{file_path})",
@@ -96,6 +95,30 @@ module QueryStream
96
95
  )
97
96
  end
98
97
 
98
+ # 読み込み結果をレコード配列へ正規化する。
99
+ #
100
+ # **常に配列を返すのが本メソッドの契約である。** 空のデータファイルは YAML が
101
+ # `nil` を返すため、素通しすると呼び出し先(TemplateCompiler)が
102
+ # `undefined method 'any?' for nil` で落ちる——データを空にしただけの著者に
103
+ # NoMethodError を見せることになる。
104
+ #
105
+ # 配列でもハッシュでもない中身(先頭が文字列や数値だけの YAML)は、
106
+ # レコード群として解釈しようがないので DataLoadError で理由を伝える。
107
+ # @return [Array<Hash>]
108
+ def normalize_records(records, file_path)
109
+ case records
110
+ when nil then []
111
+ when Hash then [records]
112
+ when Array then records
113
+ else
114
+ raise DataLoadError.new(
115
+ "データファイルはレコードの配列(またはハッシュ 1 件)である必要があります" \
116
+ "(#{records.class} が入っています): #{file_path}",
117
+ file_path: file_path
118
+ )
119
+ end
120
+ end
121
+
99
122
  # 指定名ですべての拡張子を試行する
100
123
  # @param base_name [String] 拡張子なしファイル名
101
124
  # @param data_dir [String] データディレクトリ
@@ -51,7 +51,32 @@ module QueryStream
51
51
  end
52
52
  end
53
53
 
54
- class UnknownKeyError < Error; end # テンプレート内に存在しないキー
54
+ # テンプレートに、データレコードが持たないキーが書かれている
55
+ #
56
+ # 「どのキーが無いか」だけでなく「代わりに何が使えるか」「どのファイルを直すか」まで
57
+ # 属性で渡す。呼び出し元はこれを使って「もしかして =author?」のような案内を組み立てられる。
58
+ # 属性が無かった頃はこのクラスだけが gem 内で logger.error を呼んでおり、
59
+ # 利用できるキーの一覧を呼び出し元が受け取れなかった。
60
+ #
61
+ # location(記法の位置)と template_path(雛形の位置)は別物である。
62
+ # 直すのは雛形なので、記法の位置だけでは著者はファイルを開けない。
63
+ #
64
+ # @attr_reader key_path [String] テンプレートに書かれていたキー("author.name" 等)
65
+ # @attr_reader available_keys [Array<Symbol>] レコードが実際に持つキー
66
+ # @attr_reader template_path [String, nil] 打ち間違いがあるテンプレートのパス
67
+ # @attr_reader location [String] 記法が書かれていたソースファイル名と行番号
68
+ class UnknownKeyError < Error
69
+ attr_reader :key_path, :available_keys, :template_path, :location
70
+
71
+ def initialize(msg = nil, key_path: nil, available_keys: [], template_path: nil, location: nil)
72
+ super(msg || "テンプレートに存在しないキーが記述されています: #{key_path}")
73
+ @key_path = key_path
74
+ @available_keys = Array(available_keys)
75
+ @template_path = template_path
76
+ @location = location
77
+ end
78
+ end
79
+
55
80
  class InvalidDateError < Error; end # 無効な日付
56
81
 
57
82
  # データファイルの読み込みに失敗した
@@ -51,10 +51,11 @@ module QueryStream
51
51
  # @param records [Array<Hash>] データレコード群
52
52
  # @param source_filename [String, nil] エラー報告用ファイル名
53
53
  # @param line_number [Integer, nil] エラー報告用行番号
54
+ # @param template_path [String, nil] エラー報告用テンプレートパス(キーの打ち間違いはここを直す)
54
55
  # @return [String] 展開後のテキスト
55
- def render(template, records, source_filename: nil, line_number: nil)
56
+ def render(template, records, source_filename: nil, line_number: nil, template_path: nil)
56
57
  lines = template.lines
57
- validate_template_keys!(lines, records.first, source_filename:, line_number:) if records.any?
58
+ validate_template_keys!(lines, records.first, source_filename:, line_number:, template_path:) if records.any?
58
59
 
59
60
  parts = classify_lines(lines)
60
61
  return '' if records.empty?
@@ -306,7 +307,8 @@ module QueryStream
306
307
  # @param sample_record [Hash] サンプルレコード(最初の1件)
307
308
  # @param source_filename [String, nil] エラー報告用ファイル名
308
309
  # @param line_number [Integer, nil] エラー報告用行番号
309
- def validate_template_keys!(lines, sample_record, source_filename: nil, line_number: nil)
310
+ # @param template_path [String, nil] エラー報告用テンプレートパス
311
+ def validate_template_keys!(lines, sample_record, source_filename: nil, line_number: nil, template_path: nil)
310
312
  return unless sample_record
311
313
 
312
314
  location = source_filename ? "#{source_filename}:#{line_number}" : ''
@@ -327,10 +329,7 @@ module QueryStream
327
329
  line.scan(VARIABLE_PATTERN).each do |(key_path)|
328
330
  root_key = key_path.split('.').first.to_sym
329
331
  unless available_keys.include?(root_key)
330
- msg = "テンプレートに存在しないキーが記述されています: #{key_path}"
331
- QueryStream.logger.error("#{msg}(#{location})")
332
- QueryStream.logger.error(" 利用可能なキー: #{available_keys.join(', ')}")
333
- raise UnknownKeyError, msg
332
+ raise UnknownKeyError.new(key_path:, available_keys:, template_path:, location:)
334
333
  end
335
334
  end
336
335
 
@@ -341,10 +340,7 @@ module QueryStream
341
340
 
342
341
  root_key = src.split('.').first.to_sym
343
342
  unless available_keys.include?(root_key)
344
- msg = "テンプレートに存在しないキーが記述されています: #{src}"
345
- QueryStream.logger.error("#{msg}(#{location})")
346
- QueryStream.logger.error(" 利用可能なキー: #{available_keys.join(', ')}")
347
- raise UnknownKeyError, msg
343
+ raise UnknownKeyError.new(key_path: src, available_keys:, template_path:, location:)
348
344
  end
349
345
  end
350
346
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QueryStream
4
- VERSION = '1.2.2'
4
+ VERSION = '1.4.0'
5
5
  end
data/lib/query_stream.rb CHANGED
@@ -29,6 +29,10 @@ module QueryStream
29
29
  # 行頭 = の直後に英数字/ハイフン/アンダースコアのデータ名(スペースは任意)
30
30
  QUERY_STREAM_PATTERN = /^=\s*([a-zA-Z][a-zA-Z0-9_-]*)(?:\s*\|.*)?$/
31
31
 
32
+ # これを超える長さの引数はパスとみなさず本文として扱う(scan の path/content 判定)。
33
+ # 主要な OS の PATH_MAX は 4096 前後で、それより長い「パス」は実在しない。
34
+ MAX_PATH_BYTES = 4096
35
+
32
36
  class << self
33
37
  # グローバル設定を返す
34
38
  # @return [Configuration]
@@ -42,12 +46,6 @@ module QueryStream
42
46
  yield(configuration)
43
47
  end
44
48
 
45
- # ロガーへのショートカット
46
- # @return [Logger]
47
- def logger
48
- configuration.logger
49
- end
50
-
51
49
  # テキストコンテンツ内の QueryStream 記法をすべて展開する
52
50
  # 1行の展開に失敗しても残りの行の処理を継続する。
53
51
  # エラー情報は例外の属性として呼び出し元に委ねる(gem 内ではログ出力しない)。
@@ -57,10 +55,13 @@ module QueryStream
57
55
  # @param templates_dir [String, nil] テンプレートディレクトリ(nil時はconfigを使用)
58
56
  # @param on_error [Proc, nil] エラー時コールバック。|exception| を受け取る。省略時は何もしない。
59
57
  # @param on_warning [Proc, nil] 警告時コールバック。|warning| を受け取る。省略時は何もしない。
58
+ # @param post_render [Proc, nil] 展開結果の後段フィルタ。(text, context) -> String。省略時は configuration.post_render を使う。
60
59
  # @return [String] 展開後のテキストコンテンツ
61
- def render(content, source_filename: nil, data_dir: nil, templates_dir: nil, on_error: nil, on_warning: nil)
60
+ def render(content, source_filename: nil, data_dir: nil, templates_dir: nil, on_error: nil, on_warning: nil,
61
+ post_render: nil)
62
62
  data_dir ||= configuration.data_dir
63
63
  templates_dir ||= configuration.templates_dir
64
+ post_render ||= configuration.post_render
64
65
 
65
66
  lines = content.lines
66
67
  result = []
@@ -70,7 +71,7 @@ module QueryStream
70
71
  line_number = idx + 1
71
72
 
72
73
  # コードブロック内はスキップ
73
- if line.lstrip.start_with?('```')
74
+ if code_fence?(line)
74
75
  in_code_block = !in_code_block
75
76
  result << line
76
77
  next
@@ -82,10 +83,10 @@ module QueryStream
82
83
  end
83
84
 
84
85
  # QueryStream 記法の検出
85
- if line.match?(QUERY_STREAM_PATTERN)
86
+ if query_line?(line)
86
87
  begin
87
88
  expanded = render_query(
88
- line.chomp, line_number:, source_filename:, data_dir:, templates_dir:, on_warning:
89
+ line.chomp, line_number:, source_filename:, data_dir:, templates_dir:, on_warning:, post_render:
89
90
  )
90
91
  result << expanded << "\n"
91
92
  rescue Error => e
@@ -107,8 +108,10 @@ module QueryStream
107
108
  # @param source_filename [String, nil] ソースファイル名
108
109
  # @param data_dir [String, nil] データディレクトリ
109
110
  # @param templates_dir [String, nil] テンプレートディレクトリ
111
+ # @param post_render [Proc, nil] 展開結果の後段フィルタ。(text, context) -> String
110
112
  # @return [String] 展開後のテキスト
111
- def render_query(query, line_number: nil, source_filename: nil, data_dir: nil, templates_dir: nil, on_warning: nil)
113
+ def render_query(query, line_number: nil, source_filename: nil, data_dir: nil, templates_dir: nil, on_warning: nil,
114
+ post_render: nil)
112
115
  data_dir ||= configuration.data_dir
113
116
  templates_dir ||= configuration.templates_dir
114
117
  location = source_filename ? "#{source_filename}:#{line_number}" : "行#{line_number}"
@@ -178,26 +181,42 @@ module QueryStream
178
181
  template_content = File.read(template_path, encoding: 'utf-8')
179
182
 
180
183
  # --- Phase: Render ---
181
- TemplateCompiler.render(template_content, records, source_filename:, line_number:)
184
+ rendered = TemplateCompiler.render(template_content, records, source_filename:, line_number:, template_path:)
185
+
186
+ # --- Phase: Post-render filter ---
187
+ # 展開結果を呼び出し元の後段フィルタへ通す(画像パス解決など gem 外の後処理)。
188
+ # コールバックが String 以外を返した場合は安全側に倒して元の展開結果を採用する。
189
+ return rendered unless post_render
190
+
191
+ context = {
192
+ source: parsed[:source], # 記法に書かれた論理名(例: "physics_book")
193
+ data_file: data_file, # 単複解決後の実パス(例: "data/physics_books.yml")
194
+ data_dir: data_dir,
195
+ template_path: template_path,
196
+ query: query,
197
+ location: location # "filename:line" 形式
198
+ }
199
+ result = post_render.call(rendered, context)
200
+ result.is_a?(String) ? result : rendered
182
201
  end
183
202
 
184
203
  # テキスト内の QueryStream 記法を検出してリストを返す
185
204
  # @param path_or_content [String] ファイルパスまたはテキストコンテンツ
186
205
  # @return [Array<String>] 検出された QueryStream 記法のリスト
187
206
  def scan(path_or_content)
188
- content = File.exist?(path_or_content) ? File.read(path_or_content, encoding: 'utf-8') : path_or_content
207
+ content = readable_file?(path_or_content) ? File.read(path_or_content, encoding: 'utf-8') : path_or_content
189
208
  lines = content.lines
190
209
  queries = []
191
210
  in_code_block = false
192
211
 
193
212
  lines.each do |line|
194
- if line.lstrip.start_with?('```')
213
+ if code_fence?(line)
195
214
  in_code_block = !in_code_block
196
215
  next
197
216
  end
198
217
  next if in_code_block
199
218
 
200
- queries << line.chomp if line.match?(QUERY_STREAM_PATTERN)
219
+ queries << line.chomp if query_line?(line)
201
220
  end
202
221
 
203
222
  queries
@@ -205,6 +224,50 @@ module QueryStream
205
224
 
206
225
  private
207
226
 
227
+ # その行を QueryStream 記法として扱うか。
228
+ #
229
+ # **不正な UTF-8 を含む行は記法として解釈しない。** `match?` はそういう行に
230
+ # `ArgumentError: invalid byte sequence in UTF-8` を投げるので、素通しにすると
231
+ # 原稿に 1 バイトの壊れが混ざっただけで展開が丸ごと止まる。
232
+ # ここでバイト列を書き換えて(scrub して)通す手もあるが採らない——gem が黙って
233
+ # 原稿のバイト列を変えると、著者が気付けない形で本文が変わる。
234
+ # 記法として読めない行は本文として、そのまま返すのが正しい。
235
+ #
236
+ # EncodingError と ArgumentError の両方を捕まえるのは意図的である。壊れたバイト列に
237
+ # Ruby がどちらを投げるかはメソッド次第で(match? / 先頭破損の lstrip は ArgumentError、
238
+ # strip は Encoding::CompatibilityError)、その差で展開が止まってはならない。
239
+ def query_line?(line)
240
+ line.match?(QUERY_STREAM_PATTERN)
241
+ rescue EncodingError, ArgumentError
242
+ false
243
+ end
244
+
245
+ # コードフェンスの開始/終了行か。
246
+ # `lstrip` も不正な UTF-8 で ArgumentError を投げるので、query_line? と同じく
247
+ # 「読めない行は本文」へ倒す。ここを素通しにすると、記法判定だけ守っても
248
+ # 手前のフェンス判定で落ちる。
249
+ def code_fence?(line)
250
+ line.lstrip.start_with?('```')
251
+ rescue EncodingError, ArgumentError
252
+ false
253
+ end
254
+
255
+ # 引数をファイルパスとして読むべきか。
256
+ #
257
+ # `scan` はパスと本文のどちらも受け取る API なので、本文をそのまま
258
+ # `File.exist?` へ渡すと壊れる——NUL バイトを含めば `ArgumentError`、
259
+ # ディレクトリなら「存在する」と判定されて `File.read` が `Errno::EISDIR` を出す。
260
+ # パスとして成立しうる形だけを先に選別し、判定自体の失敗も本文扱いに倒す。
261
+ def readable_file?(str)
262
+ s = str.to_s
263
+ return false if s.empty? || s.include?("\0") || s.include?("\n")
264
+ return false if s.bytesize > MAX_PATH_BYTES
265
+
266
+ File.file?(s)
267
+ rescue ArgumentError, SystemCallError
268
+ false
269
+ end
270
+
208
271
  # テンプレートファイルパスを解決する
209
272
  # @param singular_name [String] 単数形のデータ名
210
273
  # @param style [String, nil] スタイル名
data/query-stream.gemspec CHANGED
@@ -17,15 +17,16 @@ Gem::Specification.new do |spec|
17
17
  spec.metadata['source_code_uri'] = 'https://github.com/Atelier-Mirai/query-stream'
18
18
  spec.metadata['changelog_uri'] = 'https://github.com/Atelier-Mirai/query-stream/blob/master/CHANGELOG.md'
19
19
 
20
- spec.required_ruby_version = '>= 4.0'
20
+ spec.required_ruby_version = '>= 3.4'
21
21
 
22
- spec.files = Dir.glob('{lib,bin}/**/*') + %w[README.md LICENSE Gemfile query-stream.gemspec]
22
+ spec.files = Dir.glob('{lib,bin}/**/*') +
23
+ %w[README.md CHANGELOG.md RELEASE_NOTE.md LICENSE Gemfile query-stream.gemspec]
23
24
  spec.bindir = 'bin'
24
25
  spec.executables = ['query-stream']
25
26
  spec.require_paths = ['lib']
26
27
 
27
28
  # Runtime dependencies
28
- spec.add_dependency 'logger'
29
+ # logger への依存は 1.4.0 で外した。gem 自身はログを出さず、失敗は構造化例外で伝える。
29
30
  spec.add_dependency 'samovar', '~> 2.1'
30
31
 
31
32
  # Development dependencies
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: query-stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atelier Mirai
@@ -9,20 +9,6 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: logger
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: samovar
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -88,9 +74,11 @@ executables:
88
74
  extensions: []
89
75
  extra_rdoc_files: []
90
76
  files:
77
+ - CHANGELOG.md
91
78
  - Gemfile
92
79
  - LICENSE
93
80
  - README.md
81
+ - RELEASE_NOTE.md
94
82
  - bin/query-stream
95
83
  - lib/query_stream.rb
96
84
  - lib/query_stream/command.rb
@@ -117,14 +105,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
105
  requirements:
118
106
  - - ">="
119
107
  - !ruby/object:Gem::Version
120
- version: '4.0'
108
+ version: '3.4'
121
109
  required_rubygems_version: !ruby/object:Gem::Requirement
122
110
  requirements:
123
111
  - - ">="
124
112
  - !ruby/object:Gem::Version
125
113
  version: '0'
126
114
  requirements: []
127
- rubygems_version: 4.0.10
115
+ rubygems_version: 4.0.16
128
116
  specification_version: 4
129
117
  summary: QueryStream - YAML/JSON data renderer with template expansion
130
118
  test_files: []