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