lib/when_exe/parts/resource.rb in when_exe-0.3.4 vs lib/when_exe/parts/resource.rb in when_exe-0.3.5
- old
+ new
@@ -141,29 +141,42 @@
# Base URI for When_exe Resources
#
# @return [String]
#
- attr_reader :base_uri
+ def base_uri
+ @base_uri ||= When::SourceURI
+ end
+ # Root Directory for When_exe Resources
+ #
+ # @return [String]
+ #
+ def root_dir
+ @root_dir ||= When::RootDir
+ end
+
# @private
attr_reader :_prefix, :_prefix_values, :_prefix_index
private :_prefix, :_prefix_values, :_prefix_index
# 初期化
#
- # @param [String] base_uri Base URI for When_exe Resources
+ # @param [Hash] options 以下の通り
+ # @option options [String] :base_uri Base URI for When_exe Resources (Default When::SourceURI)
+ # @option options [String] :root_dir Root Directory for When_exe Resources Cash data (Default When::RootDir)
#
# @return [void]
#
# @note
# 本メソッドでマルチスレッド対応の管理変数の初期化を行っている。
# このため、本メソッド自体はスレッドセーフでない。
#
- def _setup_(base_uri=When::SourceURI)
+ def _setup_(options={})
super()
@_prefix = {
+ '_wp' => 'http://en.wikipedia.org/wiki/',
'_w' => base_uri + '/',
'_p' => base_uri + 'Parts/',
'_b' => base_uri + 'BasicTypes/',
'_m' => base_uri + 'BasicTypes/M17n/',
'_co' => base_uri + 'Coordinates/',
@@ -174,18 +187,27 @@
'_tm' => base_uri + 'TM/',
'_e' => base_uri + 'TM/CalendarEra/',
'_t' => base_uri + 'TimeStandard/',
'_ep' => base_uri + 'Ephemeris/',
'_c' => base_uri + 'CalendarTypes/',
- '_n' => base_uri + 'CalendarTypes/CalendarNote/',
+ '_n' => base_uri + 'CalendarNote/',
'_sc' => base_uri + 'Ephemeris/V50/'
}
- @base_uri = base_uri
+ @base_uri = options[:base_uri] || When::SourceURI
+ @root_dir = options[:root_dir] || When::RootDir
@_prefix_values = @_prefix.values.sort.reverse
@_prefix_index = @_prefix.invert
end
+ # 設定情報を取得する
+ #
+ # @return [Hash] 設定情報
+ #
+ def _setup_info
+ {:base_uri => base_uri, :root_dir => root_dir}
+ end
+
# オブジェクト生成&参照
#
# 指定した iri の When::Parts::Resource オブジェクトを取得する。
# 当該オブジェクトが未登録であれば生成する。
#
@@ -223,26 +245,30 @@
my_mutex = Mutex.new
@_pool[iri] = my_mutex
end
end
case @_pool[iri]
- when my_mutex; my_mutex.synchronize {_create_object(iri, path, query) }
- when Mutex ; @_pool[iri].synchronize { @_pool[iri] }
+ when my_mutex; my_mutex.synchronize {@_pool[iri] = _create_object(iri, path, query) }
+ when Mutex ; @_pool[iri].synchronize {@_pool[iri]}
else ; @_pool[iri]
end
else
- @_pool ||= {}
- @_pool[iri] ? @_pool[iri] : _create_object(iri, path, query)
+ @_pool ||= {}
+ @_pool[iri] ||= _create_object(iri, path, query)
end
end
# @private
def _path_with_prefix(obj, simple=true)
_setup_ unless @_pool
path = obj.kind_of?(Class) ? obj.to_s.sub(/^When::/, base_uri).gsub(/::/, '/') :
obj.iri
- return path unless simple
+ simple ? _simplify_path(path) : path
+ end
+
+ # @private
+ 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
@@ -292,22 +318,24 @@
end
# @private
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)
+ 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] = tags[key].kind_of?(Numeric) ? tags[key] : _replace_tags(value, tags)
+ target[key] = _replace_tags(tags[key] || value, tags)
end
target
else
source
end
@@ -342,13 +370,22 @@
end while iri =~ /%28/
iri = $1 if iri =~ /^\((.*)\)$/
iri
end
+ # @private
+ 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
+
private
+ # オブジェクト生成
def _create_object(iri, path, query)
+ # query analyzation
options = {}
replace = {}
if query
options = Hash[*Resource._encode(query).split(/&/).map{|pair|
key, value = pair.split(/=/, 2)
@@ -359,73 +396,52 @@
replace[$1] = options.delete(key) if key =~ /^([A-Z].*)/
end
end
options['..'] = iri
- obj = nil
- list = _class(path)
- if list
- # direct URI
- case list[0]
- when Class
- obj = list[0].new(options)
- when Array
- top = list[0][0]
- if top.kind_of?(Hash)
- top.each_pair do |key, value|
- replace.update(value[replace.delete(key)]) if value.kind_of?(Hash) && value.key?(replace[key])
- end
- list[0] = list[0][1..-1]
- list[0] = _replace_tags(list[0], top.merge(replace))
- end
- if list[0][0].kind_of?(Class)
- # 配列の先頭がクラスである場合
- klass, *list = list[0]
- unless list[-1].kind_of?(Hash)
- if list.length == 1
- list[0] = {'.'=>Array(list[0])}
- else
- list << {}
- end
- end
- else
- # 配列の先頭がクラスではない場合
- klass, *list = [list[1], *list[0]]
- list << {} unless list[-1].kind_of?(Hash)
- end
- list[-1] = list[-1].merge(options)
- obj = klass.new(*list)
+ # internal Resource
+ if path.index(Resource.base_uri) == 0
+ list = _class(path)
+ if list
+ return _internal(list, replace, options)
else
- obj = list[0]
+ raise IOError, 'IRI not found - ' + path
end
- else
- # external Resource
- parsed = nil
+ end
+
+ # external Resource
+ begin
+ object = When::Parts::Locale.send(:wikipedia_object, path, {:query=>query})
+ return object if object
OpenURI
- begin
- args = [path, "1".respond_to?(:force_encoding) ? 'r:utf-8' : 'r']
- args << {:ssl_verify_mode=>OpenSSL::SSL::VERIFY_NONE} if path =~ /^https:/
- open(*args) do |file|
- resource = _replace_tags(file.read, replace)
- parsed = (resource[0..5]=='BEGIN:') ? _ics(resource.split(/[\n\r]+/)) :
- _xml(REXML::Document.new(resource).root)
+ args = [path, "1".respond_to?(:force_encoding) ? 'r:utf-8' : 'r']
+ args << {:ssl_verify_mode=>OpenSSL::SSL::VERIFY_NONE} if path =~ /^https:/
+ open(*args) do |file|
+ resource = file.read
+ case resource[0..5].upcase
+ when 'BEGIN:'
+ options['.'] = _ics(_replace_tags(resource, replace).split(/[\n\r]+/))
+ options['.'][0].new(options)
+ when '<?XML '
+ options['.'] = _xml(REXML::Document.new(_replace_tags(resource, replace)).root)
+ options['.'][0].new(options)
+ else
+ raise NoMethodError, 'JSON not supported' unless Object.const_defined?(:JSON)
+ _internal(_json([JSON.parse(resource)]), replace, options)
end
- rescue OpenURI::HTTPError => error
- message = error.message + " - #{path}"
- error = error.respond_to?(:uri) ?
- error.class.new(message, error.io, error.uri) :
- error.class.new(message, error.io)
- raise error
end
- options['.'] = parsed
- obj = parsed[0].new(options)
+ rescue OpenURI::HTTPError => error
+ message = error.message + " - #{path}"
+ error = error.respond_to?(:uri) ?
+ error.class.new(message, error.io, error.uri) :
+ error.class.new(message, error.io)
+ raise error
end
- @_pool[iri] = obj
end
+ # 内部形式定義の取得
def _class(path)
- return nil unless path.index(Resource.base_uri) == 0
list = [When]
path[Resource.base_uri.length..-1].split(/\//).each do |mod|
if list[0].const_defined?(mod)
list.unshift(list[0].const_get(mod))
else
@@ -435,10 +451,46 @@
end
end
return list
end
+ # 内部形式定義のオブジェクト化
+ def _internal(list, replace, options)
+ case list[0]
+ when Class
+ list[0].new(options)
+ when Array
+ top = list[0][0]
+ if top.kind_of?(Hash)
+ top.each_pair do |key, value|
+ replace.update(value[replace[key]]) if value.kind_of?(Hash) && value[replace[key]]
+ end
+ list[0] = list[0][1..-1]
+ list[0] = _replace_tags(list[0], top.merge(replace))
+ end
+ if list[0][0].kind_of?(Class)
+ # 配列の先頭がクラスである場合
+ klass, *list = list[0]
+ unless list[-1].kind_of?(Hash)
+ if list.length == 1
+ list[0] = {'.'=>Array(list[0])}
+ else
+ list << {}
+ end
+ end
+ else
+ # 配列の先頭がクラスではない場合
+ klass, *list = [list[1], *list[0]]
+ list << {} unless list[-1].kind_of?(Hash)
+ end
+ list[-1] = list[-1].merge(options)
+ klass.new(*list)
+ else
+ list[0]
+ end
+ end
+
# .xml フォーマットの読み込み
def _xml(xml, namespace={})
obj = [_class(_extract_prefix(xml.attributes['type'].to_s))[0]]
xml.attributes.each_pair do |key,value|
expanded_name = value.expanded_name
@@ -495,10 +547,31 @@
end
end
end
raise ArgumentError, "BEGIN-END mismatch"
end
+
+ # .json フォーマットの読み込み
+ def _json(json)
+ case json
+ when Array
+ json.map {|value| _json(value)}
+ when Hash
+ hash = {}
+ json.each_pair {|key, value| hash[key] = _json(value)}
+ hash
+ when String
+ return json unless json =~ /^When::/
+ begin
+ return json.split('::').inject(Object) {|ns, sym| ns.const_get(sym)}
+ rescue
+ json
+ end
+ else
+ json
+ end
+ end
end
include Synchronize
# @private
@@ -506,11 +579,12 @@
# self が has-a 関係で包含するオブジェクト
#
# @return [Array<When::Parts::Resource>]
#
- attr_reader :child
+ attr_accessor :child
+ private :child=
#
# Resource包含階層で使用する namespace
#
# When::BasicTypes::M17n の生成に使用する namespace を定義する。
@@ -537,20 +611,24 @@
#
attr_reader :keys
# オブジェクトの IRI
#
- # @return [Sring]
+ # @param [Boolean] prefix true ならIRI の先頭部分を簡約表現にする
#
- def iri
- return @iri if @iri
- root = @_pool['..']
- path = root.instance_of?(String) ? root : label.to_s
- if root.respond_to?(:iri)
- prefix = root.iri
- path = prefix + '::' + path if prefix
+ # @return [Sring]
+ #
+ 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
- @iri = path
+ prefix ? Resource._simplify_path(@iri) : @iri
end
# IRI または child の番号によるオブジェクト参照
#
# @param [String] iri オブジェクトの IRI