query-stream 1.0.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/Gemfile +5 -0
- data/LICENSE +41 -0
- data/README.md +115 -0
- data/bin/query-stream +7 -0
- data/lib/query_stream/command.rb +40 -0
- data/lib/query_stream/configuration.rb +35 -0
- data/lib/query_stream/data_resolver.rb +73 -0
- data/lib/query_stream/errors.rb +25 -0
- data/lib/query_stream/filter_engine.rb +136 -0
- data/lib/query_stream/query_stream_parser.rb +280 -0
- data/lib/query_stream/singularize.rb +39 -0
- data/lib/query_stream/template_compiler.rb +330 -0
- data/lib/query_stream/version.rb +5 -0
- data/lib/query_stream.rb +225 -0
- data/query-stream.gemspec +33 -0
- metadata +128 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cde26fe750e8ad95270ff7d757ace2e9401fffa40d1d4bfaef36e090dcff9e5c
|
|
4
|
+
data.tar.gz: 47628d365441535243d08a4ac109ce8e102e1401a5c14e6d31519f39948d1707
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6b795dcb38ab09d478ebab374e129d7121ff7a15e7fabba554629278cd94b2f47dda90af400f8b9a42eb87df99aa632af01edf92b3238fc1efeebe0f9ade3a3e
|
|
7
|
+
data.tar.gz: fb34d776cde2a2f7665c22bb22c446687543ee104591bee2e712dabe572c0f4b3652b8a215ce5f7890ca581705e452317510c6f256c42c2d69e65c2efd359ae8
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Atelier Mirai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# 日本語訳(参考)
|
|
26
|
+
|
|
27
|
+
MIT ライセンス
|
|
28
|
+
|
|
29
|
+
Copyright (c) 2025 Atelier Mirai
|
|
30
|
+
|
|
31
|
+
本ソフトウェアおよび関連ドキュメントファイル(以下「ソフトウェア」)の複製を取得したすべての人に対して、
|
|
32
|
+
ソフトウェアを制限なく扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複製、変更、
|
|
33
|
+
結合、公表、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供された人が
|
|
34
|
+
そうすることを許可する権利も含まれますが、それらに限定されません。
|
|
35
|
+
|
|
36
|
+
上記の著作権表示およびこの許可表示を、ソフトウェアのすべての複製または重要な部分に含めるものとします。
|
|
37
|
+
|
|
38
|
+
本ソフトウェアは「現状のまま」提供され、明示または黙示を問わず、商品性、特定目的への適合性、
|
|
39
|
+
および権利の非侵害を含むがそれらに限定されないいかなる保証もありません。
|
|
40
|
+
著作権者または権利者は、ソフトウェアに関して、契約、不法行為、またはその他の方法で
|
|
41
|
+
発生するいかなる請求、損害、責任についても責任を負いません。
|
data/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# QueryStream
|
|
2
|
+
|
|
3
|
+
YAML/JSON データファイルとテンプレートファイルを組み合わせて、テキストコンテンツ内の QueryStream 記法を展開する汎用 Ruby ライブラリ。
|
|
4
|
+
|
|
5
|
+
## インストール
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Gemfile
|
|
9
|
+
gem 'query-stream'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
bundle install
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 基本的な使い方
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
require 'query_stream'
|
|
20
|
+
|
|
21
|
+
# テキスト内の QueryStream 記法を展開
|
|
22
|
+
source = File.read('contents/05-references.md')
|
|
23
|
+
result = QueryStream.render(source)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## QueryStream 記法
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
= [源泉] | [抽出条件] | [ソート] | [件数] | [スタイル]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 例
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
= books # 全件展開
|
|
36
|
+
= books | tags=ruby # タグで絞り込み
|
|
37
|
+
= books | tags=ruby | -title | 5 # 絞り込み+降順ソート+5件
|
|
38
|
+
= book | 楽しいRuby # 主キーで一件検索
|
|
39
|
+
= books | :full # fullスタイルで展開
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 具体例:vivlio-style での書籍データ展開
|
|
43
|
+
|
|
44
|
+
#### データファイル例 (`data/books.yml`)
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
- title: 楽しいRuby
|
|
48
|
+
author:
|
|
49
|
+
name: 高橋征義
|
|
50
|
+
desc: Rubyを楽しく学べる入門書。
|
|
51
|
+
cover: ruby.webp
|
|
52
|
+
|
|
53
|
+
- title: はじめてのC
|
|
54
|
+
author:
|
|
55
|
+
name: 柴田望洋
|
|
56
|
+
desc: C言語の定番入門書。
|
|
57
|
+
cover: c.webp
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### テンプレートファイル例 (`templates/_book.md`)
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
:::{.book-card}
|
|
64
|
+

|
|
65
|
+
**=title**
|
|
66
|
+
=desc
|
|
67
|
+
:::
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Markdown記述
|
|
71
|
+
|
|
72
|
+
```markdown
|
|
73
|
+
## 参考書籍
|
|
74
|
+
|
|
75
|
+
= books
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### 展開結果
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
## 参考書籍
|
|
84
|
+
|
|
85
|
+
:::{.book-card}
|
|
86
|
+

|
|
87
|
+
**楽しいRuby**
|
|
88
|
+
Rubyを楽しく学べる入門書。
|
|
89
|
+
:::
|
|
90
|
+
|
|
91
|
+
:::{.book-card}
|
|
92
|
+

|
|
93
|
+
**はじめてのC**
|
|
94
|
+
C言語の定番入門書。
|
|
95
|
+
:::
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
VFMフェンス記法(`:::{.book-card}`)にも対応しており、各レコードが個別のフェンスで囲まれて展開されます。
|
|
101
|
+
|
|
102
|
+
## 設定
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
QueryStream.configure do |config|
|
|
106
|
+
config.data_dir = 'data'
|
|
107
|
+
config.templates_dir = 'templates'
|
|
108
|
+
config.default_format = :md
|
|
109
|
+
config.logger = Logger.new($stdout)
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## ライセンス
|
|
114
|
+
|
|
115
|
+
MIT License
|
data/bin/query-stream
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'samovar'
|
|
4
|
+
|
|
5
|
+
# ================================================================
|
|
6
|
+
# File: lib/query_stream/command.rb
|
|
7
|
+
# ================================================================
|
|
8
|
+
# 責務:
|
|
9
|
+
# QueryStream の CLI コマンド。--version のみ提供する。
|
|
10
|
+
# ================================================================
|
|
11
|
+
|
|
12
|
+
module QueryStream
|
|
13
|
+
module Command
|
|
14
|
+
# トップレベルコマンド
|
|
15
|
+
class Top < Samovar::Command
|
|
16
|
+
self.description = 'QueryStream - YAML/JSON data renderer'
|
|
17
|
+
|
|
18
|
+
options do
|
|
19
|
+
option '--version', 'Print version and exit'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# コマンド実行
|
|
23
|
+
def call
|
|
24
|
+
if @options[:version]
|
|
25
|
+
puts "query-stream #{QueryStream::VERSION}"
|
|
26
|
+
else
|
|
27
|
+
print_usage
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
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"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
# ================================================================
|
|
6
|
+
# File: lib/query_stream/configuration.rb
|
|
7
|
+
# ================================================================
|
|
8
|
+
# 責務:
|
|
9
|
+
# QueryStream のグローバル設定を管理する。
|
|
10
|
+
# data_dir, templates_dir, default_format, logger の4項目。
|
|
11
|
+
# ================================================================
|
|
12
|
+
|
|
13
|
+
module QueryStream
|
|
14
|
+
# グローバル設定クラス
|
|
15
|
+
class Configuration
|
|
16
|
+
# @return [String] データファイルのディレクトリ
|
|
17
|
+
attr_accessor :data_dir
|
|
18
|
+
|
|
19
|
+
# @return [String] テンプレートファイルのディレクトリ
|
|
20
|
+
attr_accessor :templates_dir
|
|
21
|
+
|
|
22
|
+
# @return [Symbol] スタイル省略時のデフォルト出力形式(:md / :html / :json)
|
|
23
|
+
attr_accessor :default_format
|
|
24
|
+
|
|
25
|
+
# @return [Logger] ログ出力先
|
|
26
|
+
attr_accessor :logger
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
@data_dir = 'data'
|
|
30
|
+
@templates_dir = 'templates'
|
|
31
|
+
@default_format = :md
|
|
32
|
+
@logger = Logger.new($stdout)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
# ================================================================
|
|
7
|
+
# File: lib/query_stream/data_resolver.rb
|
|
8
|
+
# ================================================================
|
|
9
|
+
# 責務:
|
|
10
|
+
# データファイルの探索・単数形/複数形の自動解決を行う。
|
|
11
|
+
# YAML (.yml, .yaml) と JSON (.json) をサポートする。
|
|
12
|
+
# ================================================================
|
|
13
|
+
|
|
14
|
+
module QueryStream
|
|
15
|
+
# データファイル探索・読み込みモジュール
|
|
16
|
+
module DataResolver
|
|
17
|
+
# サポートする拡張子(優先順位順)
|
|
18
|
+
EXTENSIONS = %w[.yml .yaml .json].freeze
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
# データファイルのパスを解決する
|
|
23
|
+
# 指定名そのまま → 複数形(末尾に s を付与)→ 単数形の順で探索する
|
|
24
|
+
# @param source_name [String] データ名(単数形または複数形)
|
|
25
|
+
# @param data_dir [String] データディレクトリ
|
|
26
|
+
# @return [String, nil] 見つかったファイルパス、または nil
|
|
27
|
+
def resolve(source_name, data_dir)
|
|
28
|
+
# そのまま試行
|
|
29
|
+
found = find_with_extensions(source_name, data_dir)
|
|
30
|
+
return found if found
|
|
31
|
+
|
|
32
|
+
# 複数形を試行(単数形→複数形: book → books)
|
|
33
|
+
found = find_with_extensions("#{source_name}s", data_dir)
|
|
34
|
+
return found if found
|
|
35
|
+
|
|
36
|
+
# 単数形を試行(複数形→単数形: books → book)
|
|
37
|
+
singular = Singularize.call(source_name)
|
|
38
|
+
if singular != source_name
|
|
39
|
+
found = find_with_extensions(singular, data_dir)
|
|
40
|
+
return found if found
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# レコード群をファイルから読み込む
|
|
47
|
+
# @param file_path [String] データファイルパス
|
|
48
|
+
# @return [Array<Hash>] レコード群(シンボルキー)
|
|
49
|
+
def load_records(file_path)
|
|
50
|
+
records = case File.extname(file_path).downcase
|
|
51
|
+
when '.json'
|
|
52
|
+
JSON.parse(File.read(file_path, encoding: 'utf-8'), symbolize_names: true)
|
|
53
|
+
else
|
|
54
|
+
YAML.load_file(file_path, symbolize_names: true)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
records = [records] if records.is_a?(Hash)
|
|
58
|
+
records
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# 指定名ですべての拡張子を試行する
|
|
62
|
+
# @param base_name [String] 拡張子なしファイル名
|
|
63
|
+
# @param data_dir [String] データディレクトリ
|
|
64
|
+
# @return [String, nil] 見つかったファイルパス、または nil
|
|
65
|
+
def find_with_extensions(base_name, data_dir)
|
|
66
|
+
EXTENSIONS.each do |ext|
|
|
67
|
+
path = File.join(data_dir, "#{base_name}#{ext}")
|
|
68
|
+
return path if File.exist?(path)
|
|
69
|
+
end
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ================================================================
|
|
4
|
+
# File: lib/query_stream/errors.rb
|
|
5
|
+
# ================================================================
|
|
6
|
+
# 責務:
|
|
7
|
+
# QueryStream の例外クラス体系を定義する。
|
|
8
|
+
# ERROR系は処理を中断し、WARNING系は処理を続行する。
|
|
9
|
+
# ================================================================
|
|
10
|
+
|
|
11
|
+
module QueryStream
|
|
12
|
+
# 基底クラス
|
|
13
|
+
class Error < StandardError; end
|
|
14
|
+
class Warning < StandardError; end
|
|
15
|
+
|
|
16
|
+
# ERROR系(処理を中断)
|
|
17
|
+
class TemplateNotFoundError < Error; end # テンプレートファイルが存在しない
|
|
18
|
+
class DataNotFoundError < Error; end # データファイルが存在しない
|
|
19
|
+
class UnknownKeyError < Error; end # テンプレート内に存在しないキー
|
|
20
|
+
class InvalidDateError < Error; end # 無効な日付
|
|
21
|
+
|
|
22
|
+
# WARNING系(処理を続行)
|
|
23
|
+
class AmbiguousQueryWarning < Warning; end # 一件検索で複数件ヒット
|
|
24
|
+
class NoResultWarning < Warning; end # 一件検索で0件ヒット
|
|
25
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'date'
|
|
4
|
+
|
|
5
|
+
# ================================================================
|
|
6
|
+
# File: lib/query_stream/filter_engine.rb
|
|
7
|
+
# ================================================================
|
|
8
|
+
# 責務:
|
|
9
|
+
# AND/OR/比較/Range によるフィルタリングとソート処理を行う。
|
|
10
|
+
# 日付の自動正規化にも対応する。
|
|
11
|
+
# ================================================================
|
|
12
|
+
|
|
13
|
+
module QueryStream
|
|
14
|
+
# フィルタリング&ソートエンジンモジュール
|
|
15
|
+
module FilterEngine
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# フィルタ条件をレコード群に適用する
|
|
19
|
+
# @param records [Array<Hash>] レコード群
|
|
20
|
+
# @param filters [Array<Hash>] フィルタ条件の配列
|
|
21
|
+
# @return [Array<Hash>] フィルタ後のレコード群
|
|
22
|
+
def apply_filters(records, filters)
|
|
23
|
+
return records if filters.nil? || filters.empty?
|
|
24
|
+
|
|
25
|
+
records.select do |record|
|
|
26
|
+
filters.all? { evaluate_filter(record, it) }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# ソート条件を適用する
|
|
31
|
+
# @param records [Array<Hash>] レコード群
|
|
32
|
+
# @param sort [Hash] ソート条件 { field:, direction: }
|
|
33
|
+
# @return [Array<Hash>] ソート後のレコード群
|
|
34
|
+
def apply_sort(records, sort)
|
|
35
|
+
sorted = records.sort_by { to_comparable(it[sort[:field]]) }
|
|
36
|
+
sort[:direction] == :desc ? sorted.reverse : sorted
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# 単一フィルタ条件をレコードに対して評価する
|
|
40
|
+
# @param record [Hash] 単一レコード
|
|
41
|
+
# @param filter [Hash] フィルタ条件 { field:, op:, value: }
|
|
42
|
+
# @return [Boolean] 条件に合致するか
|
|
43
|
+
def evaluate_filter(record, filter)
|
|
44
|
+
# 主キー検索(_primary_key)の特別処理
|
|
45
|
+
if filter[:field] == :_primary_key
|
|
46
|
+
return evaluate_primary_key_lookup(record, filter[:value])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
field_value = record[filter[:field]]
|
|
50
|
+
|
|
51
|
+
case filter[:op]
|
|
52
|
+
when :eq
|
|
53
|
+
match_eq(field_value, filter[:value])
|
|
54
|
+
when :neq
|
|
55
|
+
!match_eq(field_value, filter[:value])
|
|
56
|
+
when :gt
|
|
57
|
+
to_comparable(field_value) > to_comparable(filter[:value])
|
|
58
|
+
when :gte
|
|
59
|
+
to_comparable(field_value) >= to_comparable(filter[:value])
|
|
60
|
+
when :lt
|
|
61
|
+
to_comparable(field_value) < to_comparable(filter[:value])
|
|
62
|
+
when :lte
|
|
63
|
+
to_comparable(field_value) <= to_comparable(filter[:value])
|
|
64
|
+
when :range
|
|
65
|
+
range = filter[:value]
|
|
66
|
+
range.cover?(to_comparable(field_value))
|
|
67
|
+
else
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# 主キー候補フィールドを順番に走査して一致するものを探す
|
|
73
|
+
# @param record [Hash] 単一レコード
|
|
74
|
+
# @param query_value [Object] 検索値
|
|
75
|
+
# @return [Boolean] いずれかの主キー候補と一致するか
|
|
76
|
+
def evaluate_primary_key_lookup(record, query_value)
|
|
77
|
+
QueryStreamParser::PRIMARY_KEY_FIELDS.any? do |key|
|
|
78
|
+
record[key]&.to_s == query_value.to_s
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# 等値比較(配列・カンマ区切り文字列を透過的に扱う)
|
|
83
|
+
# データ側が配列/カンマ区切りの場合、ORの値リストと交差判定する
|
|
84
|
+
def match_eq(field_value, filter_values)
|
|
85
|
+
field_list = normalize_to_list(field_value)
|
|
86
|
+
value_list = Array(filter_values).map { it.to_s.strip }
|
|
87
|
+
|
|
88
|
+
# フィールド側の値リストと条件値リストに交差があれば一致
|
|
89
|
+
(field_list & value_list).any?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# フィールド値をリスト化する(配列/カンマ区切り/単値を統一)
|
|
93
|
+
def normalize_to_list(value)
|
|
94
|
+
case value
|
|
95
|
+
when Array
|
|
96
|
+
value.map { it.to_s.strip }
|
|
97
|
+
when String
|
|
98
|
+
value.split(',').map { it.strip }
|
|
99
|
+
when nil
|
|
100
|
+
[]
|
|
101
|
+
else
|
|
102
|
+
[value.to_s.strip]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# 比較用に値を正規化する(数値変換・日付変換を試みる)
|
|
107
|
+
def to_comparable(value)
|
|
108
|
+
case value
|
|
109
|
+
when Date, Time
|
|
110
|
+
value
|
|
111
|
+
when String
|
|
112
|
+
# 日付形式(YYYY-MM-DD)を検出して Date に変換
|
|
113
|
+
if value.match?(/\A\d{4}-\d{2}-\d{2}\z/)
|
|
114
|
+
begin
|
|
115
|
+
return Date.parse(value)
|
|
116
|
+
rescue Date::Error
|
|
117
|
+
raise InvalidDateError, "無効な日付: #{value}"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
# 数値変換を試みる
|
|
121
|
+
case value
|
|
122
|
+
when /\A-?\d+\z/
|
|
123
|
+
value.to_i
|
|
124
|
+
when /\A-?\d+\.\d+\z/
|
|
125
|
+
value.to_f
|
|
126
|
+
else
|
|
127
|
+
value
|
|
128
|
+
end
|
|
129
|
+
when Integer, Float
|
|
130
|
+
value
|
|
131
|
+
else
|
|
132
|
+
value.to_s
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|