| 1 | |
|---|
| 2 | require 'wikiforme/inline' |
|---|
| 3 | require 'wikiforme/block' |
|---|
| 4 | require 'wikiforme/syntax' |
|---|
| 5 | require 'wikiforme/xml' |
|---|
| 6 | require 'wikiforme/syntax_extend' |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | module Format |
|---|
| 10 | # replace可能な定数 |
|---|
| 11 | class ConstVariable |
|---|
| 12 | attr_accessor :obj |
|---|
| 13 | def initialize(obj = nil) |
|---|
| 14 | @obj = obj |
|---|
| 15 | end |
|---|
| 16 | def replace(obj = true) |
|---|
| 17 | @obj = obj |
|---|
| 18 | end |
|---|
| 19 | alias :set :replace |
|---|
| 20 | def method_missing(name, *args) |
|---|
| 21 | @obj.__send__(name, *args) |
|---|
| 22 | end |
|---|
| 23 | def inspect |
|---|
| 24 | @obj.inspect |
|---|
| 25 | end |
|---|
| 26 | def unset |
|---|
| 27 | @obj = nil |
|---|
| 28 | end |
|---|
| 29 | def set? |
|---|
| 30 | !@obj.nil? |
|---|
| 31 | end |
|---|
| 32 | end |
|---|
| 33 | |
|---|
| 34 | def self.reset(block_base, inline_base) |
|---|
| 35 | @@block_base = block_base |
|---|
| 36 | @@inline_base = inline_base |
|---|
| 37 | @@block = Hash.new |
|---|
| 38 | @@block_ordered = Array.new |
|---|
| 39 | @@inline = Hash.new |
|---|
| 40 | @@inline_ordered = Array.new |
|---|
| 41 | @@escape_proc = Hash.new |
|---|
| 42 | @@suffix = Hash.new |
|---|
| 43 | @@default_root = nil |
|---|
| 44 | @@default_root_text = nil |
|---|
| 45 | @@init_procs = [] |
|---|
| 46 | end |
|---|
| 47 | def self.block_elements |
|---|
| 48 | return @@block, @@block_ordered |
|---|
| 49 | end |
|---|
| 50 | def self.inline_elements |
|---|
| 51 | return @@inline, @@inline_ordered |
|---|
| 52 | end |
|---|
| 53 | def self.escape_proc |
|---|
| 54 | @@escape_proc |
|---|
| 55 | end |
|---|
| 56 | def self.suffix |
|---|
| 57 | @@suffix |
|---|
| 58 | end |
|---|
| 59 | def self.default_root |
|---|
| 60 | @@default_root |
|---|
| 61 | end |
|---|
| 62 | def self.default_root_text |
|---|
| 63 | @@default_root_text |
|---|
| 64 | end |
|---|
| 65 | def self.init_procs |
|---|
| 66 | @@init_procs |
|---|
| 67 | end |
|---|
| 68 | |
|---|
| 69 | # ブロック要素を作成 |
|---|
| 70 | def self.block(name = nil, base_element = nil) |
|---|
| 71 | return @@block if !name |
|---|
| 72 | # FIXME extendの実装が、記述順に依存してしまっている |
|---|
| 73 | # extend元の要素は先に定義されている必要がある |
|---|
| 74 | name = name.to_sym |
|---|
| 75 | if @@block.include?(name) |
|---|
| 76 | return @@block[name] |
|---|
| 77 | end |
|---|
| 78 | if base_element |
|---|
| 79 | if !@@block.include?(base_element.to_sym) |
|---|
| 80 | # FIXME エラーメッセージ |
|---|
| 81 | raise WikiForme::FormatLoadError, "Base element :#{base_element} is not declared: :#{name}" # MSG |
|---|
| 82 | end |
|---|
| 83 | element = @@block[name] = Class.new(@@block[base_element.to_sym]) |
|---|
| 84 | else |
|---|
| 85 | element = @@block[name] = Class.new(@@block_base) |
|---|
| 86 | end |
|---|
| 87 | element.module_eval { |
|---|
| 88 | const_set(:BLOCK_ELEMENT, true) |
|---|
| 89 | const_set(:BLOCK_GROUP, false) |
|---|
| 90 | const_set(:INLINE_ELEMENT, false) |
|---|
| 91 | # 要素名: Symbol |
|---|
| 92 | const_set(:NAME, name) |
|---|
| 93 | # 包含可能要素: SymbolのArray |
|---|
| 94 | # CONTAIN_NAMESは継承する |
|---|
| 95 | if defined? self::CONTAIN_NAMES |
|---|
| 96 | const_set(:CONTAIN_NAMES, self::CONTAIN_NAMES.dup) |
|---|
| 97 | else |
|---|
| 98 | const_set(:CONTAIN_NAMES, []) |
|---|
| 99 | end |
|---|
| 100 | const_set(:CONTAIN, []) # ClassのArray |
|---|
| 101 | # 包含不可能要素: SymbolのArray |
|---|
| 102 | # UNCONTAIN_NAMESは継承する |
|---|
| 103 | if defined? self::UNCONTAIN_NAMES |
|---|
| 104 | const_set(:UNCONTAIN_NAMES, self::UNCONTAIN_NAMES.dup) |
|---|
| 105 | else |
|---|
| 106 | const_set(:UNCONTAIN_NAMES, []) |
|---|
| 107 | end |
|---|
| 108 | const_set(:UNCONTAIN, []) # ClassのArray |
|---|
| 109 | # 所属グループの定義: SymbolのArray(@から始まる) |
|---|
| 110 | # GROUP_NAMESは継承する |
|---|
| 111 | if defined? self::GROUP_NAMES |
|---|
| 112 | const_set(:GROUP_NAMES, self::GROUP_NAMES.dup) |
|---|
| 113 | else |
|---|
| 114 | const_set(:GROUP_NAMES, []) |
|---|
| 115 | end |
|---|
| 116 | # 親要素: Symbolかnil |
|---|
| 117 | # PARENT_COMPLETION_NAMEは継承する |
|---|
| 118 | if defined? self::PARENT_COMPLETION_NAME |
|---|
| 119 | const_set(:PARENT_COMPLETION_NAME, self::PARENT_COMPLETION_NAME.dup) |
|---|
| 120 | else |
|---|
| 121 | const_set(:PARENT_COMPLETION_NAME, ConstVariable.new) |
|---|
| 122 | end |
|---|
| 123 | const_set(:PARENT_COMPLETION, ConstVariable.new) # Classかnil |
|---|
| 124 | # デフォルトシンタックス: 文字列かnilかSymbol(:text, :blank) |
|---|
| 125 | const_set(:DEFAULT_SYNTAX, ConstVariable.new) |
|---|
| 126 | # multiline要素の終了マーク: 文字列かnil |
|---|
| 127 | # MULTILINEは継承する |
|---|
| 128 | if defined? self::MULTILINE |
|---|
| 129 | const_set(:MULTILINE, self::MULTILINE.dup) |
|---|
| 130 | else |
|---|
| 131 | const_set(:MULTILINE, ConstVariable.new) |
|---|
| 132 | end |
|---|
| 133 | # closer要素か否か: trueかnil |
|---|
| 134 | # CLOSERは継承する |
|---|
| 135 | if defined? self::CLOSER |
|---|
| 136 | const_set(:CLOSER, self::CLOSER.dup) |
|---|
| 137 | else |
|---|
| 138 | const_set(:CLOSER, ConstVariable.new) |
|---|
| 139 | end |
|---|
| 140 | } |
|---|
| 141 | @@block_ordered.push(element) |
|---|
| 142 | element |
|---|
| 143 | end |
|---|
| 144 | |
|---|
| 145 | # インライン要素を作成 |
|---|
| 146 | def self.inline(name = nil, base_element = nil) |
|---|
| 147 | return @@block if !name |
|---|
| 148 | # FIXME extendの実装が、記述順に依存してしまっている |
|---|
| 149 | # extend元の要素は先に定義されている必要がある |
|---|
| 150 | name = name.to_sym |
|---|
| 151 | if @@inline.include?(name) |
|---|
| 152 | return @@inline[name] |
|---|
| 153 | end |
|---|
| 154 | if base_element |
|---|
| 155 | if !@@inline.include?(base_element.to_sym) |
|---|
| 156 | raise WikiForme::FormatLoadError, "Base element :#{base_element} is not declared: :#{name}" # MSG |
|---|
| 157 | end |
|---|
| 158 | element = @@inline[name] = Class.new(@@inline[base_element.to_sym]) |
|---|
| 159 | else |
|---|
| 160 | element = @@inline[name] = Class.new(@@inline_base) |
|---|
| 161 | end |
|---|
| 162 | element.module_eval { |
|---|
| 163 | const_set(:BLOCK_ELEMENT, false) |
|---|
| 164 | const_set(:BLOCK_GROUP, false) |
|---|
| 165 | const_set(:INLINE_ELEMENT, true) |
|---|
| 166 | # 要素名: Symbol |
|---|
| 167 | const_set(:NAME, name) |
|---|
| 168 | # デフォルトシンタックス: 文字列の配列かnil |
|---|
| 169 | const_set(:DEFAULT_SYNTAX, ConstVariable.new) |
|---|
| 170 | # Regexp要素なら正規表現: Regexpかnil |
|---|
| 171 | # REGEXPは継承する |
|---|
| 172 | if defined? self::REGEXP |
|---|
| 173 | const_set(:REGEXP, self::REGEXP.dup) |
|---|
| 174 | else |
|---|
| 175 | const_set(:REGEXP, ConstVariable.new) |
|---|
| 176 | end |
|---|
| 177 | } |
|---|
| 178 | @@inline_ordered.push(element) |
|---|
| 179 | element |
|---|
| 180 | end |
|---|
| 181 | |
|---|
| 182 | # 初期化メソッドを登録 |
|---|
| 183 | def self.initialize(&proc) |
|---|
| 184 | @@init_procs.push(proc) |
|---|
| 185 | end |
|---|
| 186 | |
|---|
| 187 | # デフォルトのルート要素を定義 |
|---|
| 188 | def self.default_root=(sym) |
|---|
| 189 | @@default_root = sym.to_sym |
|---|
| 190 | end |
|---|
| 191 | |
|---|
| 192 | # ルート要素のデフォルトテキストを定義 |
|---|
| 193 | def self.default_root_text=(text) |
|---|
| 194 | @@default_root_text = text.to_s |
|---|
| 195 | end |
|---|
| 196 | |
|---|
| 197 | # escape_*, suffix_* を指定 |
|---|
| 198 | def self.method_missing(name, *args) |
|---|
| 199 | if name.to_s =~ /escape_([^=]+)=?/ |
|---|
| 200 | if args.length == 0 |
|---|
| 201 | if block_given? |
|---|
| 202 | @@escape_proc[$~[1].to_sym] = Proc.new {|rtext| |
|---|
| 203 | yield rtext |
|---|
| 204 | } |
|---|
| 205 | end |
|---|
| 206 | return @@escape_proc[$~[1].to_sym] |
|---|
| 207 | elsif args.length == 1 |
|---|
| 208 | return @@escape_proc[$~[1].to_sym] = args[0] |
|---|
| 209 | end |
|---|
| 210 | elsif name.to_s =~ /suffix_([^=]+)=?/ |
|---|
| 211 | if args.length == 0 |
|---|
| 212 | return @@suffix[$~[1].to_sym] |
|---|
| 213 | elsif args.length == 1 |
|---|
| 214 | return @@suffix[$~[1].to_sym] = args[0].to_s |
|---|
| 215 | end |
|---|
| 216 | end |
|---|
| 217 | raise NameError, "undefined method `#{name}' for #{self.inspect}:#{self.class}" |
|---|
| 218 | end |
|---|
| 219 | end |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | class WikiForme::ParserParameters |
|---|
| 223 | def _set(params, format, block, inline, block_base, inline_base) |
|---|
| 224 | @params = params || {} |
|---|
| 225 | @format = format |
|---|
| 226 | @block = block |
|---|
| 227 | @inline = inline |
|---|
| 228 | @block_base = block_base |
|---|
| 229 | @inline_base = inline_base |
|---|
| 230 | end |
|---|
| 231 | attr_reader :params, :format, :block, :inline, :block_base, :inline_base |
|---|
| 232 | def [](key) |
|---|
| 233 | params[key] |
|---|
| 234 | end |
|---|
| 235 | end |
|---|
| 236 | Parser = WikiForme::ParserParameters.new |
|---|
| 237 | |
|---|
| 238 | |
|---|
| 239 | module WikiForme |
|---|
| 240 | GROUP_NAME_REGEXP = /@(.*)/ |
|---|
| 241 | FORMAT_BUNDLE_SUFFIX = '4me' |
|---|
| 242 | FORMAT_BUNDLE_REGEXP = /(.*)\.#{FORMAT_BUNDLE_SUFFIX}$/ |
|---|
| 243 | FORMAT_FILE_REGEXP = /\.rb$/ |
|---|
| 244 | SYNTAX_FILE_REGEXP = /\.yaml$/ |
|---|
| 245 | end |
|---|
| 246 | |
|---|
| 247 | |
|---|
| 248 | class WikiForme::AssembleScope |
|---|
| 249 | def initialize(params, block_parser, inline_parser) |
|---|
| 250 | @params = params |
|---|
| 251 | @block_parser = block_parser |
|---|
| 252 | @inline_parser = inline_parser |
|---|
| 253 | end |
|---|
| 254 | attr_reader :params, :block_parser, :inline_parser |
|---|
| 255 | end |
|---|
| 256 | |
|---|
| 257 | |
|---|
| 258 | class WikiForme::ProcessScope |
|---|
| 259 | def initialize(format_type) |
|---|
| 260 | @format_type = format_type |
|---|
| 261 | end |
|---|
| 262 | attr_reader :format_type |
|---|
| 263 | end |
|---|
| 264 | |
|---|
| 265 | |
|---|
| 266 | module WikiForme; class FormatLoader |
|---|
| 267 | attr_reader :block, :group, :inline, :syntax |
|---|
| 268 | attr_reader :block_ordered, :inline_ordered |
|---|
| 269 | attr_reader :escape_proc, :default_root, :default_root_text |
|---|
| 270 | attr_reader :suffix |
|---|
| 271 | attr_reader :block_base, :inline_base |
|---|
| 272 | def initialize(root_bundle) |
|---|
| 273 | @block_base = Class.new(BlockElement) |
|---|
| 274 | @inline_base = Class.new(InlineElement) |
|---|
| 275 | Format.reset(@block_base, @inline_base) |
|---|
| 276 | |
|---|
| 277 | # 記法バンドル内のsyntax.yamlファイルのリスト |
|---|
| 278 | @syntax_files = [] |
|---|
| 279 | |
|---|
| 280 | # 記法バンドルをロード |
|---|
| 281 | ::Parser._set(nil, |
|---|
| 282 | nil, |
|---|
| 283 | nil, |
|---|
| 284 | nil, |
|---|
| 285 | @block_base, |
|---|
| 286 | @inline_base ) |
|---|
| 287 | load_format(root_bundle, 0) |
|---|
| 288 | |
|---|
| 289 | # ブロック要素のリスト |
|---|
| 290 | @block, @block_ordered = Format.block_elements |
|---|
| 291 | |
|---|
| 292 | # インライン要素のリスト |
|---|
| 293 | @inline, @inline_ordered = Format.inline_elements |
|---|
| 294 | |
|---|
| 295 | # ブロック要素グループのリスト |
|---|
| 296 | @group = {} |
|---|
| 297 | |
|---|
| 298 | # エスケープメソッド |
|---|
| 299 | @escape_proc = Format.escape_proc |
|---|
| 300 | |
|---|
| 301 | # 出力先ファイルのデフォルト拡張子 |
|---|
| 302 | @suffix = Format.suffix |
|---|
| 303 | |
|---|
| 304 | # デフォルトのルート要素 |
|---|
| 305 | @default_root = Format.default_root |
|---|
| 306 | |
|---|
| 307 | # ルート要素のデフォルトテキスト |
|---|
| 308 | @default_root_text = Format.default_root_text |
|---|
| 309 | |
|---|
| 310 | # 初期化メソッド群 |
|---|
| 311 | @init_procs = Format.init_procs |
|---|
| 312 | |
|---|
| 313 | resolve # 要素名から要素クラスを解決 |
|---|
| 314 | |
|---|
| 315 | # デフォルト文法とカスタマイズ文法をマージ |
|---|
| 316 | @syntax = SyntaxLoader.new(self, @syntax_files) |
|---|
| 317 | end |
|---|
| 318 | |
|---|
| 319 | # Assembleの前とProcessの前に呼ばれる |
|---|
| 320 | # Assembleの前はprocess_scope = nil |
|---|
| 321 | def set_scope(assemble_scope, process_scope = nil) |
|---|
| 322 | ::Parser._set(assemble_scope.params, |
|---|
| 323 | self, |
|---|
| 324 | assemble_scope.block_parser, |
|---|
| 325 | assemble_scope.inline_parser, |
|---|
| 326 | @block_base, |
|---|
| 327 | @inline_base ) |
|---|
| 328 | if process_scope |
|---|
| 329 | @block_base.format_type = process_scope.format_type |
|---|
| 330 | @inline_base.format_type = process_scope.format_type |
|---|
| 331 | assemble_scope.inline_parser.format_type = process_scope.format_type |
|---|
| 332 | else |
|---|
| 333 | # assemble時にinit_procsを呼ぶ |
|---|
| 334 | @init_procs.each{|proc| proc.call} |
|---|
| 335 | end |
|---|
| 336 | end |
|---|
| 337 | |
|---|
| 338 | def supported_format |
|---|
| 339 | supported = {} |
|---|
| 340 | basemethods = Object.public_instance_methods |
|---|
| 341 | @block.each_value {|e| |
|---|
| 342 | (e.public_instance_methods - basemethods).each {|m| |
|---|
| 343 | if m =~ /process_(.*)/ |
|---|
| 344 | supported[$~[1]] = true |
|---|
| 345 | end |
|---|
| 346 | } |
|---|
| 347 | } |
|---|
| 348 | @inline.each_value {|e| |
|---|
| 349 | (e.public_instance_methods - basemethods).each {|m| |
|---|
| 350 | if m =~ /(?:process_|expand_)(.*)/ |
|---|
| 351 | supported[$~[1]] = true |
|---|
| 352 | end |
|---|
| 353 | } |
|---|
| 354 | } |
|---|
| 355 | supported.keys.map {|m| m.to_sym} |
|---|
| 356 | end |
|---|
| 357 | |
|---|
| 358 | private |
|---|
| 359 | # .4meディレクトリを再帰的に潜る |
|---|
| 360 | def load_format(dir, depth) |
|---|
| 361 | if depth > 6 |
|---|
| 362 | # FIXME エラーログ |
|---|
| 363 | $stderr.puts "format directory depth limits", $@ |
|---|
| 364 | return |
|---|
| 365 | end |
|---|
| 366 | next_dirs = [] |
|---|
| 367 | entries = Dir.entries(dir) |
|---|
| 368 | entries.delete('.') |
|---|
| 369 | entries.delete('..') |
|---|
| 370 | entries.sort! |
|---|
| 371 | entries.each {|fname| |
|---|
| 372 | rpath = "#{dir}/#{fname}" |
|---|
| 373 | ftype = File.stat(rpath).ftype |
|---|
| 374 | if ftype == 'directory' && fname =~ FORMAT_BUNDLE_REGEXP |
|---|
| 375 | next_dirs << rpath |
|---|
| 376 | elsif ftype == 'file' && fname =~ FORMAT_FILE_REGEXP |
|---|
| 377 | begin |
|---|
| 378 | in_dir(dir) { load(fname) } |
|---|
| 379 | rescue |
|---|
| 380 | raise FormatLoadError, "#{$!} on file #{rpath}:#{$!.backtrace[1].split(':').last}" |
|---|
| 381 | end |
|---|
| 382 | elsif ftype == "file" && fname =~ SYNTAX_FILE_REGEXP |
|---|
| 383 | @syntax_files.push(rpath) |
|---|
| 384 | end |
|---|
| 385 | } |
|---|
| 386 | next_dirs.each {|ndir| |
|---|
| 387 | load_format(ndir, depth+1) |
|---|
| 388 | } |
|---|
| 389 | end |
|---|
| 390 | # dirで実行 |
|---|
| 391 | def in_dir(dir) |
|---|
| 392 | savedir = Dir.pwd |
|---|
| 393 | Dir.chdir(dir) |
|---|
| 394 | begin |
|---|
| 395 | yield |
|---|
| 396 | ensure |
|---|
| 397 | Dir.chdir(savedir) |
|---|
| 398 | end |
|---|
| 399 | end |
|---|
| 400 | private |
|---|
| 401 | # CONTAIN, UNCONTAIN, GROUP, PARENT_COMPLETIONを解決する |
|---|
| 402 | def resolve |
|---|
| 403 | # GROUPを解決する |
|---|
| 404 | resolver = {} |
|---|
| 405 | group = @group |
|---|
| 406 | @block.each_value {|element| |
|---|
| 407 | element::CONTAIN_NAMES.each {|contain| |
|---|
| 408 | if contain.to_s =~ GROUP_NAME_REGEXP |
|---|
| 409 | element::CONTAIN.push( create_group(contain) ) |
|---|
| 410 | end |
|---|
| 411 | } |
|---|
| 412 | element::UNCONTAIN_NAMES.each {|contain| |
|---|
| 413 | if contain.to_s =~ GROUP_NAME_REGEXP |
|---|
| 414 | element::UNCONTAIN.push( create_group(contain) ) |
|---|
| 415 | end |
|---|
| 416 | } |
|---|
| 417 | element::GROUP_NAMES.each {|contain| |
|---|
| 418 | if contain.to_s =~ GROUP_NAME_REGEXP |
|---|
| 419 | create_group(contain) |
|---|
| 420 | end |
|---|
| 421 | } |
|---|
| 422 | } |
|---|
| 423 | @block.each_pair {|name, element| |
|---|
| 424 | element::GROUP_NAMES.each {|s| |
|---|
| 425 | if !group.include?(s) |
|---|
| 426 | raise FormatLoadError, "While resolving block element :#{name}, No such group :#{s}" |
|---|
| 427 | end |
|---|
| 428 | element.module_eval { |
|---|
| 429 | include group[s] |
|---|
| 430 | } |
|---|
| 431 | } |
|---|
| 432 | resolver[name] = ElementResolver.new(element, resolver) |
|---|
| 433 | } |
|---|
| 434 | # 他の要素を解決する |
|---|
| 435 | resolver.each_value {|res| |
|---|
| 436 | res.resolve1 |
|---|
| 437 | } |
|---|
| 438 | resolver.each_value {|res| |
|---|
| 439 | res.resolve2 |
|---|
| 440 | } |
|---|
| 441 | @block |
|---|
| 442 | end |
|---|
| 443 | def create_group(name) |
|---|
| 444 | if !@group.include?(name) |
|---|
| 445 | @group[name] = Module.new { |
|---|
| 446 | const_set(:BLOCK_ELEMENT, false) |
|---|
| 447 | const_set(:BLOCK_GROUP, true) |
|---|
| 448 | const_set(:INLINE_ELEMENT, false) |
|---|
| 449 | # 名前: Symbol |
|---|
| 450 | const_set(:NAME, name) |
|---|
| 451 | } |
|---|
| 452 | @group[name] |
|---|
| 453 | else |
|---|
| 454 | @group[name] |
|---|
| 455 | end |
|---|
| 456 | end |
|---|
| 457 | class ElementResolver |
|---|
| 458 | attr_reader :element |
|---|
| 459 | def initialize(element, resolver) |
|---|
| 460 | @element = element |
|---|
| 461 | @resolver = resolver |
|---|
| 462 | @finish = false |
|---|
| 463 | @working = false |
|---|
| 464 | end |
|---|
| 465 | def resolve1 |
|---|
| 466 | return @element if @finish |
|---|
| 467 | # FIXME 以下のエラーメッセージ |
|---|
| 468 | raise FormatLoadError, "Looped dependency is detected" if @working |
|---|
| 469 | @working = true |
|---|
| 470 | resolver = @resolver |
|---|
| 471 | @element.module_eval { |
|---|
| 472 | const_get(:CONTAIN_NAMES).each {|s| |
|---|
| 473 | next if s.to_s =~ GROUP_NAME_REGEXP |
|---|
| 474 | raise FormatLoadError, "While resolving block element :#{const_get(:NAME)}, no such element: :#{s}" if !resolver.include?(s) |
|---|
| 475 | const_get(:CONTAIN).push( resolver[s].element ) |
|---|
| 476 | } |
|---|
| 477 | const_get(:UNCONTAIN_NAMES).each {|s| |
|---|
| 478 | next if s.to_s =~ GROUP_NAME_REGEXP |
|---|
| 479 | raise FormatLoadError, "While resolving block element :#{const_get(:NAME)}, no such element: :#{s}" if !resolver.include?(s) |
|---|
| 480 | const_get(:UNCONTAIN).push( resolver[s].element ) |
|---|
| 481 | } |
|---|
| 482 | } |
|---|
| 483 | @finish = true |
|---|
| 484 | @element |
|---|
| 485 | end |
|---|
| 486 | def resolve2 |
|---|
| 487 | resolver = @resolver |
|---|
| 488 | @element.module_eval { |
|---|
| 489 | parent = const_get(:PARENT_COMPLETION_NAME) |
|---|
| 490 | if parent.set? |
|---|
| 491 | raise FormatLoadError, "While resolving block element :#{const_get(:NAME)}, no such element: :#{parent.obj}" if !resolver.include?(parent.obj) |
|---|
| 492 | const_get(:PARENT_COMPLETION).replace( resolver[parent.obj].element ) |
|---|
| 493 | end |
|---|
| 494 | } |
|---|
| 495 | @element |
|---|
| 496 | end |
|---|
| 497 | end |
|---|
| 498 | end; end |
|---|
| 499 | |
|---|