Module: QueryStream
- Defined in:
- lib/query_stream/errors.rb,
lib/query_stream.rb,
lib/query_stream/command.rb,
lib/query_stream/version.rb,
lib/query_stream/singularize.rb,
lib/query_stream/configuration.rb,
lib/query_stream/data_resolver.rb,
lib/query_stream/filter_engine.rb,
lib/query_stream/template_compiler.rb,
lib/query_stream/query_stream_parser.rb
Overview
File: lib/query_stream/query_stream_parser.rb
責務:
QueryStream
パイプライン:
1. Source -
トークンの自動判別:
Defined Under Namespace
Modules: Command, DataResolver, FilterEngine, QueryStreamParser, Singularize, TemplateCompiler Classes: AmbiguousQueryWarning, Configuration, DataNotFoundError, Error, InvalidDateError, NoResultWarning, TemplateNotFoundError, UnknownKeyError, Warning
Constant Summary collapse
- QUERY_STREAM_PATTERN =
QueryStream 記法を検出する正規表現行頭 = の直後に英数字/ハイフン/アンダースコアのデータ名(スペースは任意)
/^=\s*([a-zA-Z][a-zA-Z0-9_-]*)(?:\s*\|.*)?$/- VERSION =
'1.0.0'
Class Method Summary collapse
-
.configuration ⇒ Configuration
グローバル設定を返す.
-
.configure {|Configuration| ... } ⇒ Object
設定をブロックで変更する.
-
.logger ⇒ Logger
ロガーへのショートカット.
-
.render(content, source_filename: nil, data_dir: nil, templates_dir: nil) ⇒ String
テキストコンテンツ内の QueryStream 記法をすべて展開する.
-
.render_query(query, line_number: nil, source_filename: nil, data_dir: nil, templates_dir: nil) ⇒ String
単一の QueryStream 記法を展開する.
-
.scan(path_or_content) ⇒ Array<String>
テキスト内の QueryStream 記法を検出してリストを返す.
Class Method Details
.configuration ⇒ Configuration
グローバル設定を返す
35 36 37 |
# File 'lib/query_stream.rb', line 35 def configuration @configuration ||= Configuration.new end |
.configure {|Configuration| ... } ⇒ Object
設定をブロックで変更する
41 42 43 |
# File 'lib/query_stream.rb', line 41 def configure yield(configuration) end |
.logger ⇒ Logger
ロガーへのショートカット
47 48 49 |
# File 'lib/query_stream.rb', line 47 def logger configuration.logger end |
.render(content, source_filename: nil, data_dir: nil, templates_dir: nil) ⇒ String
テキストコンテンツ内の QueryStream 記法をすべて展開する
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/query_stream.rb', line 57 def render(content, source_filename: nil, data_dir: nil, templates_dir: nil) data_dir ||= configuration.data_dir templates_dir ||= configuration.templates_dir lines = content.lines result = [] in_code_block = false lines.each_with_index do |line, idx| line_number = idx + 1 # コードブロック内はスキップ if line.lstrip.start_with?('```') in_code_block = !in_code_block result << line next end if in_code_block result << line next end # QueryStream 記法の検出 if line.match?(QUERY_STREAM_PATTERN) = render_query( line.chomp, line_number:, source_filename:, data_dir:, templates_dir: ) result << << "\n" else result << line end end result.join end |
.render_query(query, line_number: nil, source_filename: nil, data_dir: nil, templates_dir: nil) ⇒ String
単一の QueryStream 記法を展開する
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/query_stream.rb', line 101 def render_query(query, line_number: nil, source_filename: nil, data_dir: nil, templates_dir: nil) data_dir ||= configuration.data_dir templates_dir ||= configuration.templates_dir location = source_filename ? "#{source_filename}:#{line_number}" : "行#{line_number}" # --- Phase: Parse --- parsed = QueryStreamParser.parse(query) # --- Phase: Load Data --- data_file = DataResolver.resolve(parsed[:source], data_dir) unless data_file expected = File.join(data_dir, "#{parsed[:source]}.yml") logger.error("データファイルが見つかりません(#{location})") logger.error(" 記法: #{query}") logger.error(" 期待: #{expected}") raise DataNotFoundError, "データファイルが見つかりません: #{expected}" end records = DataResolver.load_records(data_file) # --- Phase: Filter --- records = FilterEngine.apply_filters(records, parsed[:filters]) # --- Phase: Sort --- records = FilterEngine.apply_sort(records, parsed[:sort]) if parsed[:sort] # --- Phase: Limit --- records = records.first(parsed[:limit]) if parsed[:limit] # --- Phase: Single record warning --- if parsed[:single_lookup] case records.size when 0 logger.warn("一件検索で該当なし(#{location}): #{query}") return '' when 1 # 正常 else logger.warn("一件検索で複数件ヒット(#{location}): #{query}") logger.warn(" #{records.size}件見つかりました。条件を明示してください。") end end # --- Phase: Resolve Template --- singular = Singularize.call(parsed[:source]) style = parsed[:style] format = parsed[:format] template_path = resolve_template_path(singular, style, format, templates_dir) unless File.exist?(template_path) hint = build_template_hint(singular, style, format, templates_dir) logger.error("テンプレートファイルが見つかりません(#{location})") logger.error(" 記法: #{query}") logger.error(" 期待: #{template_path}") logger.error(" ヒント: #{hint}") if hint raise TemplateNotFoundError, "テンプレートファイルが見つかりません: #{template_path}" end template_content = File.read(template_path, encoding: 'utf-8') # --- Phase: Render --- TemplateCompiler.render(template_content, records, source_filename:, line_number:) end |
.scan(path_or_content) ⇒ Array<String>
テキスト内の QueryStream 記法を検出してリストを返す
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/query_stream.rb', line 168 def scan(path_or_content) content = File.exist?(path_or_content) ? File.read(path_or_content, encoding: 'utf-8') : path_or_content lines = content.lines queries = [] in_code_block = false lines.each do |line| if line.lstrip.start_with?('```') in_code_block = !in_code_block next end next if in_code_block queries << line.chomp if line.match?(QUERY_STREAM_PATTERN) end queries end |