when_exe 0.2.100 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.ja.txt +25 -25
- data/LICENSE.txt +31 -31
- data/bin/irb.rc +5 -0
- data/bin/locales.rb +2 -2
- data/bin/when.rb +16 -0
- data/bin/when.rb.config +7 -0
- data/lib/when_exe.rb +616 -14
- data/lib/when_exe/basictypes.rb +615 -0
- data/lib/when_exe/calendartypes.rb +1700 -0
- data/lib/when_exe/coordinates.rb +1936 -0
- data/lib/when_exe/core/compatibility.rb +54 -0
- data/lib/when_exe/core/duration.rb +72 -72
- data/lib/when_exe/core/extension.rb +382 -0
- data/lib/when_exe/ephemeris.rb +1845 -0
- data/lib/when_exe/googlecalendar.rb +140 -0
- data/lib/when_exe/icalendar.rb +1587 -0
- data/lib/when_exe/inspect.rb +1237 -0
- data/lib/when_exe/locales/af.rb +90 -0
- data/lib/when_exe/locales/ar.rb +145 -0
- data/lib/when_exe/locales/az.rb +90 -0
- data/lib/when_exe/locales/bg.rb +90 -0
- data/lib/when_exe/locales/bn.rb +94 -0
- data/lib/when_exe/locales/bs.rb +121 -0
- data/lib/when_exe/locales/ca.rb +92 -0
- data/lib/when_exe/locales/cs.rb +107 -0
- data/lib/when_exe/locales/cy.rb +150 -0
- data/lib/when_exe/locales/da.rb +84 -0
- data/lib/when_exe/locales/de.rb +92 -0
- data/lib/when_exe/locales/de_AT.rb +92 -0
- data/lib/when_exe/locales/de_CH.rb +92 -0
- data/lib/when_exe/locales/el.rb +93 -0
- data/lib/when_exe/locales/en.rb +88 -0
- data/lib/when_exe/locales/en_AU.rb +88 -0
- data/lib/when_exe/locales/en_CA.rb +88 -0
- data/lib/when_exe/locales/en_GB.rb +88 -0
- data/lib/when_exe/locales/en_IN.rb +88 -0
- data/lib/when_exe/locales/en_NZ.rb +88 -0
- data/lib/when_exe/locales/eo.rb +89 -0
- data/lib/when_exe/locales/es.rb +84 -0
- data/lib/when_exe/locales/es_419.rb +84 -0
- data/lib/when_exe/locales/es_AR.rb +84 -0
- data/lib/when_exe/locales/es_CL.rb +84 -0
- data/lib/when_exe/locales/es_CO.rb +84 -0
- data/lib/when_exe/locales/es_MX.rb +84 -0
- data/lib/when_exe/locales/es_PE.rb +85 -0
- data/lib/when_exe/locales/es_VE.rb +84 -0
- data/lib/when_exe/locales/et.rb +94 -0
- data/lib/when_exe/locales/eu.rb +95 -0
- data/lib/when_exe/locales/fa.rb +80 -0
- data/lib/when_exe/locales/fi.rb +89 -0
- data/lib/when_exe/locales/fr.rb +88 -0
- data/lib/when_exe/locales/fr_CA.rb +88 -0
- data/lib/when_exe/locales/fr_CH.rb +88 -0
- data/lib/when_exe/locales/gl.rb +81 -0
- data/lib/when_exe/locales/he.rb +84 -0
- data/lib/when_exe/locales/hi.rb +80 -0
- data/lib/when_exe/locales/hi_IN.rb +84 -0
- data/lib/when_exe/locales/hr.rb +128 -0
- data/lib/when_exe/locales/hu.rb +84 -0
- data/lib/when_exe/locales/id.rb +89 -0
- data/lib/when_exe/locales/is.rb +89 -0
- data/lib/when_exe/locales/it.rb +87 -0
- data/lib/when_exe/locales/it_CH.rb +87 -0
- data/lib/when_exe/locales/ja.rb +78 -0
- data/lib/when_exe/locales/kn.rb +86 -0
- data/lib/when_exe/locales/ko.rb +78 -0
- data/lib/when_exe/locales/links.rb +2342 -0
- data/lib/when_exe/locales/lo.rb +123 -0
- data/lib/when_exe/locales/locales.rb +91 -0
- data/lib/when_exe/locales/lt.rb +111 -0
- data/lib/when_exe/locales/lv.rb +118 -0
- data/lib/when_exe/locales/mk.rb +93 -0
- data/lib/when_exe/locales/mn.rb +80 -0
- data/lib/when_exe/locales/nb.rb +81 -0
- data/lib/when_exe/locales/ne.rb +81 -0
- data/lib/when_exe/locales/nl.rb +92 -0
- data/lib/when_exe/locales/nn.rb +73 -0
- data/lib/when_exe/locales/or.rb +84 -0
- data/lib/when_exe/locales/pl.rb +128 -0
- data/lib/when_exe/locales/pt.rb +88 -0
- data/lib/when_exe/locales/pt_BR.rb +88 -0
- data/lib/when_exe/locales/rm.rb +143 -0
- data/lib/when_exe/locales/ro.rb +105 -0
- data/lib/when_exe/locales/ru.rb +128 -0
- data/lib/when_exe/locales/sk.rb +109 -0
- data/lib/when_exe/locales/sl.rb +122 -0
- data/lib/when_exe/locales/sr.rb +122 -0
- data/lib/when_exe/locales/sv.rb +83 -0
- data/lib/when_exe/locales/sw.rb +89 -0
- data/lib/when_exe/locales/th.rb +78 -0
- data/lib/when_exe/locales/tl.rb +99 -0
- data/lib/when_exe/locales/tr.rb +96 -0
- data/lib/when_exe/locales/uk.rb +128 -0
- data/lib/when_exe/locales/uz.rb +128 -0
- data/lib/when_exe/locales/vi.rb +94 -0
- data/lib/when_exe/locales/wo.rb +82 -0
- data/lib/when_exe/locales/zh_CN.rb +77 -0
- data/lib/when_exe/locales/zh_HK.rb +77 -0
- data/lib/when_exe/locales/zh_TW.rb +77 -0
- data/lib/when_exe/mini_application.rb +252 -0
- data/lib/when_exe/parts/enumerator.rb +472 -0
- data/lib/when_exe/parts/geometric_complex.rb +379 -0
- data/lib/when_exe/parts/locale.rb +513 -0
- data/lib/when_exe/parts/method_cash.rb +207 -0
- data/lib/when_exe/parts/resource.rb +806 -0
- data/lib/when_exe/parts/timezone.rb +182 -0
- data/lib/when_exe/region/bahai.rb +145 -0
- data/lib/when_exe/region/balinese.rb +627 -0
- data/lib/when_exe/region/chinese.rb +896 -0
- data/lib/when_exe/region/chinese_calendar.rb +919 -0
- data/lib/when_exe/region/chinese_epoch.rb +1245 -0
- data/lib/when_exe/region/christian.rb +644 -0
- data/lib/when_exe/region/far_east.rb +192 -0
- data/lib/when_exe/region/french.rb +66 -0
- data/lib/when_exe/region/geologicalage.rb +639 -0
- data/lib/when_exe/region/indian.rb +1066 -0
- data/lib/when_exe/region/iranian.rb +66 -0
- data/lib/when_exe/region/islamic.rb +105 -0
- data/lib/when_exe/region/japanese.rb +851 -0
- data/lib/when_exe/region/japanese_notes.rb +964 -0
- data/lib/when_exe/region/japanese_residues.rb +1149 -0
- data/lib/when_exe/region/javanese.rb +228 -0
- data/lib/when_exe/region/jewish.rb +127 -0
- data/lib/when_exe/region/korean.rb +267 -0
- data/lib/when_exe/region/m17n.rb +115 -0
- data/lib/when_exe/region/martian.rb +215 -0
- data/lib/when_exe/region/mayan.rb +122 -0
- data/lib/when_exe/region/moon.rb +333 -0
- data/lib/when_exe/region/nihon_shoki.rb +73 -0
- data/lib/when_exe/region/planets.rb +585 -0
- data/lib/when_exe/region/pope.rb +298 -0
- data/lib/when_exe/region/residue.rb +229 -0
- data/lib/when_exe/region/roman.rb +325 -0
- data/lib/when_exe/region/ryukyu.rb +98 -0
- data/lib/when_exe/region/shire.rb +254 -0
- data/lib/when_exe/region/sun.rb +210 -0
- data/lib/when_exe/region/thai.rb +227 -0
- data/lib/when_exe/region/tibetan.rb +233 -0
- data/lib/when_exe/region/v50.rb +111 -0
- data/lib/when_exe/region/vietnamese.rb +173 -0
- data/lib/when_exe/region/world.rb +197 -0
- data/lib/when_exe/timestandard.rb +547 -0
- data/lib/when_exe/tmduration.rb +330 -330
- data/lib/when_exe/tmobjects.rb +1295 -0
- data/lib/when_exe/tmposition.rb +1955 -0
- data/lib/when_exe/tmreference.rb +1547 -0
- data/lib/when_exe/version.rb +10 -3
- data/link_to_online_documents +4 -0
- data/test/examples/JapanHolidays.ics +456 -0
- data/test/examples/Millennium.ics +17 -0
- data/test/examples/NewYork.ics +61 -0
- data/test/examples/Residue.m17n +135 -0
- data/test/examples/Spatial.m17n +179 -0
- data/test/examples/Terms.m17n +39 -0
- data/test/examples/Test.ics +53 -0
- data/test/examples/USA-DST.ics +61 -0
- data/test/examples/geometric_complex.rb +41 -0
- data/test/examples/sample.xml +14 -0
- data/test/examples/today.rb +61 -0
- data/test/test.rb +54 -19
- data/test/test.rb.config +1 -0
- data/test/test/basictypes.rb +368 -0
- data/test/test/calendartypes.rb +57 -0
- data/test/test/coordinates.rb +380 -0
- data/test/test/ephemeris.rb +127 -0
- data/test/test/googlecalendar.rb +167 -0
- data/test/test/icalendar.rb +848 -0
- data/test/test/inspect.rb +115 -0
- data/test/test/parts.rb +480 -0
- data/test/test/region/chinese.rb +161 -0
- data/test/test/region/french.rb +33 -0
- data/test/test/region/geologicalage.rb +14 -0
- data/test/test/region/indian.rb +55 -0
- data/test/test/region/iran.rb +54 -0
- data/test/test/region/islamic.rb +18 -0
- data/test/test/region/japanese.rb +62 -0
- data/test/test/region/jewish.rb +61 -0
- data/test/test/region/m17n.rb +181 -0
- data/test/test/region/mayan.rb +78 -0
- data/test/test/region/moon.rb +14 -0
- data/test/test/region/planets.rb +14 -0
- data/test/test/region/residue.rb +123 -0
- data/test/test/region/sun.rb +14 -0
- data/test/test/region/thai.rb +94 -0
- data/test/test/region/tibetan.rb +30 -0
- data/test/test/tmobjects.rb +356 -57
- data/test/test/tmposition.rb +237 -0
- data/test/test/tmreference.rb +95 -0
- data/when_exe.gemspec +2 -2
- metadata +187 -7
- data/doc/COPYING +0 -31
- data/doc/COPYING.ja +0 -25
- data/doc/document_url +0 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (C) 2011-2013 Takashi SUGA
|
|
4
|
+
|
|
5
|
+
You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
|
|
6
|
+
=end
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# 本ライブラリのための諸々の部品
|
|
10
|
+
#
|
|
11
|
+
module When::Parts
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# == メソッドの実行結果をキャッシュし処理の高速化を行う
|
|
15
|
+
#
|
|
16
|
+
# === fn というメソッドをキャッシュ化
|
|
17
|
+
# * fn ではなく fn_ を定義しておく
|
|
18
|
+
# * fn メソッドが呼ばれると fn_ を実行し、{引数=>戻り値} を Hash に記憶する
|
|
19
|
+
# * 同じ引数で再度 fn メソッドが呼ばれると Hash から戻り値を取り出して返す
|
|
20
|
+
#
|
|
21
|
+
# === a_to_b と b_to_a という互いに逆関数のメソッドをキャッシュ化
|
|
22
|
+
# * a_to_b ではなく a_to_b_ , b_to_a ではなく b_to_a_ を定義しておく
|
|
23
|
+
# * a_to_b メソッドが呼ばれると a_to_b_ を実行し、{引数=>戻り値}, {戻り値=>引数}を Hash に記憶する
|
|
24
|
+
# * 同じ引数で再度 a_to_b メソッドが呼ばれると Hash から戻り値を取り出して返す
|
|
25
|
+
# * b_to_a メソッドが呼ばれ Hash に戻り値があれば Hash から戻り値を取り出して返す
|
|
26
|
+
#
|
|
27
|
+
# == 特記事項
|
|
28
|
+
#
|
|
29
|
+
# === Argument identification
|
|
30
|
+
# The eql? method of When::TM::(Temporal)Position is not overridden.
|
|
31
|
+
# It seems that the cost of identification of the argument exceeds the merit of the method cash.
|
|
32
|
+
# I do not recommend applying the methodcash to the method which takes
|
|
33
|
+
# When::TM::(Temporal)Position as an argument.
|
|
34
|
+
#
|
|
35
|
+
# === Multi-thread critical situation
|
|
36
|
+
# There is a problem in consistency of hash when this function is used in multi-thread environment.
|
|
37
|
+
# If the initialize method sets Mutex in instance variable @_m_cash_lock_,
|
|
38
|
+
# this function gives up use of hash in the critical situation.
|
|
39
|
+
#
|
|
40
|
+
# class Foo
|
|
41
|
+
# include MethodCash
|
|
42
|
+
#
|
|
43
|
+
# def initialize
|
|
44
|
+
# ...
|
|
45
|
+
# @_m_cash_lock_ = Mutex.new
|
|
46
|
+
# ...
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# 参考 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/47663
|
|
51
|
+
#
|
|
52
|
+
module MethodCash
|
|
53
|
+
|
|
54
|
+
alias :method_missing_ :method_missing
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# 最初に発生する method_missing で、キャッシュ機能を登録する
|
|
58
|
+
#
|
|
59
|
+
# @param [Symbol] name メソッド名
|
|
60
|
+
# @param [Array] args メソッド引数
|
|
61
|
+
# @param [block] block ブロック(省略可)
|
|
62
|
+
#
|
|
63
|
+
# @return [void]
|
|
64
|
+
#
|
|
65
|
+
def method_missing(name, *args, &block)
|
|
66
|
+
|
|
67
|
+
return method_missing_(name, *args, &block) unless respond_to?("#{name}_", true)
|
|
68
|
+
|
|
69
|
+
if ((name.to_s =~ /^(_*)(.+?)_to_(.+)$/) && respond_to?("#{$1}#{$3}_to_#{$2}_", true))
|
|
70
|
+
prefix, from, to = $~[1..3]
|
|
71
|
+
begin
|
|
72
|
+
if (@_m_cash_lock_)
|
|
73
|
+
return send("#{prefix}#{from}_to_#{to}_", *args, &block) unless @_m_cash_lock_.try_lock
|
|
74
|
+
unlock = "ensure ; @_m_cash_lock_.locked? && @_m_cash_lock_.unlock"
|
|
75
|
+
end
|
|
76
|
+
[[from, to],[to, from]].each do |pair|
|
|
77
|
+
a, b = pair
|
|
78
|
+
lock = @_m_cash_lock_ ? " return #{prefix}#{a}_to_#{b}_(*args) unless @_m_cash_lock_.try_lock" : ''
|
|
79
|
+
instance_eval %Q{
|
|
80
|
+
def #{prefix}#{a}_to_#{b}(*args)
|
|
81
|
+
key = _key_simplefy(args)
|
|
82
|
+
inv = @_m_cash_["#{prefix}#{a}_to_#{b}"][key]
|
|
83
|
+
return inv if inv
|
|
84
|
+
begin
|
|
85
|
+
#{lock}
|
|
86
|
+
inv = #{prefix}#{a}_to_#{b}_(*args)
|
|
87
|
+
@_m_cash_["#{prefix}#{b}_to_#{a}"][_key_simplefy(inv)] = args
|
|
88
|
+
@_m_cash_["#{prefix}#{a}_to_#{b}"][key] = inv
|
|
89
|
+
return inv
|
|
90
|
+
#{unlock}
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
key = _key_simplefy(args)
|
|
96
|
+
inv = send("#{prefix}#{from}_to_#{to}_", *args)
|
|
97
|
+
@_m_cash_ ||= {}
|
|
98
|
+
@_m_cash_["#{prefix}#{to}_to_#{from}"] ||= {}
|
|
99
|
+
@_m_cash_["#{prefix}#{from}_to_#{to}"] ||= {}
|
|
100
|
+
@_m_cash_["#{prefix}#{to}_to_#{from}"][_key_simplefy(inv)] = args
|
|
101
|
+
@_m_cash_["#{prefix}#{from}_to_#{to}"][key] = inv
|
|
102
|
+
return inv
|
|
103
|
+
ensure
|
|
104
|
+
@_m_cash_lock_ && @_m_cash_lock_.locked? && @_m_cash_lock_.unlock
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
else
|
|
108
|
+
begin
|
|
109
|
+
respond = respond_to?("#{name}_setup", true)
|
|
110
|
+
setup = respond ? "#{name}_setup(key, *args)" :
|
|
111
|
+
"(@_m_cash_[\"#{name}\"][key] = #{name}_(*args))"
|
|
112
|
+
if (@_m_cash_lock_)
|
|
113
|
+
return send("#{name}_", *args, &block) unless @_m_cash_lock_.try_lock
|
|
114
|
+
lock = " return #{name}_(*args) unless @_m_cash_lock_.try_lock"
|
|
115
|
+
unlock = "ensure ; @_m_cash_lock_.locked? && @_m_cash_lock_.unlock"
|
|
116
|
+
end
|
|
117
|
+
instance_eval %Q{
|
|
118
|
+
def #{name}(*args)
|
|
119
|
+
key = _key_simplefy(args)
|
|
120
|
+
ret = @_m_cash_["#{name}"][key]
|
|
121
|
+
return ret if ret
|
|
122
|
+
begin
|
|
123
|
+
#{lock}
|
|
124
|
+
return #{setup}
|
|
125
|
+
#{unlock}
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
}
|
|
129
|
+
key = _key_simplefy(args)
|
|
130
|
+
@_m_cash_ ||= {}
|
|
131
|
+
@_m_cash_["#{name}"] ||= {}
|
|
132
|
+
if (respond)
|
|
133
|
+
return send("#{name}_setup", key, *args)
|
|
134
|
+
else
|
|
135
|
+
return(@_m_cash_["#{name}"][key] ||= send("#{name}_", *args))
|
|
136
|
+
end
|
|
137
|
+
ensure
|
|
138
|
+
@_m_cash_lock_ && @_m_cash_lock_.locked? && @_m_cash_lock_.unlock
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def _key_simplefy(args)
|
|
146
|
+
key = args.kind_of?(Array) ? args.dup : args
|
|
147
|
+
key = key[0] while key.kind_of?(Array) && key.length<=1
|
|
148
|
+
return key
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# デバッグのためのオブジェクト内部記録用
|
|
154
|
+
# @private
|
|
155
|
+
module SnapShot
|
|
156
|
+
|
|
157
|
+
@@depth = 2
|
|
158
|
+
|
|
159
|
+
class << self
|
|
160
|
+
def _default(depth=2)
|
|
161
|
+
@@depth = depth
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def _snapshot(object, depth=@@depth, processed={})
|
|
165
|
+
obj = object.dup rescue (return object)
|
|
166
|
+
# def obj.is_snapshoted? ; true ; end
|
|
167
|
+
if (depth==0 || processed.key?(object))
|
|
168
|
+
return object if object.instance_of?(String)
|
|
169
|
+
string = object.to_s
|
|
170
|
+
string = "<##{object.class}>" + string unless (string =~ /^#</)
|
|
171
|
+
return string
|
|
172
|
+
else
|
|
173
|
+
object.instance_variables.each do |v|
|
|
174
|
+
if ((v =~ /^@_/) && object.kind_of?(SnapShot))
|
|
175
|
+
obj._remove_instance_variable(v)
|
|
176
|
+
else
|
|
177
|
+
src = object.instance_variable_get(v)
|
|
178
|
+
case src
|
|
179
|
+
when Array
|
|
180
|
+
val = src.map {|e| _snapshot(e, depth-1, processed)}
|
|
181
|
+
when Hash
|
|
182
|
+
val = {}
|
|
183
|
+
src.each_pair {|k,c| val[_snapshot(k, depth-1, processed)] = _snapshot(c, depth-1, processed)}
|
|
184
|
+
else
|
|
185
|
+
val = _snapshot(src, depth-1, processed)
|
|
186
|
+
end
|
|
187
|
+
obj.instance_variable_set(v, val)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
processed[object] = true
|
|
191
|
+
end
|
|
192
|
+
return obj
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def _snapshot(depth=@@depth, processed={})
|
|
197
|
+
SnapShot._snapshot(self, depth, processed)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
private
|
|
201
|
+
|
|
202
|
+
def _remove_instance_variable(name)
|
|
203
|
+
remove_instance_variable(name) if (name =~ /^@_/)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
# module Resource ; include SnapShot ; end
|
|
207
|
+
end
|
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (C) 2011-2013 Takashi SUGA
|
|
4
|
+
|
|
5
|
+
You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
|
|
6
|
+
=end
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# 本ライブラリのための諸々の部品
|
|
10
|
+
#
|
|
11
|
+
module When::Parts
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Resource which has 'International Resource Identifier'
|
|
15
|
+
#
|
|
16
|
+
module Resource
|
|
17
|
+
|
|
18
|
+
# 登録済み Prefix
|
|
19
|
+
Prefix = {'_w' => When::SourceURI + '/',
|
|
20
|
+
'_p' => When::SourceURI + 'Parts/',
|
|
21
|
+
'_b' => When::SourceURI + 'BasicTypes/',
|
|
22
|
+
'_m' => When::SourceURI + 'BasicTypes/M17n/',
|
|
23
|
+
'_co' => When::SourceURI + 'Coordinates/',
|
|
24
|
+
'_l' => When::SourceURI + 'Coordinates/Spatial?',
|
|
25
|
+
'_v' => When::SourceURI + 'V/',
|
|
26
|
+
'_rs' => When::SourceURI + 'RS/',
|
|
27
|
+
'_ex' => When::SourceURI + 'EX/',
|
|
28
|
+
'_tm' => When::SourceURI + 'TM/',
|
|
29
|
+
'_e' => When::SourceURI + 'TM/CalendarEra/',
|
|
30
|
+
'_t' => When::SourceURI + 'TimeStandard/',
|
|
31
|
+
'_ep' => When::SourceURI + 'Ephemeris/',
|
|
32
|
+
'_c' => When::SourceURI + 'CalendarTypes/',
|
|
33
|
+
'_n' => When::SourceURI + 'CalendarTypes/CalendarNote/',
|
|
34
|
+
'_sc' => When::SourceURI + 'Ephemeris/V50/'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# @private
|
|
38
|
+
PrefixKeys = Prefix.keys.sort.reverse.map {|k| k.downcase}
|
|
39
|
+
|
|
40
|
+
# @private
|
|
41
|
+
PrefixValues = Prefix.values.sort.reverse
|
|
42
|
+
|
|
43
|
+
# @private
|
|
44
|
+
PrefixIndex = Prefix.invert
|
|
45
|
+
|
|
46
|
+
# @private
|
|
47
|
+
LabelProperty = nil
|
|
48
|
+
|
|
49
|
+
# @private
|
|
50
|
+
class Element
|
|
51
|
+
attr_reader :predicate
|
|
52
|
+
attr_reader :object
|
|
53
|
+
attr_reader :attribute
|
|
54
|
+
attr_accessor :namespace
|
|
55
|
+
attr_reader :marked
|
|
56
|
+
|
|
57
|
+
def initialize(key, object=nil, marked=nil)
|
|
58
|
+
key = key.downcase.gsub(/-/,'_') if (key==key.upcase)
|
|
59
|
+
@predicate, @namespace = key.split(/:/).reverse
|
|
60
|
+
@object = object
|
|
61
|
+
@marked = marked
|
|
62
|
+
@attribute = {}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @private
|
|
67
|
+
module Synchronize
|
|
68
|
+
|
|
69
|
+
# 排他実行
|
|
70
|
+
#
|
|
71
|
+
# 与えられたブロックを必要なら排他制御をして実行する
|
|
72
|
+
#
|
|
73
|
+
def synchronize
|
|
74
|
+
if @_lock_
|
|
75
|
+
@_lock_.synchronize do
|
|
76
|
+
yield
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
yield
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# Resource の has-a 親子関係を管理する
|
|
86
|
+
#
|
|
87
|
+
module Pool
|
|
88
|
+
|
|
89
|
+
include Synchronize
|
|
90
|
+
|
|
91
|
+
# 初期化
|
|
92
|
+
# @return [void]
|
|
93
|
+
def _setup_
|
|
94
|
+
@_lock_ = Mutex.new if When.multi_thread
|
|
95
|
+
@_lock_.lock if @_lock_
|
|
96
|
+
@_pool = {}
|
|
97
|
+
@_lock_.unlock if @_lock_
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# オブジェクト参照
|
|
101
|
+
#
|
|
102
|
+
# @param [String] label
|
|
103
|
+
#
|
|
104
|
+
# @return [When::Parts::Resource] 指定した label で登録した子 Resource を返す
|
|
105
|
+
#
|
|
106
|
+
def [](label)
|
|
107
|
+
|
|
108
|
+
# nil label
|
|
109
|
+
return _pool[label] unless label
|
|
110
|
+
|
|
111
|
+
# 階層構造の確認
|
|
112
|
+
unless label =~ /\?/
|
|
113
|
+
terms = label.split(/::/)
|
|
114
|
+
terms.shift if terms[0] == ''
|
|
115
|
+
return terms.inject(self) {|obj,term| obj = obj[term]} if terms.length >= 2
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# 階層がない場合
|
|
119
|
+
path, options = label.split(/\?/, 2)
|
|
120
|
+
label = Resource._extract_prefix(path)
|
|
121
|
+
label += '?' + options if options
|
|
122
|
+
_pool[label.gsub(/%3A%3A/, '::')]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# オブジェクト登録
|
|
126
|
+
#
|
|
127
|
+
# 指定した label で子 Resource を登録する
|
|
128
|
+
#
|
|
129
|
+
# @param [String] label
|
|
130
|
+
# @param [When::Parts::Resource] obj
|
|
131
|
+
#
|
|
132
|
+
# @return [void]
|
|
133
|
+
#
|
|
134
|
+
def []=(label, obj)
|
|
135
|
+
# raise NameError, "Name duplication" if (@_pool[label])
|
|
136
|
+
_pool[label] = obj
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @private
|
|
140
|
+
def pool_keys
|
|
141
|
+
_pool.keys
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @private
|
|
145
|
+
def _pool
|
|
146
|
+
_setup_ unless @_pool
|
|
147
|
+
@_pool
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
class << self
|
|
152
|
+
|
|
153
|
+
include Pool
|
|
154
|
+
|
|
155
|
+
# オブジェクト生成&参照
|
|
156
|
+
#
|
|
157
|
+
# 指定した iri の When::Parts::Resource オブジェクトを取得する。
|
|
158
|
+
# 当該オブジェクトが未登録であれば生成する。
|
|
159
|
+
#
|
|
160
|
+
# @param [String] iri International Resource Identifier
|
|
161
|
+
# @param [String] namespace (デフォルトの名前空間, 指定がないときは名前空間を省略しない)
|
|
162
|
+
#
|
|
163
|
+
# @return [When::Parts::Resource]
|
|
164
|
+
#
|
|
165
|
+
def _instance(iri, namespace=nil)
|
|
166
|
+
# 配列は個別に処理
|
|
167
|
+
return iri.map {|e| _instance(e, namespace)} if iri.kind_of?(Array)
|
|
168
|
+
|
|
169
|
+
# 文字列以外はそのまま返す
|
|
170
|
+
return iri unless iri.instance_of?(String)
|
|
171
|
+
|
|
172
|
+
# 階層がある場合は、階層をたどる
|
|
173
|
+
iri = namespace + iri if namespace && iri !~ /^[_a-z\d]+:[^:]/i
|
|
174
|
+
root, *leaves= iri.split(/::/)
|
|
175
|
+
return leaves.inject(_instance(root)) {|obj,leaf| obj[leaf]} unless leaves==[] || iri =~ /\?/
|
|
176
|
+
|
|
177
|
+
# 登録ずみなら、参照
|
|
178
|
+
path, query = _extract_prefix(iri).split(/\?/, 2)
|
|
179
|
+
iri = query ? (path + '?' + query) : path
|
|
180
|
+
if When.multi_thread
|
|
181
|
+
my_mutex = nil
|
|
182
|
+
@_lock_.synchronize do
|
|
183
|
+
@_pool ||= {}
|
|
184
|
+
unless @_pool[iri]
|
|
185
|
+
my_mutex = Mutex.new
|
|
186
|
+
@_pool[iri] = my_mutex
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
case @_pool[iri]
|
|
190
|
+
when my_mutex; my_mutex.synchronize {_create_object(iri, path, query) }
|
|
191
|
+
when Mutex ; @_pool[iri].synchronize { @_pool[iri] }
|
|
192
|
+
else ; @_pool[iri]
|
|
193
|
+
end
|
|
194
|
+
else
|
|
195
|
+
@_pool ||= {}
|
|
196
|
+
@_pool[iri] ? @_pool[iri] : _create_object(iri, path, query)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# @private
|
|
201
|
+
def _path_with_prefix(obj, simple=true)
|
|
202
|
+
path = obj.kind_of?(Class) ? obj.to_s.sub(/^When::/, When::SourceURI).gsub(/::/, '/') :
|
|
203
|
+
obj.iri
|
|
204
|
+
return path unless simple
|
|
205
|
+
PrefixValues.each do |value|
|
|
206
|
+
index = path.index(value)
|
|
207
|
+
return PrefixIndex[value] + ':' + path[value.length..-1] if index
|
|
208
|
+
end
|
|
209
|
+
return path
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# @private
|
|
213
|
+
def _parse(line, type=nil)
|
|
214
|
+
return line unless line.kind_of?(String)
|
|
215
|
+
line.sub!(/\s#.*$/, '')
|
|
216
|
+
return Locale._split($1) if type && line =~ /^#{type}:(.+)$/i
|
|
217
|
+
return Locale._split(line) unless line =~ /^(\*)?([A-Z][-A-Z_]{0,255})(?:;(.*?))?:(.*)$/i
|
|
218
|
+
|
|
219
|
+
marked, key, property, value = $~[1..4]
|
|
220
|
+
element = Element.new(key, value, marked)
|
|
221
|
+
if (property)
|
|
222
|
+
element.attribute['.'] = property+':'+value
|
|
223
|
+
property.split(/;/) do |pr|
|
|
224
|
+
prop = Element.new(*pr.split(/=/, 2))
|
|
225
|
+
element.attribute[prop.predicate] = prop
|
|
226
|
+
end
|
|
227
|
+
else
|
|
228
|
+
element.attribute['.'] = value
|
|
229
|
+
end
|
|
230
|
+
return element
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# @private
|
|
234
|
+
def _extract_prefix(path, capitalize=false)
|
|
235
|
+
if (path =~ /^(.+?):+(.+)$/)
|
|
236
|
+
prefix, klass = $~[1..2]
|
|
237
|
+
if capitalize
|
|
238
|
+
prefix = '_' + prefix.downcase
|
|
239
|
+
klass = klass.capitalize if klass == klass.upcase
|
|
240
|
+
end
|
|
241
|
+
path = Prefix[prefix] + klass if (Prefix[prefix])
|
|
242
|
+
elsif capitalize && path =~ /^(v[^\/]+|daylight$|standard$)/i
|
|
243
|
+
klass = path.sub(/^v/i, '').capitalize
|
|
244
|
+
path = Prefix['_v'] + klass if When::V.const_defined?(klass) &&
|
|
245
|
+
When::V.const_get(klass).kind_of?(Class)
|
|
246
|
+
end
|
|
247
|
+
return path
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
private
|
|
251
|
+
|
|
252
|
+
def _create_object(iri, path, query)
|
|
253
|
+
options = {}
|
|
254
|
+
replace = {}
|
|
255
|
+
if query
|
|
256
|
+
options = Hash[*query.split(/&/).map{ |pair| pair.split(/=/, 2) }.flatten]
|
|
257
|
+
keys = options.keys
|
|
258
|
+
keys.each do |key|
|
|
259
|
+
replace[$1] = options.delete(key) if key =~ /^!(.+)/
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
options['..'] = iri
|
|
263
|
+
|
|
264
|
+
obj = nil
|
|
265
|
+
list = _class(path)
|
|
266
|
+
if list
|
|
267
|
+
# direct URI
|
|
268
|
+
case list[0]
|
|
269
|
+
when Class
|
|
270
|
+
obj = list[0].new(options)
|
|
271
|
+
when Array
|
|
272
|
+
if list[0][0].kind_of?(Class)
|
|
273
|
+
# 配列の先頭がクラスである場合
|
|
274
|
+
klass, *list = list[0]
|
|
275
|
+
unless list[-1].kind_of?(Hash)
|
|
276
|
+
if list.length == 1
|
|
277
|
+
list[0] = {'.'=>Array(list[0])}
|
|
278
|
+
else
|
|
279
|
+
list << {}
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
else
|
|
283
|
+
# 配列の先頭がクラスではない場合
|
|
284
|
+
klass, *list = [list[1], *list[0]]
|
|
285
|
+
list << {} unless list[-1].kind_of?(Hash)
|
|
286
|
+
end
|
|
287
|
+
list[-1] = list[-1].merge(options)
|
|
288
|
+
obj = klass.new(*list)
|
|
289
|
+
else
|
|
290
|
+
obj = list[0]
|
|
291
|
+
end
|
|
292
|
+
else
|
|
293
|
+
# external Resource
|
|
294
|
+
parsed = nil
|
|
295
|
+
OpenURI
|
|
296
|
+
begin
|
|
297
|
+
open(path, "1".respond_to?(:force_encoding) ? 'r:utf-8' : 'r') do |file|
|
|
298
|
+
resource = file.read
|
|
299
|
+
replace.keys.each do |key|
|
|
300
|
+
resource.gsub!(/#\{#{key}\}/, replace[key])
|
|
301
|
+
end
|
|
302
|
+
parsed = (resource[0..5]=='BEGIN:') ? _ics(resource.split(/[\n\r]+/)) :
|
|
303
|
+
_xml(REXML::Document.new(resource).root)
|
|
304
|
+
end
|
|
305
|
+
rescue OpenURI::HTTPError => error
|
|
306
|
+
message = error.message + " - #{path}"
|
|
307
|
+
error = error.respond_to?(:uri) ?
|
|
308
|
+
error.class.new(message, error.io, error.uri) :
|
|
309
|
+
error.class.new(message, error.io)
|
|
310
|
+
raise error
|
|
311
|
+
end
|
|
312
|
+
options['.'] = parsed
|
|
313
|
+
obj = parsed[0].new(options)
|
|
314
|
+
end
|
|
315
|
+
@_pool[iri] = obj
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def _class(path)
|
|
319
|
+
return nil unless (path =~ /^http:\/\/hosi\.org\/When\/(.*)/)
|
|
320
|
+
list = [When]
|
|
321
|
+
$1.split(/\//).each do |mod|
|
|
322
|
+
if list[0].const_defined?(mod)
|
|
323
|
+
list.unshift(list[0].const_get(mod))
|
|
324
|
+
else
|
|
325
|
+
return nil unless (list[0] == When::V)
|
|
326
|
+
list.unshift(When::V::Root)
|
|
327
|
+
return list
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
return list
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# .xml フォーマットの読み込み
|
|
334
|
+
def _xml(xml, namespace={})
|
|
335
|
+
obj = [_class(_extract_prefix(xml.attributes['type'].to_s))[0]]
|
|
336
|
+
xml.attributes.each_pair do |key,value|
|
|
337
|
+
expanded_name = value.expanded_name
|
|
338
|
+
next unless (expanded_name =~ /^xmlns/)
|
|
339
|
+
key = '' if expanded_name == 'xmlns'
|
|
340
|
+
namespace[key] = value.to_s
|
|
341
|
+
end
|
|
342
|
+
obj << Element.new('xmlns:namespace', namespace) if (namespace.size>0)
|
|
343
|
+
xml.each do |e|
|
|
344
|
+
next unless defined? e.name
|
|
345
|
+
if (e.attributes['type'])
|
|
346
|
+
obj << _xml(e, namespace)
|
|
347
|
+
else
|
|
348
|
+
element = Element.new(e.expanded_name, e.attributes['ref']||e.text)
|
|
349
|
+
e.attributes.each_pair do |key,value|
|
|
350
|
+
attr = Element.new(value.name, value)
|
|
351
|
+
attr.namespace = value.prefix
|
|
352
|
+
element.attribute[key] = attr
|
|
353
|
+
end
|
|
354
|
+
obj << element
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
return obj
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# .ics フォーマットの読み込み
|
|
361
|
+
def _ics(ics, type=nil)
|
|
362
|
+
obj = [type] if type
|
|
363
|
+
indent = nil
|
|
364
|
+
while (line = ics.shift) do
|
|
365
|
+
line.chomp!
|
|
366
|
+
case line
|
|
367
|
+
when /^\s*BEGIN:(.*)$/
|
|
368
|
+
if (type)
|
|
369
|
+
obj[-1] = _parse(obj[-1], type) if obj.length > 1
|
|
370
|
+
obj << _ics(ics, $1)
|
|
371
|
+
else
|
|
372
|
+
type = $1
|
|
373
|
+
obj = [type]
|
|
374
|
+
end
|
|
375
|
+
when /^\s*END:(.*)$/
|
|
376
|
+
raise TypeError, "Irregal Type : #{$1}" unless (type == $1)
|
|
377
|
+
obj[0] = _class(_extract_prefix(type, true))[0]
|
|
378
|
+
obj[-1] = _parse(obj[-1], type)
|
|
379
|
+
return obj
|
|
380
|
+
when /^\s*#/
|
|
381
|
+
when /^(\s*)(.*)$/
|
|
382
|
+
indent = $1 unless indent
|
|
383
|
+
if (indent.length < $1.length)
|
|
384
|
+
obj[-1] += line[(indent.length+1)..-1] # See RFC5545 3.1 Content Lines
|
|
385
|
+
else
|
|
386
|
+
obj << $2
|
|
387
|
+
obj[-2] = _parse(obj[-2], type)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
raise ArgumentError, "BEGIN-END mismatch"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
include Synchronize
|
|
396
|
+
|
|
397
|
+
# @private
|
|
398
|
+
attr_reader :_pool
|
|
399
|
+
|
|
400
|
+
# self が has-a 関係で包含するオブジェクト
|
|
401
|
+
#
|
|
402
|
+
# @return [Array<When::Parts::Resource>]
|
|
403
|
+
#
|
|
404
|
+
attr_reader :child
|
|
405
|
+
|
|
406
|
+
#
|
|
407
|
+
# Resource包含階層で使用する namespace
|
|
408
|
+
#
|
|
409
|
+
# When::BasicTypes::M17n の生成に使用する namespace を定義する。
|
|
410
|
+
# RFC 5545 に対する拡張である。
|
|
411
|
+
# xml で記述する場合には、本ライブラリ以外でも namespace を定義している。
|
|
412
|
+
#
|
|
413
|
+
# @return [Hash] { prefix => prefix文字列 }
|
|
414
|
+
#
|
|
415
|
+
attr_reader :namespace
|
|
416
|
+
|
|
417
|
+
#
|
|
418
|
+
# Resource包含階層で使用する locale
|
|
419
|
+
#
|
|
420
|
+
# When::BasicTypes::M17n の生成に使用する locale を定義する。
|
|
421
|
+
# RFC 5545 に対する拡張である。
|
|
422
|
+
#
|
|
423
|
+
# @return [Array<String>]
|
|
424
|
+
#
|
|
425
|
+
attr_reader :locale
|
|
426
|
+
|
|
427
|
+
# strftime で有効な locale
|
|
428
|
+
#
|
|
429
|
+
# @return [Array<String>]
|
|
430
|
+
#
|
|
431
|
+
attr_reader :keys
|
|
432
|
+
|
|
433
|
+
# オブジェクトの IRI
|
|
434
|
+
#
|
|
435
|
+
# @return [Sring]
|
|
436
|
+
#
|
|
437
|
+
def iri
|
|
438
|
+
return @iri if @iri
|
|
439
|
+
root = @_pool['..']
|
|
440
|
+
path = root.instance_of?(String) ? root : label.to_s
|
|
441
|
+
path = path.gsub(/::/, '%3A%3A')
|
|
442
|
+
if root.respond_to?(:iri)
|
|
443
|
+
prefix = root.iri
|
|
444
|
+
path = prefix + '::' + path if prefix
|
|
445
|
+
end
|
|
446
|
+
@iri = path
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# IRI または child の番号によるオブジェクト参照
|
|
450
|
+
#
|
|
451
|
+
# @param [String] iri オブジェクトの IRI
|
|
452
|
+
# @param [Numeric] iri child の index
|
|
453
|
+
#
|
|
454
|
+
# @return [When::parts::Resource]
|
|
455
|
+
#
|
|
456
|
+
def [](iri)
|
|
457
|
+
case iri
|
|
458
|
+
when Numeric
|
|
459
|
+
return child[iri * 1]
|
|
460
|
+
when String
|
|
461
|
+
obj = self
|
|
462
|
+
iri.split(/::/).each do |label|
|
|
463
|
+
return obj.child if label == '*'
|
|
464
|
+
if obj == Resource
|
|
465
|
+
obj = Resource._instance(label)
|
|
466
|
+
else
|
|
467
|
+
case label
|
|
468
|
+
when '' ; obj = Resource
|
|
469
|
+
when '.' # obj = obj
|
|
470
|
+
else ; obj = obj._pool[label.gsub(/%3A%3A/, '::')]
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
raise ArgumentError, "IRI not found: #{iri}" unless obj
|
|
474
|
+
end
|
|
475
|
+
return obj
|
|
476
|
+
else
|
|
477
|
+
super(iri)
|
|
478
|
+
#raise ArgumentError, "IRI not found: #{iri}"
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# self を直接に包含するオブジェクト
|
|
483
|
+
#
|
|
484
|
+
# @return [When::Parts::Resource]
|
|
485
|
+
#
|
|
486
|
+
def parent
|
|
487
|
+
@_pool['..'].kind_of?(Resource) ? @_pool['..'] : nil
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# self を包含するオブジェクト階層
|
|
491
|
+
#
|
|
492
|
+
# @param [Class] klass 階層を遡るクラス
|
|
493
|
+
#
|
|
494
|
+
# @return [When::Parts::Resource]
|
|
495
|
+
#
|
|
496
|
+
def hierarchy(klass=self.class)
|
|
497
|
+
hierarchy = []
|
|
498
|
+
parent = self
|
|
499
|
+
while parent.kind_of?(klass)
|
|
500
|
+
hierarchy << parent
|
|
501
|
+
parent = parent.parent
|
|
502
|
+
end
|
|
503
|
+
hierarchy.reverse
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
# self が other を包含するか
|
|
507
|
+
#
|
|
508
|
+
# @return [Boolean]
|
|
509
|
+
# [ true - 包含する ]
|
|
510
|
+
# [ false - 包含しない ]
|
|
511
|
+
#
|
|
512
|
+
def include?(other)
|
|
513
|
+
c = other
|
|
514
|
+
while c.kind_of?(Resource)
|
|
515
|
+
return true if c.equal?(self)
|
|
516
|
+
c = c.parent
|
|
517
|
+
end
|
|
518
|
+
return false
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# other が self を包含するか
|
|
522
|
+
#
|
|
523
|
+
# @return [Boolean]
|
|
524
|
+
# [ true - 包含される ]
|
|
525
|
+
# [ false - 包含されない ]
|
|
526
|
+
#
|
|
527
|
+
def included?(other)
|
|
528
|
+
other.include?(self)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# 前のオブジェクト
|
|
532
|
+
#
|
|
533
|
+
# @return [When::Parts::Resource]
|
|
534
|
+
#
|
|
535
|
+
def prev
|
|
536
|
+
c = self
|
|
537
|
+
c = c.child[0] while c.child && c.child.size > 0
|
|
538
|
+
c = c._pool['.<-']
|
|
539
|
+
c = c.child[-1] while c && c.child && c.child.size > 0
|
|
540
|
+
c
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
# 次のオブジェクト
|
|
544
|
+
#
|
|
545
|
+
# @return [When::Parts::Resource]
|
|
546
|
+
#
|
|
547
|
+
def next
|
|
548
|
+
c = self
|
|
549
|
+
c = c.child[0] while c.child && c.child.size > 0
|
|
550
|
+
c._pool['.->']
|
|
551
|
+
end
|
|
552
|
+
alias :succ :next
|
|
553
|
+
|
|
554
|
+
# オブジェクト包含階層の末端か?
|
|
555
|
+
#
|
|
556
|
+
# @return [Boolean]
|
|
557
|
+
# [ true - IRIが付与された他のオブジェクトを包含していない ]
|
|
558
|
+
# [ false - IRIが付与された他のオブジェクトを包含している ]
|
|
559
|
+
#
|
|
560
|
+
def leaf?
|
|
561
|
+
!@child || (@child.length==0)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
# IRIが付与されているか?
|
|
565
|
+
#
|
|
566
|
+
# @return [Boolean]
|
|
567
|
+
# [ true - IRIが付与されている ]
|
|
568
|
+
# [ false - IRIが付与されていない ]
|
|
569
|
+
#
|
|
570
|
+
def registered?
|
|
571
|
+
leaf = self
|
|
572
|
+
while leaf._pool['..'].respond_to?(:_pool)
|
|
573
|
+
root = leaf._pool['..']
|
|
574
|
+
return false unless leaf.equal?(root._pool[leaf.label])
|
|
575
|
+
leaf = root
|
|
576
|
+
end
|
|
577
|
+
Resource._pool.value?(leaf)
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# When::BasicTypes::M17n の生成/参照
|
|
581
|
+
#
|
|
582
|
+
# @param [When::BasicTypes::M17n] source 処理を行わず、そのままsourceを返す
|
|
583
|
+
# @param [String] source locale と 文字列の対応
|
|
584
|
+
# @param [Array] source 要素を個別に解釈して生成したオブジェクトのArrayを返す
|
|
585
|
+
# @param [Hash] namespace prefix の指定
|
|
586
|
+
# @param [Array] locale locale の定義順序の指定
|
|
587
|
+
# @param [Hash] options (see {When::BasicTypes::M17n.new}[link:When/BasicTypes/M17n.html#method-c-new])
|
|
588
|
+
#
|
|
589
|
+
# @return [When::BasicTypes::M17n or Array<them>]
|
|
590
|
+
#
|
|
591
|
+
def m17n(source, namespace=nil, locale=nil, options={})
|
|
592
|
+
case source
|
|
593
|
+
when Array ; When::BasicTypes::M17n.new(source, namespace, locale, options)
|
|
594
|
+
when When::BasicTypes::M17n ; source
|
|
595
|
+
when String
|
|
596
|
+
return self[$1] if source =~ /^\s*\[((\.{1,2}|::)+[^\]]+)\]/
|
|
597
|
+
When::BasicTypes::M17n.new(source, namespace, locale, options)
|
|
598
|
+
else ; raise TypeError, "Invalid Type: #{source.class}"
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# オブジェクトを順に取り出す enumerator
|
|
603
|
+
#
|
|
604
|
+
# @param [Symbol] direction 取り出す方向
|
|
605
|
+
# [ :forward - 昇順 ]
|
|
606
|
+
# [ :reverse - 降順 ]
|
|
607
|
+
#
|
|
608
|
+
def enum_for(direction=:forward)
|
|
609
|
+
Enumerator.new(self, direction)
|
|
610
|
+
end
|
|
611
|
+
alias :to_enum :enum_for
|
|
612
|
+
|
|
613
|
+
# Enumerator 生成のダミー
|
|
614
|
+
#
|
|
615
|
+
# @param [Object] other
|
|
616
|
+
#
|
|
617
|
+
# @return [Enumerator]
|
|
618
|
+
#
|
|
619
|
+
def ^(other)
|
|
620
|
+
return nil
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
# 順次実行
|
|
624
|
+
#
|
|
625
|
+
# @param [Array] args 各サブクラスの enum_for にそのまま渡す
|
|
626
|
+
# @param [Block] block 実行するブロック
|
|
627
|
+
#
|
|
628
|
+
# @return [Enumerator]
|
|
629
|
+
#
|
|
630
|
+
def each(*args, &block)
|
|
631
|
+
enum = enum_for(*args)
|
|
632
|
+
return enum unless block
|
|
633
|
+
enum.each(&block)
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# map, collect の再定義
|
|
637
|
+
#
|
|
638
|
+
# has-a 関係の子 Resource に対して map/collect を行う
|
|
639
|
+
#
|
|
640
|
+
# @param [Block] block 実行するブロック
|
|
641
|
+
#
|
|
642
|
+
# @return [Array]
|
|
643
|
+
#
|
|
644
|
+
def map(&block)
|
|
645
|
+
@child.map(&block)
|
|
646
|
+
end
|
|
647
|
+
alias :collect :map
|
|
648
|
+
|
|
649
|
+
protected
|
|
650
|
+
|
|
651
|
+
# @private
|
|
652
|
+
def pool_keys
|
|
653
|
+
_pool.keys
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
private
|
|
657
|
+
|
|
658
|
+
# 属性の設定
|
|
659
|
+
def _attributes(args)
|
|
660
|
+
options =_get_options(args)
|
|
661
|
+
_set_variables(options)
|
|
662
|
+
return args, options
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# option の読み出し
|
|
666
|
+
def _get_options(args)
|
|
667
|
+
options = args[-1].kind_of?(Hash) ? args.pop : {}
|
|
668
|
+
@_pool = {}
|
|
669
|
+
@_pool['..'] = options['..'] if (options['..'])
|
|
670
|
+
|
|
671
|
+
# 配下のオブジェクトの生成と関連付け
|
|
672
|
+
if (options.key?('.'))
|
|
673
|
+
_child(options)
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
options
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# 変数の設定
|
|
680
|
+
def _set_variables(options)
|
|
681
|
+
@options = options[:options] || {} if options.key?(:options)
|
|
682
|
+
options.each_pair do |key,value|
|
|
683
|
+
unless (key =~ /^options$|^[_.]/)
|
|
684
|
+
# スキームの":"がエンコーディングされていたら、valueをデコード
|
|
685
|
+
if (value =~ /^\w+%3A/i)
|
|
686
|
+
value.gsub!(/%[0-9A-F]{2}/i) do |c|
|
|
687
|
+
c.sub(/%/,'0x').hex.chr
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
case "#{key}"
|
|
691
|
+
when 'namespace' ; value = Locale._namespace(value)
|
|
692
|
+
when 'locale' ; value = Locale._locale(value)
|
|
693
|
+
end
|
|
694
|
+
instance_variable_set("@#{key}", value)
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
# 配下のオブジェクトの生成
|
|
700
|
+
def _child(options)
|
|
701
|
+
@child = []
|
|
702
|
+
query = options.dup
|
|
703
|
+
options['..'] = self
|
|
704
|
+
leaf = options['.']
|
|
705
|
+
label_candidates = nil
|
|
706
|
+
|
|
707
|
+
leaf.each_index do |i|
|
|
708
|
+
element = Resource._parse(leaf[i])
|
|
709
|
+
case element
|
|
710
|
+
when Array
|
|
711
|
+
if element[0].kind_of?(Class)
|
|
712
|
+
list = []
|
|
713
|
+
element.each do |e|
|
|
714
|
+
if e.kind_of?(Hash)
|
|
715
|
+
list += e.keys.map {|key| Resource::Element.new(key, e[key])}
|
|
716
|
+
else
|
|
717
|
+
list << e
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
options['.'] = list
|
|
721
|
+
@child << element[0].new(options.dup)
|
|
722
|
+
else
|
|
723
|
+
options.delete('.')
|
|
724
|
+
@child << self.class.new(*(element + [options]))
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
when Resource::Element
|
|
728
|
+
key = element.predicate
|
|
729
|
+
value = element.object
|
|
730
|
+
if (value)
|
|
731
|
+
case key
|
|
732
|
+
when 'namespace'
|
|
733
|
+
options[key] ||= {}
|
|
734
|
+
options[key] = options[key].merge(Locale._namespace(value))
|
|
735
|
+
when 'locale'
|
|
736
|
+
options[key] = Locale._locale(value)
|
|
737
|
+
else
|
|
738
|
+
if (value.instance_of?(String) && value =~ /^\[/)
|
|
739
|
+
options.delete('.')
|
|
740
|
+
value = m17n(value, nil, nil, options.dup)
|
|
741
|
+
@_pool[value.to_s] = value
|
|
742
|
+
end
|
|
743
|
+
if element.marked || key == self.class::LabelProperty
|
|
744
|
+
@label = value
|
|
745
|
+
else
|
|
746
|
+
options[key] = value
|
|
747
|
+
label_candidates ||= value
|
|
748
|
+
end
|
|
749
|
+
end
|
|
750
|
+
else
|
|
751
|
+
options.delete(key)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
options.update(query)
|
|
756
|
+
unless @label
|
|
757
|
+
raise ArgumentError, "label attribute not found: #{leaf}" unless label_candidates
|
|
758
|
+
@label = label_candidates
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# 配下のオブジェクトの前後関係の設定
|
|
763
|
+
def _sequence
|
|
764
|
+
return unless @child
|
|
765
|
+
prev = @_pool['..'].child[-1] if @_pool['..'].respond_to?(:child)
|
|
766
|
+
@child.each do |v|
|
|
767
|
+
if prev
|
|
768
|
+
v._pool['.<-'] = prev
|
|
769
|
+
prev._pool['.->'] = v
|
|
770
|
+
while (prev.child && prev.child[-1]) do
|
|
771
|
+
prev = prev.child[-1]
|
|
772
|
+
prev._pool['.->'] = v
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
@_pool[v.label.to_s] = v
|
|
776
|
+
prev = v
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
# その他のメソッド
|
|
781
|
+
# When::Parts::GeometricComplex で定義されていないメソッドは
|
|
782
|
+
# 処理を @child (type: Array) に委譲する
|
|
783
|
+
#
|
|
784
|
+
def method_missing(name, *args, &block)
|
|
785
|
+
@child.send(name.to_sym, *args, &block)
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
#
|
|
789
|
+
# オブジェクトを順に取り出す enumerator
|
|
790
|
+
#
|
|
791
|
+
class Enumerator < When::Parts::Enumerator
|
|
792
|
+
|
|
793
|
+
#
|
|
794
|
+
# 次のオブジェクトを取り出す
|
|
795
|
+
#
|
|
796
|
+
# @return [When::Parts::Resource]
|
|
797
|
+
#
|
|
798
|
+
def succ
|
|
799
|
+
value = @current
|
|
800
|
+
@current = (@current==:first) ? @first : ((@direction == :reverse) ? @current.prev : @current.next)
|
|
801
|
+
@current = nil unless @first.leaf? || @first.include?(@current)
|
|
802
|
+
return value
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
end
|
|
806
|
+
end
|