0)
when ','
if (b+d+s == 0)
list.unshift(line[i+1..-1])
line = i > 0 ? line[0..i-1] : ''
end
end
end
list.unshift(line)
end
# locale 指定を解析して Hash の値を取り出す
# @private
def _hash_value(hash, locale, defaults=['', 'en'])
locale = locale.sub(/\..*/, '')
return hash[locale] if hash[locale]
return _hash_value(hash, _alias[locale], defaults) if _alias[locale]
language = locale.sub(/-.*/, '')
return hash[language] if hash[language]
defaults.each do |default|
return hash[default] if hash[default]
end
return nil
end
# 漢字の包摂パターン
# @private
def _unification
@unifications ||= DefaultUnification
end
# @private
def _get_locale(locale, access_key)
return nil unless access_key
access_key = access_key.split(/\//).map {|key| key =~ /\A[0-9]+\z/ ? key.to_i : key}
locale = locale.sub(/\..*/, '')
[locale, locale.sub(/-.*/, '')].each do |loc|
symbol = ('Locale_' + loc.sub(/-/,'_')).to_sym
return {locale=>access_key.inject(const_get(symbol)) {|hash, key| hash = hash[key]}} if const_defined?(symbol)
end
return nil
end
private
# Locale の読み替えパターン
def _alias
@aliases ||= DefaultAlias
end
# 名前空間定義の省略時に名前空間生成に用いる書式
def _namespaces
@namespaces ||= DefaultNamespaces
end
# wikipedia オブジェクトの生成・参照
def wikipedia_object(path, options={})
query = options.delete(:query)
interval = options.key?(:interval) ? options.delete(:interval) : @wikipedia_interval
return nil unless Object.const_defined?(:JSON) && path =~ Ref
_wikipedia_relation(_wikipedia_object(path, $1, $2, query, interval, options), path, query)
end
# wikipedia の読み込み
def _wikipedia_object(path, locale, file, query, interval, options)
# 採取済みデータ
title = URI.decode(file.gsub('_', ' '))
mode = "".respond_to?(:force_encoding) ? ':utf-8' : ''
dir = When::Parts::Resource.root_dir + '/data/wikipedia/' + locale
FileUtils.mkdir_p(dir) unless FileTest.exist?(dir)
open("#{dir}/#{file}.json", 'r'+mode) do |source|
json = JSON.parse(source.read)
json.update(Hash[*query.split('&').map {|pair| pair.split('=')}.flatten]) if query
json.key?('names') ?
When::BasicTypes::M17n.new(json) :
When::Coordinates::Spatial.new(json)
end
rescue => no_file_error
# 新しいデータ
case interval
when 0
raise no_file_error
when Numeric
if @wikipedia_last_access
delay = (@wikipedia_last_access + interval.abs - Time.now.to_f).ceil
sleep(delay) if delay > 0
end
end
contents = nil
begin
OpenURI
source = open(path, 'r'+mode)
contents = source.read
ensure
@wikipedia_last_access = Time.now.to_f
source.close if source
end
# wikipedia contents
raise KeyError, 'Article not found: ' + title if contents =~ //
# word
word = {
:label => title,
:names => {''=>title, locale=>title},
:link => {''=>path, locale=>path }
}
contents.scan(Link) do |link|
word[:names][$1] = $4
word[:link ][$1] = "http://#{$1}.wikipedia.org/wiki/#{$3}"
end
object = When::BasicTypes::M17n.new(word)
# location
if contents =~ /tools\.wmflabs\.org\/geohack\/geohack\.php\?.+?params=(.+?[NS])_(.+?[EW])/
location = {
:label => object
}
location[:lat], location[:long] = $~[1..2].map {|pos|
pos.gsub(/_(\d)[._]/, '_0\1_').sub('.', '_').sub('_', '.').gsub('_', '')
}
object = When::Coordinates::Spatial.new(location)
end
# save data
open("#{dir}/#{file}.json", 'w'+mode) do |source|
source.write(JSON.dump(object.to_h({:method=>:to_h}).update(options)))
end
query ? _wikipedia_object(path, locale, file, query) : object
end
# wikipedia オブジェクトの関連付け
def _wikipedia_relation(object, path, query)
code_space = path.sub(/[^\/]+\z/, '')
if object.kind_of?(When::Coordinates::Spatial)
object.label._pool['..'] = object
object._pool[object.label.to_s] = object.label
object.send(:child=, [object.label])
object.label.send(:code_space=, code_space)
else
object.send(:code_space=, code_space)
end
object._pool['..'] = path
object._pool['..'] += '?' + query if query
object
end
end
# ローケール指定時の文字列
#
# @return [Hash]
attr_reader :names
# 有効なローケール指定
#
# @return [Array]
attr_reader :keys
# 有効な文字列 - additional attribute
#
# @return [Array]
attr_reader :values
# 文字列の説明 - additional attribute
#
# @return [Hash] { anyURI }
attr_reader :link
# Rails 用 I18n 定義へのアクセス・キー
#
# @return [String]
attr_reader :access_key
protected :access_key
# 特定 locale に対応した文字列の取得
#
# @param [String] loc locale の指定 ( lang[-|_]country.encode )
# [ lang - 言語 ]
# [ country - 国(省略可) ]
# [ encode - 文字コード(省略可) ]
#
# @return [String] loc に対応した文字列
#
def translate(loc='')
return to_s unless loc
loc = loc.sub('_', '-')
lang, code = loc.split(/\./)
result = _label_value(loc)
return result if !code || @names.member?(loc)
return result.encode(code)
end
alias :/ :translate
# 特定 locale に対応した reference URI の取得
#
# @param [String] loc locale の指定
#
# @return [String] loc に対応した reference URI
#
def reference(loc='')
loc ||= ''
return Locale._hash_value(@link, loc.sub('_', '-'))
end
# 部分文字列
#
# @param [Range] range String#[] と同様の指定方法で範囲を指定する
#
# @return [When::Locale] 指定範囲に対応した部分文字列
#
def [](range)
dup._copy({
:label => to_s[range],
:names => @names.keys.inject({}) {|l,k|
l[k] = @names[k][range]
l
}
})
end
# 文字列の一致
#
# @param [String, Regexp] regexp マッチする正規表現
#
# @return [Integer] マッチした位置のindex(いずれかの locale でマッチが成功した場合)
# @return [nil] すべての locale でマッチに失敗した場合
#
def =~(regexp)
@keys.each do |key|
index = (@names[key] =~ regexp)
return index if index
end
return nil
end
# 部分文字列の位置
#
# @param [String] other 部分文字列
#
# @return [Integer] 部分文字列の先頭のindex(いずれかの locale で部分文字列を含んだ場合)
# @return [nil] すべての locale で部分文字列を含まない場合
#
def index(other)
@keys.each do |key|
index = @names[key].index(Locale.translate(other, key))
return index if index
end
return nil
end
# 文字列の連結
#
# @param [String, When::Toos::Locale] other 連結する文字列
#
# @return [When::Toos::Locale] 連結された文字列
#
def +(other)
names = {}
case other
when Locale
(@names.keys + other.names.keys).uniq.each do |key|
names[key] = _label_value(key) + other._label_value(key)
end
links = other.link
else
@names.keys.each do |key|
names[key] = _label_value(key) + other.to_s
end
links = {}
end
return dup._copy({:names=>names, :link=>links.merge(link), :label=>to_s + other.to_s})
end
# 書式指定による文字列化
#
# @param [Array