Module: When::Parts::Resource

Extended by:
Pool
Includes:
Synchronize
Included in:
BasicTypes::M17n, BasicTypes::Object, TM::Position, TM::TemporalPosition
Defined in:
lib/when_exe/parts/resource.rb

Overview

Resource which has ‘International Resource Identifier’

Defined Under Namespace

Modules: Pool, Synchronize Classes: ContentLine

Constant Summary collapse

LabelProperty =
nil
ConstTypes =
{
  'SolarTerms'  => ['CalendarNote',     '%sSolarTerms',  '_n:%sSolarTerms%s' ],
  'LunarPhases' => ['LunarPhases',      '%sLunarPhases', '_n:%sLunarPhases%s'],
  'Terms'       => ['BasicTypes::M17n', '%s',            '_m:%s%s'           ],
  'Era'         => ['TM::CalendarEra',  '%s',            '_e:%s%s'           ],
  'Residue'     => ['Coordinates',      '%s',            '_co:%s%s'          ],
  'Week'        => ['CalendarNote',     '%sWeek',        '_n:%sWeek%s'       ],
  'Note'        => ['CalendarNote',     '%s',            '_n:%s%s'           ],
  'Notes'       => ['CalendarNote',     '%s',            '_n:%s/Notes%s'     ],
  nil           => ['CalendarTypes',    '%s',            '_c:%s%s'           ]
}
ConstList =
[]
IRIHeader =
/\A[_a-z\d]+:[^:]/i
IRIEncodeTable =
{'#'=>'%23', '<'=>'%3C', '>'=>'%3E', '{'=>'%7B', '}'=>'%7D'}
IRIDecodeTable =
IRIEncodeTable.invert
IRIEncode =
/[#{IRIEncodeTable.keys.join('')}]/
IRIDecode =
/#{IRIDecodeTable.keys.join('|')}/

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Pool

[]=, _setup_

Methods included from Synchronize

#synchronize

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object (private)

その他のメソッド

When::Parts::Resource で定義されていないメソッドは
処理を @child (type: Array) に委譲する


1105
1106
1107
1108
1109
1110
1111
1112
1113
# File 'lib/when_exe/parts/resource.rb', line 1105

def method_missing(name, *args, &block)
  return __method_missing(name, *args, &block) if When::Parts::MethodCash::Escape.key?(name)
  self.class.module_eval %Q{
    def #{name}(*args, &block)
      @child.send("#{name}", *args, &block)
    end
  } unless When::Parts::MethodCash.escape(name)
  @child.send(name, *args, &block)
end

Class Attribute Details

._prefixObject (readonly)



243
244
245
# File 'lib/when_exe/parts/resource.rb', line 243

def _prefix
  @_prefix
end

._prefix_indexObject (readonly)



243
244
245
# File 'lib/when_exe/parts/resource.rb', line 243

def _prefix_index
  @_prefix_index
end

._prefix_valuesObject (readonly)



243
244
245
# File 'lib/when_exe/parts/resource.rb', line 243

def _prefix_values
  @_prefix_values
end

Instance Attribute Details

#_poolObject (readonly)



691
692
693
# File 'lib/when_exe/parts/resource.rb', line 691

def _pool
  @_pool
end

#childArray<When::Parts::Resource>

self が has-a 関係で包含するオブジェクト



697
698
699
# File 'lib/when_exe/parts/resource.rb', line 697

def child
  @child
end

#keysArray<String> (readonly)

strftime で有効な locale

Returns:



725
726
727
# File 'lib/when_exe/parts/resource.rb', line 725

def keys
  @keys
end

#localeArray<String> (readonly)

Resource包含階層で使用する locale

When::BasicTypes::M17n の生成に使用する locale を定義する。
RFC 5545 に対する拡張である。

Returns:



719
720
721
# File 'lib/when_exe/parts/resource.rb', line 719

def locale
  @locale
end

#namespaceHash (readonly)

Resource包含階層で使用する namespace

When::BasicTypes::M17n の生成に使用する namespace を定義する。
RFC 5545 に対する拡張である。
xml で記述する場合には、本ライブラリ以外でも namespace を定義している。

Returns:

  • (Hash)

    { prefix => prefix文字列 }



709
710
711
# File 'lib/when_exe/parts/resource.rb', line 709

def namespace
  @namespace
end

Class Method Details

._abbreviation_to_iri(abbreviation, abbreviation_types = ConstTypes) ⇒ String

略称を iri に変換する

Parameters:

  • abbreviation (String or Symbol)

    略称

Returns:



229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/when_exe/parts/resource.rb', line 229

def _abbreviation_to_iri(abbreviation, abbreviation_types=ConstTypes)
  abbreviation_types[:pattern] ||= /\A(?=[A-Z])(.*?)(#{abbreviation_types.keys.compact.join('|')})?(\?.+|::.+)?\z/
  abbreviation.to_s =~ abbreviation_types[:pattern]
  return nil unless $1
  klass, name, iri = abbreviation_types[$2]
  key,   name, iri = $2, name % $1, iri % [$1,$3]
  if klass.kind_of?(String)
    klass = klass.split('::').inject(When) {|k,n| k.const_get(n)}
    abbreviation_types[key][0] = klass
  end
  klass.const_defined?(name) ? iri : nil
end

._decode(iri) ⇒ Object



459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/when_exe/parts/resource.rb', line 459

def _decode(iri)
  iri = iri.gsub(When::Parts::Resource::IRIDecode) {|c| When::Parts::Resource::IRIDecodeTable[c]}
  return iri unless iri =~ /%28/

  begin
    unless iri.gsub!(/%28.*?%29/) {|token|
      token.gsub(/%([\dA-F]{2})/i) {$1.to_i(16).chr}
    }
      raise ArgumentError, 'Brackets do not correspond: ' + iri 
    end
  end while iri =~ /%28/
  iri = $1 if iri =~ /\A\((.*)\)\z/
  iri
end

._encode(iri) ⇒ Object



444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/when_exe/parts/resource.rb', line 444

def _encode(iri)
  return iri unless iri =~ /\(/

  iri = iri.dup
  begin
    unless iri.gsub!(/\([^()]*\)/) {|token|
      token.gsub(/[():?&%]/) {|char|'%' + char.ord.to_s(16)}
    }
      raise ArgumentError, 'Brackets do not correspond: ' + iri 
    end
  end while iri =~ /\(/
  iri
end

._extract_prefix(path, capitalize = false) ⇒ Object



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/when_exe/parts/resource.rb', line 403

def _extract_prefix(path, capitalize=false)
  if (path =~ /\A(.+?):+(.+)\z/)
    prefix, klass = $~[1..2]
    if capitalize
      prefix = '_' + prefix.downcase
      klass  = klass.capitalize if klass == klass.upcase
    end
    path = _prefix[prefix] + klass if _prefix[prefix]
  elsif capitalize && path =~ /\A(v[^\/]+|daylight$|standard$)/i
    klass = path.sub(/\Av/i, '').capitalize
    path  = _prefix['_v'] + klass if When::V.const_defined?(klass) &&
                                     When::V.const_get(klass).kind_of?(Class)
  end
  return path
end

._instance(iri, namespace = nil, &block) ⇒ When::Parts::Resource

オブジェクト生成&参照

指定した iri の When::Parts::Resource オブジェクトを取得する。 当該オブジェクトが未登録であれば生成する。

Parameters:

  • iri (String)

    International Resource Identifier

  • namespace (String) (defaults to: nil)

    (デフォルトの名前空間, 指定がないときは名前空間を省略しない)

  • block (Block)

    オブジェクトが見つからない場合の代替処理

Returns:



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/when_exe/parts/resource.rb', line 314

def _instance(iri, namespace=nil, &block)
  _setup_ unless @_pool

  case iri
  when Array    ; return iri.map {|e| _instance(e, namespace)}                  # 配列は個別に処理
  when Resource ; return iri                                                    # 登録済みはそのまま
  when String   ;                                                               # 解析処理へ
  else          ; raise ArgumentError, "can't convert #{iri.class} to String"   # 例外
  end

  # 内部文字列化
  iri = When::EncodingConversion.to_internal_encoding(iri)

  # 階層がある場合は、階層をたどる
  iri = Resource._decode(iri)
  iri = $1 while iri =~ /\A\((.*)\)\z/
  iri = namespace + iri if namespace && iri !~ IRIHeader
  root, *leaves= Resource._encode(iri).split(/::/)
  if leaves.size > 0
    return leaves.inject(_instance(Resource._decode(root))) {|obj,leaf| obj[Resource._decode(leaf)]}
  end

  # 登録ずみなら、参照
  iri = _extract_prefix(iri)
  path, query = iri.split(/\?/, 2)
  if When.multi_thread
    my_mutex = nil
    @_lock_.synchronize do
      @_pool ||= {}
      unless @_pool[iri]
        my_mutex    = Mutex.new
        @_pool[iri] = my_mutex
      end
    end
    case @_pool[iri]
    when my_mutex; my_mutex.synchronize    {@_pool[iri] = _create_object(iri, path, query, &block) }
    when Mutex   ; @_pool[iri].synchronize {@_pool[iri]}
    else         ; @_pool[iri]
    end
  else
    @_pool      ||= {}
    @_pool[iri] ||= _create_object(iri, path, query, &block)
  end
end

._instantiate(resource) ⇒ Object



475
476
477
478
479
# File 'lib/when_exe/parts/resource.rb', line 475

def _instantiate(resource)
  return resource unless resource.kind_of?(Array)
  return resource[0].new(*resource[1..-1]) if resource[0].kind_of?(Class)
  return resource.map {|rsc| _instantiate(rsc)}
end

._parse(line, type = nil) ⇒ Object



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/when_exe/parts/resource.rb', line 377

def _parse(line, type=nil)
  return line unless line.kind_of?(String)
  line.sub!(/\s#.*\z/, '')
  return When::Locale._split($1) if type && /\A#{type}:(.+)\z/i =~ line
  tokens = line.scan(/((?:[^\\:]|\\.)+)(?::(?!\z))?|:/).flatten
  return When::Locale._split(line) unless tokens.size > 1 && /\A(\*)?([A-Z][-A-Z_]{0,255})(?:;(.+))?\z/i =~ tokens[0]
  marked, key, property = $~[1..3]
  values = tokens[1..-1]
  value  = values.join(':') unless values == [nil]
  content = ContentLine.new(key, value, marked)
  value ||= ''
  if property
    content.attribute['.'] = property + ':' + value
    property.scan(/((?:[^\\;]|\\.)+)(?:;(?!\z))?|;/).flatten.each do |pr|
      pr ||= ''
      pr.gsub!(/\\./) {|escape| ContentLine::RFC6350[escape] || escape}
      prop = ContentLine.new(*pr.split(/=/, 2))
      content.attribute[prop.predicate] = prop
    end
  else
    content.attribute['.'] = value
  end
  return content
end

._path_with_prefix(obj, simple = true) ⇒ Object



360
361
362
363
364
365
# File 'lib/when_exe/parts/resource.rb', line 360

def _path_with_prefix(obj, simple=true)
  _setup_ unless @_pool
  path = obj.kind_of?(Class) ? obj.to_s.sub(/\AWhen::/, base_uri).gsub(/::/, '/') :
                               obj.iri
  simple ? _simplify_path(path) : path
end

._replace_tags(source, tags) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/when_exe/parts/resource.rb', line 420

def _replace_tags(source, tags)
  case source
  when When::BasicTypes::M17n
    source
  when String
    target = source.dup
    tags.each_pair do |key, value|
      target.gsub!(/#\{([?&][^=#}]+?=)?#{key}(:.*?)?\}/, '\1' + value) if value.kind_of?(String)
    end
    target.gsub(/#\{.+?(:(.*?))?\}/, '\2')
  when Array
    source.map {|target| _replace_tags(target, tags)}
  when Hash
    target = {}
    source.each_pair do |key, value|
      target[key] = _replace_tags(tags[key] || value, tags)
    end
    target
  else
    source
  end
end

._setup_(options = {}) ⇒ void

Note:

本メソッドでマルチスレッド対応の管理変数の初期化を行っている。 このため、本メソッド自体はスレッドセーフでない。

This method returns an undefined value.

初期化

Parameters:

  • options (Hash) (defaults to: {})

    以下の通り

Options Hash (options):

  • :base_uri (String)

    Base URI for When_exe Resources (Default When::SourceURI)

  • :additional_namespaces (Hash<String(namespace)=>String(URI)>)

    User defined namespaces (Default {})

  • :root_dir (String)

    Root Directory for When_exe Resources Cash data (Default When::RootDir)

  • :leave_const (Boolean)

    If true, leave Constants of When module defined



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/when_exe/parts/resource.rb', line 260

def _setup_(options={})
  super()
  @_prefix = {
    '_wp'  => 'https://en.wikipedia.org/wiki/',
    '_w'   => base_uri + '/',
    '_p'   => base_uri + 'Parts/',
    '_b'   => base_uri + 'BasicTypes/',
    '_m'   => base_uri + 'BasicTypes/M17n/',
    '_co'  => base_uri + 'Coordinates/',
    '_l'   => base_uri + 'Coordinates/Spatial?',
    '_v'   => base_uri + 'V/',
    '_rs'  => base_uri + 'RS/',
    '_ex'  => base_uri + 'EX/',
    '_tm'  => base_uri + 'TM/',
    '_e'   => base_uri + 'TM/CalendarEra/',
    '_t'   => base_uri + 'TimeStandard/',
    '_ep'  => base_uri + 'Ephemeris/',
    '_c'   => base_uri + 'CalendarTypes/',
    '_n'   => base_uri + 'CalendarNote/',
    '_sc'  => base_uri + 'Ephemeris/V50/'
  }
  @base_uri       = options[:base_uri] || When::SourceURI
  @root_dir       = options[:root_dir] || When::RootDir
  @_prefix        = options[:additional_namespaces].merge(@_prefix) if options[:additional_namespaces].kind_of?(Hash)
  @_prefix_values = @_prefix.values.sort.reverse
  @_prefix_index  = @_prefix.invert
  unless options[:leave_const] || ConstList.empty?
    ConstList.delete_if do |constant|
      When.send(:remove_const, constant) if When.const_defined?(constant)
      true
    end
    When._define_common_calendar_types
  end
end

._setup_infoHash

設定情報を取得する

Returns:

  • (Hash)

    設定情報



299
300
301
# File 'lib/when_exe/parts/resource.rb', line 299

def _setup_info
  {:base_uri => base_uri, :root_dir => root_dir}
end

._simplify_path(path) ⇒ Object



368
369
370
371
372
373
374
# File 'lib/when_exe/parts/resource.rb', line 368

def _simplify_path(path)
  _prefix_values.each do |value|
    index = path.index(value)
    return _prefix_index[value] + ':' + path[value.length..-1] if index
  end
  return path
end

.base_uriString

Base URI for When_exe Resources

Returns:



209
210
211
# File 'lib/when_exe/parts/resource.rb', line 209

def base_uri
  @base_uri ||= When::SourceURI
end

.root_dirString

Root Directory for When_exe Resources

Returns:



217
218
219
# File 'lib/when_exe/parts/resource.rb', line 217

def root_dir
  @root_dir ||= When::RootDir
end

Instance Method Details

#[](iri) ⇒ When::parts::Resource

IRI または child の番号によるオブジェクト参照

Parameters:

  • iri (String)

    オブジェクトの IRI

  • iri (Numeric)

    child の index

Returns:

  • (When::parts::Resource)


753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
# File 'lib/when_exe/parts/resource.rb', line 753

def [](iri)
  case iri
  when Numeric
    return child[iri * 1]
  when String
    obj = self
    Resource._encode(iri).split(/::/).each do |label|
      return obj.child if label == '*'
      if obj == Resource
        obj = Resource._instance(Resource._decode(label))
      else
        case label
        when ''  ; obj = Resource
        when '.' # obj = obj
        else     ; obj = obj._pool[Resource._decode(label)]
        end
      end
      raise ArgumentError, "IRI not found: #{iri}" unless obj
    end
    return obj
  else
    super(iri)
    #raise ArgumentError, "IRI not found: #{iri}"
  end
end

#^(other) ⇒ Enumerator

Enumerator 生成のダミー

Parameters:

  • other (Object)

Returns:



912
913
914
# File 'lib/when_exe/parts/resource.rb', line 912

def ^(other)
  return nil
end

#each(*args, &block) ⇒ Enumerator

順次実行

Parameters:

  • args (Array)

    各サブクラスの enum_for にそのまま渡す

  • block (Block)

    実行するブロック

Returns:



923
924
925
926
927
# File 'lib/when_exe/parts/resource.rb', line 923

def each(*args, &block)
  enum = enum_for(*args)
  return enum unless block
  enum.each(&block)
end

#enum_forObject Also known as: to_enum

子オブジェクトを順に取り出す enumerator



901
902
903
# File 'lib/when_exe/parts/resource.rb', line 901

def enum_for
  @child.enum_for
end

#hierarchy(klass = self.class) ⇒ When::Parts::Resource

self を包含するオブジェクト階層

Parameters:

  • klass (Class) (defaults to: self.class)

    階層を遡るクラス

Returns:



793
794
795
796
797
798
799
800
801
# File 'lib/when_exe/parts/resource.rb', line 793

def hierarchy(klass=self.class)
  hierarchy = []
  parent    = self
  while parent.kind_of?(klass)
    hierarchy << parent
    parent = parent.parent
  end
  hierarchy.reverse
end

#include?(other) ⇒ Boolean

self が other を包含するか

Returns:

  • (Boolean)
    true - 包含する
    false - 包含しない


809
810
811
812
813
814
815
816
# File 'lib/when_exe/parts/resource.rb', line 809

def include?(other)
  c = other
  while c.kind_of?(Resource)
    return true if c.equal?(self)
    c = c.parent
  end
  return false
end

#included?(other) ⇒ Boolean

other が self を包含するか

Returns:

  • (Boolean)
    true - 包含される
    false - 包含されない


824
825
826
# File 'lib/when_exe/parts/resource.rb', line 824

def included?(other)
  other.include?(self)
end

#iri(prefix = false) ⇒ Sring

オブジェクトの IRI

Parameters:

  • prefix (Boolean) (defaults to: false)

    true ならIRI の先頭部分を簡約表現にする

Returns:

  • (Sring)


733
734
735
736
737
738
739
740
741
742
743
744
# File 'lib/when_exe/parts/resource.rb', line 733

def iri(prefix=false)
  unless @iri
    root = @_pool['..']
    path = root.instance_of?(String) ? root : label.to_s
    if root.respond_to?(:iri)
      root_iri = root.iri
      path = root_iri + '::' + path if root_iri
    end
    @iri = path
  end
  prefix ? Resource._simplify_path(@iri) : @iri
end

#leaf?Boolean

オブジェクト包含階層の末端か?

Returns:

  • (Boolean)
    true - IRIが付与された他のオブジェクトを包含していない
    false - IRIが付与された他のオブジェクトを包含している


857
858
859
# File 'lib/when_exe/parts/resource.rb', line 857

def leaf?
  !@child || (@child.length==0)
end

#m17n(source, namespace = nil, locale = nil, options = {}) ⇒ When::BasicTypes::M17n or Array<them>

When::BasicTypes::M17n の生成/参照

Parameters:

  • source (When::BasicTypes::M17n)

    処理を行わず、そのままsourceを返す

  • source (String)

    locale と 文字列の対応

  • source (Array)

    要素を個別に解釈して生成したオブジェクトのArrayを返す

  • namespace (Hash) (defaults to: nil)

    prefix の指定

  • locale (Array) (defaults to: nil)

    locale の定義順序の指定

  • options (Hash) (defaults to: {})

Returns:



888
889
890
891
892
893
894
895
896
897
# File 'lib/when_exe/parts/resource.rb', line 888

def m17n(source, namespace=nil, locale=nil, options={})
  case source
  when Array                  ; When::BasicTypes::M17n.new(source, namespace, locale, options)
  when When::BasicTypes::M17n ; source
  when String
    return self[$1] if source =~ /\A\s*\[((\.{1,2}|::)+[^\]]+)\]/
    When::BasicTypes::M17n.new(source, namespace, locale, options)
  else ; raise TypeError, "Invalid Type: #{source.class}"
  end
end

#map(&block) ⇒ Array Also known as: collect

map, collect の再定義

has-a 関係の子 Resource に対して map/collect を行う

Parameters:

  • block (Block)

    実行するブロック

Returns:



937
938
939
# File 'lib/when_exe/parts/resource.rb', line 937

def map(&block)
  @child.map(&block)
end

#nextWhen::Parts::Resource Also known as: succ

次のオブジェクト



844
845
846
847
848
# File 'lib/when_exe/parts/resource.rb', line 844

def next
  c = self
  c = c.child[0] while c.child && c.child.size > 0
  c._pool['.->']
end

#parentWhen::Parts::Resource

self を直接に包含するオブジェクト



783
784
785
# File 'lib/when_exe/parts/resource.rb', line 783

def parent
  @_pool['..'].kind_of?(Resource) ? @_pool['..'] : nil
end

#prevWhen::Parts::Resource

前のオブジェクト



832
833
834
835
836
837
838
# File 'lib/when_exe/parts/resource.rb', line 832

def prev
  c = self
  c = c.child[0] while c.child && c.child.size > 0
  c = c._pool['.<-']
  c = c.child[-1] while c && c.child && c.child.size > 0
  c
end

#registered?Boolean

IRIが付与されているか?

Returns:

  • (Boolean)
    true - IRIが付与されている
    false - IRIが付与されていない


867
868
869
870
871
872
873
874
875
# File 'lib/when_exe/parts/resource.rb', line 867

def registered?
  leaf = self
  while leaf._pool && leaf._pool['..'].respond_to?(:_pool)
    root = leaf._pool['..']
    return false unless leaf.equal?(root._pool[leaf.label])
    leaf = root
  end
  Resource._pool.value?(leaf)
end