when_exe 0.2.100 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/LICENSE.ja.txt +25 -25
  2. data/LICENSE.txt +31 -31
  3. data/bin/irb.rc +5 -0
  4. data/bin/locales.rb +2 -2
  5. data/bin/when.rb +16 -0
  6. data/bin/when.rb.config +7 -0
  7. data/lib/when_exe.rb +616 -14
  8. data/lib/when_exe/basictypes.rb +615 -0
  9. data/lib/when_exe/calendartypes.rb +1700 -0
  10. data/lib/when_exe/coordinates.rb +1936 -0
  11. data/lib/when_exe/core/compatibility.rb +54 -0
  12. data/lib/when_exe/core/duration.rb +72 -72
  13. data/lib/when_exe/core/extension.rb +382 -0
  14. data/lib/when_exe/ephemeris.rb +1845 -0
  15. data/lib/when_exe/googlecalendar.rb +140 -0
  16. data/lib/when_exe/icalendar.rb +1587 -0
  17. data/lib/when_exe/inspect.rb +1237 -0
  18. data/lib/when_exe/locales/af.rb +90 -0
  19. data/lib/when_exe/locales/ar.rb +145 -0
  20. data/lib/when_exe/locales/az.rb +90 -0
  21. data/lib/when_exe/locales/bg.rb +90 -0
  22. data/lib/when_exe/locales/bn.rb +94 -0
  23. data/lib/when_exe/locales/bs.rb +121 -0
  24. data/lib/when_exe/locales/ca.rb +92 -0
  25. data/lib/when_exe/locales/cs.rb +107 -0
  26. data/lib/when_exe/locales/cy.rb +150 -0
  27. data/lib/when_exe/locales/da.rb +84 -0
  28. data/lib/when_exe/locales/de.rb +92 -0
  29. data/lib/when_exe/locales/de_AT.rb +92 -0
  30. data/lib/when_exe/locales/de_CH.rb +92 -0
  31. data/lib/when_exe/locales/el.rb +93 -0
  32. data/lib/when_exe/locales/en.rb +88 -0
  33. data/lib/when_exe/locales/en_AU.rb +88 -0
  34. data/lib/when_exe/locales/en_CA.rb +88 -0
  35. data/lib/when_exe/locales/en_GB.rb +88 -0
  36. data/lib/when_exe/locales/en_IN.rb +88 -0
  37. data/lib/when_exe/locales/en_NZ.rb +88 -0
  38. data/lib/when_exe/locales/eo.rb +89 -0
  39. data/lib/when_exe/locales/es.rb +84 -0
  40. data/lib/when_exe/locales/es_419.rb +84 -0
  41. data/lib/when_exe/locales/es_AR.rb +84 -0
  42. data/lib/when_exe/locales/es_CL.rb +84 -0
  43. data/lib/when_exe/locales/es_CO.rb +84 -0
  44. data/lib/when_exe/locales/es_MX.rb +84 -0
  45. data/lib/when_exe/locales/es_PE.rb +85 -0
  46. data/lib/when_exe/locales/es_VE.rb +84 -0
  47. data/lib/when_exe/locales/et.rb +94 -0
  48. data/lib/when_exe/locales/eu.rb +95 -0
  49. data/lib/when_exe/locales/fa.rb +80 -0
  50. data/lib/when_exe/locales/fi.rb +89 -0
  51. data/lib/when_exe/locales/fr.rb +88 -0
  52. data/lib/when_exe/locales/fr_CA.rb +88 -0
  53. data/lib/when_exe/locales/fr_CH.rb +88 -0
  54. data/lib/when_exe/locales/gl.rb +81 -0
  55. data/lib/when_exe/locales/he.rb +84 -0
  56. data/lib/when_exe/locales/hi.rb +80 -0
  57. data/lib/when_exe/locales/hi_IN.rb +84 -0
  58. data/lib/when_exe/locales/hr.rb +128 -0
  59. data/lib/when_exe/locales/hu.rb +84 -0
  60. data/lib/when_exe/locales/id.rb +89 -0
  61. data/lib/when_exe/locales/is.rb +89 -0
  62. data/lib/when_exe/locales/it.rb +87 -0
  63. data/lib/when_exe/locales/it_CH.rb +87 -0
  64. data/lib/when_exe/locales/ja.rb +78 -0
  65. data/lib/when_exe/locales/kn.rb +86 -0
  66. data/lib/when_exe/locales/ko.rb +78 -0
  67. data/lib/when_exe/locales/links.rb +2342 -0
  68. data/lib/when_exe/locales/lo.rb +123 -0
  69. data/lib/when_exe/locales/locales.rb +91 -0
  70. data/lib/when_exe/locales/lt.rb +111 -0
  71. data/lib/when_exe/locales/lv.rb +118 -0
  72. data/lib/when_exe/locales/mk.rb +93 -0
  73. data/lib/when_exe/locales/mn.rb +80 -0
  74. data/lib/when_exe/locales/nb.rb +81 -0
  75. data/lib/when_exe/locales/ne.rb +81 -0
  76. data/lib/when_exe/locales/nl.rb +92 -0
  77. data/lib/when_exe/locales/nn.rb +73 -0
  78. data/lib/when_exe/locales/or.rb +84 -0
  79. data/lib/when_exe/locales/pl.rb +128 -0
  80. data/lib/when_exe/locales/pt.rb +88 -0
  81. data/lib/when_exe/locales/pt_BR.rb +88 -0
  82. data/lib/when_exe/locales/rm.rb +143 -0
  83. data/lib/when_exe/locales/ro.rb +105 -0
  84. data/lib/when_exe/locales/ru.rb +128 -0
  85. data/lib/when_exe/locales/sk.rb +109 -0
  86. data/lib/when_exe/locales/sl.rb +122 -0
  87. data/lib/when_exe/locales/sr.rb +122 -0
  88. data/lib/when_exe/locales/sv.rb +83 -0
  89. data/lib/when_exe/locales/sw.rb +89 -0
  90. data/lib/when_exe/locales/th.rb +78 -0
  91. data/lib/when_exe/locales/tl.rb +99 -0
  92. data/lib/when_exe/locales/tr.rb +96 -0
  93. data/lib/when_exe/locales/uk.rb +128 -0
  94. data/lib/when_exe/locales/uz.rb +128 -0
  95. data/lib/when_exe/locales/vi.rb +94 -0
  96. data/lib/when_exe/locales/wo.rb +82 -0
  97. data/lib/when_exe/locales/zh_CN.rb +77 -0
  98. data/lib/when_exe/locales/zh_HK.rb +77 -0
  99. data/lib/when_exe/locales/zh_TW.rb +77 -0
  100. data/lib/when_exe/mini_application.rb +252 -0
  101. data/lib/when_exe/parts/enumerator.rb +472 -0
  102. data/lib/when_exe/parts/geometric_complex.rb +379 -0
  103. data/lib/when_exe/parts/locale.rb +513 -0
  104. data/lib/when_exe/parts/method_cash.rb +207 -0
  105. data/lib/when_exe/parts/resource.rb +806 -0
  106. data/lib/when_exe/parts/timezone.rb +182 -0
  107. data/lib/when_exe/region/bahai.rb +145 -0
  108. data/lib/when_exe/region/balinese.rb +627 -0
  109. data/lib/when_exe/region/chinese.rb +896 -0
  110. data/lib/when_exe/region/chinese_calendar.rb +919 -0
  111. data/lib/when_exe/region/chinese_epoch.rb +1245 -0
  112. data/lib/when_exe/region/christian.rb +644 -0
  113. data/lib/when_exe/region/far_east.rb +192 -0
  114. data/lib/when_exe/region/french.rb +66 -0
  115. data/lib/when_exe/region/geologicalage.rb +639 -0
  116. data/lib/when_exe/region/indian.rb +1066 -0
  117. data/lib/when_exe/region/iranian.rb +66 -0
  118. data/lib/when_exe/region/islamic.rb +105 -0
  119. data/lib/when_exe/region/japanese.rb +851 -0
  120. data/lib/when_exe/region/japanese_notes.rb +964 -0
  121. data/lib/when_exe/region/japanese_residues.rb +1149 -0
  122. data/lib/when_exe/region/javanese.rb +228 -0
  123. data/lib/when_exe/region/jewish.rb +127 -0
  124. data/lib/when_exe/region/korean.rb +267 -0
  125. data/lib/when_exe/region/m17n.rb +115 -0
  126. data/lib/when_exe/region/martian.rb +215 -0
  127. data/lib/when_exe/region/mayan.rb +122 -0
  128. data/lib/when_exe/region/moon.rb +333 -0
  129. data/lib/when_exe/region/nihon_shoki.rb +73 -0
  130. data/lib/when_exe/region/planets.rb +585 -0
  131. data/lib/when_exe/region/pope.rb +298 -0
  132. data/lib/when_exe/region/residue.rb +229 -0
  133. data/lib/when_exe/region/roman.rb +325 -0
  134. data/lib/when_exe/region/ryukyu.rb +98 -0
  135. data/lib/when_exe/region/shire.rb +254 -0
  136. data/lib/when_exe/region/sun.rb +210 -0
  137. data/lib/when_exe/region/thai.rb +227 -0
  138. data/lib/when_exe/region/tibetan.rb +233 -0
  139. data/lib/when_exe/region/v50.rb +111 -0
  140. data/lib/when_exe/region/vietnamese.rb +173 -0
  141. data/lib/when_exe/region/world.rb +197 -0
  142. data/lib/when_exe/timestandard.rb +547 -0
  143. data/lib/when_exe/tmduration.rb +330 -330
  144. data/lib/when_exe/tmobjects.rb +1295 -0
  145. data/lib/when_exe/tmposition.rb +1955 -0
  146. data/lib/when_exe/tmreference.rb +1547 -0
  147. data/lib/when_exe/version.rb +10 -3
  148. data/link_to_online_documents +4 -0
  149. data/test/examples/JapanHolidays.ics +456 -0
  150. data/test/examples/Millennium.ics +17 -0
  151. data/test/examples/NewYork.ics +61 -0
  152. data/test/examples/Residue.m17n +135 -0
  153. data/test/examples/Spatial.m17n +179 -0
  154. data/test/examples/Terms.m17n +39 -0
  155. data/test/examples/Test.ics +53 -0
  156. data/test/examples/USA-DST.ics +61 -0
  157. data/test/examples/geometric_complex.rb +41 -0
  158. data/test/examples/sample.xml +14 -0
  159. data/test/examples/today.rb +61 -0
  160. data/test/test.rb +54 -19
  161. data/test/test.rb.config +1 -0
  162. data/test/test/basictypes.rb +368 -0
  163. data/test/test/calendartypes.rb +57 -0
  164. data/test/test/coordinates.rb +380 -0
  165. data/test/test/ephemeris.rb +127 -0
  166. data/test/test/googlecalendar.rb +167 -0
  167. data/test/test/icalendar.rb +848 -0
  168. data/test/test/inspect.rb +115 -0
  169. data/test/test/parts.rb +480 -0
  170. data/test/test/region/chinese.rb +161 -0
  171. data/test/test/region/french.rb +33 -0
  172. data/test/test/region/geologicalage.rb +14 -0
  173. data/test/test/region/indian.rb +55 -0
  174. data/test/test/region/iran.rb +54 -0
  175. data/test/test/region/islamic.rb +18 -0
  176. data/test/test/region/japanese.rb +62 -0
  177. data/test/test/region/jewish.rb +61 -0
  178. data/test/test/region/m17n.rb +181 -0
  179. data/test/test/region/mayan.rb +78 -0
  180. data/test/test/region/moon.rb +14 -0
  181. data/test/test/region/planets.rb +14 -0
  182. data/test/test/region/residue.rb +123 -0
  183. data/test/test/region/sun.rb +14 -0
  184. data/test/test/region/thai.rb +94 -0
  185. data/test/test/region/tibetan.rb +30 -0
  186. data/test/test/tmobjects.rb +356 -57
  187. data/test/test/tmposition.rb +237 -0
  188. data/test/test/tmreference.rb +95 -0
  189. data/when_exe.gemspec +2 -2
  190. metadata +187 -7
  191. data/doc/COPYING +0 -31
  192. data/doc/COPYING.ja +0 -25
  193. data/doc/document_url +0 -1
@@ -0,0 +1,1295 @@
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
+ module When::TM
9
+ #
10
+ # (5.2) Temporal Objects Package
11
+ #
12
+ #
13
+
14
+ #
15
+ # 長さと距離を計算するための操作を規定する
16
+ #
17
+ module Separation
18
+
19
+ # When::TM::GeometricPrimitive 自身の持続時間
20
+ #
21
+ # @return [When::TM::Duration]
22
+ #
23
+ # @abstract
24
+ #
25
+ def length
26
+ raise TypeError, "Absolute Class #{self.class}"
27
+ end
28
+
29
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
30
+ #
31
+ # @param [When::TM::GeometricPrimitive] other
32
+ #
33
+ # @return [When::TM::Duration]
34
+ #
35
+ # @abstract
36
+ #
37
+ def distance(other)
38
+ raise TypeError, "Absolute Class #{self.class}"
39
+ end
40
+
41
+ end
42
+
43
+ #
44
+ # 互いの相対位置を判定する操作を規定する
45
+ #
46
+ module Order
47
+
48
+ # 他のWhen::TM::Primitiveとの相対的な時間位置
49
+ #
50
+ # @param [When::TM::Primitive] other
51
+ #
52
+ # @return [When::TM::RelativePosition]
53
+ #
54
+ # @abstract
55
+ #
56
+ def relative_position(other)
57
+ raise TypeError, "Absolute Class #{self.class}"
58
+ end
59
+ alias :relativePosition :relative_position
60
+
61
+ end
62
+
63
+ # 相対的な時間位置
64
+ #
65
+ # Allen(1983) が分類した13種類の相対的な時間位置を定義している
66
+ #
67
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#RelatedTimeType gml schema}
68
+ #
69
+ # see Allen,J.F., Maintaining Knowledge about Temporal Intervals, Communications of the ACM, 1983,vol.26 pp.832-843
70
+ #
71
+ module RelativePosition
72
+
73
+ Before = :Before
74
+ After = :After
75
+ Begins = :Begins
76
+ Ends = :Ends
77
+ During = :During
78
+ Equals = :Equals
79
+ Contains = :Contains
80
+ Overlaps = :Overlaps
81
+ Meets = :Meets
82
+ OverlappedBy = :OverlappedBy
83
+ MetBy = :MetBy
84
+ BegunBy = :BegunBy
85
+ EndedBy = :EndedBy
86
+
87
+ end
88
+
89
+ # 時間のオブジェクト
90
+ #
91
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeObjectType gml schema}
92
+ #
93
+ class Object < When::BasicTypes::Object
94
+
95
+ end
96
+
97
+ # 複数の時間プリミティブの集成
98
+ #
99
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeComplexType gml schema}
100
+ #
101
+ class Complex < Object
102
+
103
+ end
104
+
105
+ # 位相複体 - 連結した位相プリミティブの集合
106
+ #
107
+ # A temporal topology complex.
108
+ #
109
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeTopologyComplexType gml schema}
110
+ #
111
+ class TopologicalComplex < Complex
112
+
113
+ # 対応するプリミティブ (relation - Complex)
114
+ #
115
+ # @return [Array<When::TM::TopologicalPrimitive>]
116
+ #
117
+ attr_reader :primitive
118
+
119
+ # オブジェクトの生成
120
+ #
121
+ # @param [When::TM::TopologicalPrimitive] primitive 対応するプリミティブの Array
122
+ #
123
+ def initialize(primitive)
124
+ @primitive = primitive
125
+ @primitive.each do |p|
126
+ p.complex << self
127
+ end
128
+ end
129
+ end
130
+
131
+ # 時間プリミティブ
132
+ #
133
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimePrimitiveType gml schema}
134
+ #
135
+ class Primitive < Object
136
+
137
+ include Order
138
+
139
+ end
140
+
141
+ # 時間幾何プリミティブ
142
+ #
143
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#AbstractTimeGeometricPrimitiveType gml schema}
144
+ #
145
+ class GeometricPrimitive < Primitive
146
+
147
+ include Separation
148
+
149
+ end
150
+
151
+ # 瞬間 - 零次元幾何プリミティブ
152
+ #
153
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimeInstantType gml schema}
154
+ #
155
+ class Instant < GeometricPrimitive
156
+
157
+ # この瞬間の時間位置
158
+ #
159
+ # @return [When::TM::Position]
160
+ #
161
+ attr_reader :position
162
+
163
+ # この瞬間を始まりとする期間 (relation - Beginning)
164
+ #
165
+ # @return [Array<When::TM::Period>]
166
+ #
167
+ attr_reader :begun_by
168
+ alias :begunBy :begun_by
169
+
170
+ # この瞬間を終わりとする期間 (relation - Ending)
171
+ #
172
+ # @return [Array<When::TM::Period>]
173
+ #
174
+ attr_reader :ended_by
175
+ alias :endedBy :ended_by
176
+
177
+ # 対応するノード (relation - Realization)
178
+ #
179
+ # @return [When::TM::Node]
180
+ #
181
+ attr_reader :topology
182
+
183
+ # When::TM::GeometricPrimitive 自身の持続時間
184
+ #
185
+ # @return [When::TM::Duration]
186
+ #
187
+ def length()
188
+ return When.Duration(0)
189
+ end
190
+
191
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
192
+ #
193
+ # @param [When::TM::GeometricPrimitive] other
194
+ #
195
+ # @return [When::TM::Duration]
196
+ #
197
+ def distance(other)
198
+ case other
199
+ when Instant
200
+ return (self.position - other.position).abs
201
+ when Period
202
+ verify = other.begin.position - self.position
203
+ return verify if verify.sign >= 0
204
+ return [self.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
205
+ else
206
+ raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
207
+ end
208
+ end
209
+
210
+ # 他のWhen::TM::Primitiveとの相対的な時間位置
211
+ #
212
+ # @param [When::TM::Primitive] other
213
+ #
214
+ # @return [When::TM::RelativePosition]
215
+ #
216
+ def relative_position(other)
217
+ case other
218
+ when Instant
219
+ verify = self.position <=> other.position
220
+ return RelativePosition::Before if verify < 0
221
+ return RelativePosition::Equals if verify == 0
222
+ return RelativePosition::After
223
+ when Period
224
+ verify = self.position <=> other.begin.position
225
+ return RelativePosition::Before if verify < 0
226
+ return RelativePosition::Begins if verify == 0
227
+ verify = self.position <=> other.end.position
228
+ return RelativePosition::During if verify < 0
229
+ return RelativePosition::Ends if verify == 0
230
+ return RelativePosition::After
231
+ else
232
+ raise TypeError, "The right operand should be When::TM::Instant or When::TM::Period"
233
+ end
234
+ end
235
+ alias :relativePosition :relative_position
236
+
237
+ # オブジェクトの生成
238
+ #
239
+ # @param [When::TM::Position] position 対応する時間位置
240
+ #
241
+ def initialize(position)
242
+ @position = position
243
+ @begun_by = []
244
+ @ended_by = []
245
+ end
246
+
247
+ private
248
+
249
+ # その他のメソッド
250
+ #
251
+ # @note
252
+ # When::TM::Instant で定義されていないメソッドは
253
+ # 処理を @position (type: When::TM::Position) に委譲する
254
+ #
255
+ def method_missing(name, *args, &block)
256
+ @position.send(name.to_sym, *args, &block)
257
+ end
258
+ end
259
+
260
+ # 期間 - 一次元幾何プリミティブ
261
+ #
262
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#TimePeriodType gml schema}
263
+ #
264
+ class Period < GeometricPrimitive
265
+
266
+ RELATIVE_POSITION = {
267
+ RelativePosition::Contains => {
268
+ RelativePosition::Before => RelativePosition::Overlaps,
269
+ RelativePosition::EndedBy => RelativePosition::EndedBy,
270
+ RelativePosition::Contains => RelativePosition::Contains
271
+ },
272
+ RelativePosition::BegunBy => {
273
+ RelativePosition::Before => RelativePosition::Begins,
274
+ RelativePosition::EndedBy => RelativePosition::Equals,
275
+ RelativePosition::Contains => RelativePosition::BegunBy
276
+ },
277
+ RelativePosition::After => {
278
+ RelativePosition::Before => RelativePosition::During,
279
+ RelativePosition::EndedBy => RelativePosition::Ends,
280
+ RelativePosition::Contains => RelativePosition::OverlappedBy
281
+ }
282
+ }
283
+
284
+ # この期間が始まる瞬間 (relation - Beginning)
285
+ #
286
+ # @return [When::TM::Instant]
287
+ #
288
+ attr_reader :begin
289
+
290
+ # この期間が終わる瞬間 (relation - Ending)
291
+ #
292
+ # @return [When::TM::Instant]
293
+ #
294
+ attr_reader :end
295
+
296
+ # 対応するエッジ (relation - Realization)
297
+ #
298
+ # @return [When::TM::Edge]
299
+ #
300
+ attr_reader :topology
301
+
302
+ # When::TM::GeometricPrimitive 自身の持続時間
303
+ #
304
+ # @return [When::TM::Duration]
305
+ #
306
+ def length()
307
+ @length ||= @end - @begin
308
+ end
309
+
310
+ # 他のWhen::TM::GeometricPrimitiveとの時間位置の差の絶対値
311
+ #
312
+ # @param [When::TM::GeometricPrimitive] other
313
+ #
314
+ # @return [When::TM::Duration]
315
+ #
316
+ def distance(other)
317
+ case other
318
+ when Instant
319
+ return other.distance(self)
320
+ when Period
321
+ verify = other.begin.position - self.end.position
322
+ return verify if verify.sign >= 0
323
+ return [self.begin.position - other.end.position, When::TM::PeriodDuration.new(0,When::DAY)].max
324
+ else
325
+ raise TypeError, "The right operand should be Instant or Period"
326
+ end
327
+ end
328
+
329
+ # 他のPrimitiveとの相対的な時間位置
330
+ #
331
+ # @param [When::TM::Primitive] other
332
+ #
333
+ # @return [When::TM::RelativePosition]
334
+ #
335
+ def relative_position(other)
336
+ case other
337
+ when Instant
338
+ verify = self.end.position <=> other.position
339
+ return RelativePosition::Before if verify < 0
340
+ return RelativePosition::EndedBy if verify == 0
341
+ verify = self.begin.position <=> other.position
342
+ return RelativePosition::Contains if verify < 0
343
+ return RelativePosition::BegunBy if verify == 0
344
+ return RelativePosition::After
345
+ when Period
346
+ verify_b = relative_position(other.begin)
347
+ case verify_b
348
+ when RelativePosition::Before ; return RelativePosition::Before
349
+ when RelativePosition::EndedBy ; return RelativePosition::Meets
350
+ end
351
+ verify_e = relative_position(other.end)
352
+ case verify_e
353
+ when RelativePosition::BegunBy ; return RelativePosition::MetBy
354
+ when RelativePosition::After ; return RelativePosition::After
355
+ else ; return RELATIVE_POSITION[verify_b][verify_e]
356
+ end
357
+ else
358
+ raise TypeError, "The right operand should be Instant or Period"
359
+ end
360
+ end
361
+ alias :relativePosition :relative_position
362
+
363
+ # オブジェクトの生成
364
+ #
365
+ # @param [When::TM::Instant] begun 始点
366
+ #
367
+ # @param [When::TM::Instant] ended 終点
368
+ #
369
+ def initialize(begun, ended)
370
+ raise ArgumentError, 'Order mismatch: begun > ended' if begun > ended
371
+ @begin = begun
372
+ @end = ended
373
+ @begin.begun_by << self
374
+ @end.ended_by << self
375
+ end
376
+
377
+ private
378
+
379
+ # その他のメソッド
380
+ #
381
+ # @note
382
+ # When::TM::Period で定義されていないメソッドは
383
+ # 処理を @begin (type: When::TM::Instant) に委譲する
384
+ #
385
+ def method_missing(name, *args, &block)
386
+ @begin.send(name.to_sym, *args, &block)
387
+ end
388
+ end
389
+
390
+ # 時間位相プリミティブ - 単独で不可分な位相要素
391
+ #
392
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#AbstractTimeTopologyPrimitiveType gml schema}
393
+ #
394
+ class TopologicalPrimitive < Primitive
395
+
396
+ # 対応するコンプレックス (relation - Complex)
397
+ #
398
+ # @return [Array<When::TM::TopologicalComplex>]
399
+ #
400
+ attr_accessor :complex
401
+
402
+ #
403
+ # オブジェクトの生成
404
+ #
405
+ def initialize
406
+ @complex = []
407
+ end
408
+
409
+ private
410
+
411
+ # その他のメソッド
412
+ #
413
+ # @note
414
+ # When::TM::TopologicalPrimitive で定義されていないメソッドは
415
+ # 処理を @geometry (type: When::TM::Instant) に委譲する
416
+ #
417
+ def method_missing(name, *args, &block)
418
+ @geometry.send(name.to_sym, *args, &block)
419
+ end
420
+ end
421
+
422
+ # 零次元位相プリミティブ - 幾何的実現は When::TM::Instant と対応する
423
+ #
424
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeNodeType gml schema}
425
+ #
426
+ class Node < TopologicalPrimitive
427
+
428
+ # 対応するエッジ (relation - Termination)
429
+ #
430
+ # @return [Array<When::TM::Edge>]
431
+ #
432
+ attr_reader :previous_edge
433
+ alias :previousEdge :previous_edge
434
+
435
+ # 対応するエッジ (relation - Initiation)
436
+ #
437
+ # @return [Array<When::TM::Edge>]
438
+ #
439
+ attr_reader :next_edge
440
+ alias :nextEdge :next_edge
441
+
442
+ # 対応する瞬間 (relation - Realization)
443
+ #
444
+ # @return [When::TM::Instant]
445
+ #
446
+ attr_reader :geometry
447
+
448
+ # オブジェクトの生成
449
+ #
450
+ # @param [When::TM::Instant] geometry 対応する瞬間
451
+ #
452
+ def initialize(geometry)
453
+ super()
454
+ @previous_edge = []
455
+ @next_edge = []
456
+ @geometry = geometry
457
+ @geometry.topology = self
458
+ end
459
+ end
460
+
461
+ # 一次元位相プリミティブ - 幾何的実現は When::TM::Period と対応する
462
+ #
463
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd#TimeEdgeType gml schema}
464
+ #
465
+ class Edge < TopologicalPrimitive
466
+
467
+ # 対応するノード (relation - Termination)
468
+ #
469
+ # @return [When::TM::Node]
470
+ #
471
+ attr_reader :end
472
+
473
+ # 対応するノード (relation - Initiation)
474
+ #
475
+ # @return [When::TM::Node]
476
+ #
477
+ attr_reader :start
478
+
479
+ # 対応する期間 (relation - Realization)
480
+ #
481
+ # @return [When::TM::Period]
482
+ #
483
+ attr_reader :geometry
484
+
485
+ # オブジェクトの生成
486
+ #
487
+ # @param [When::TM::Node] start 始点
488
+ #
489
+ # @param [When::TM::Node] ended 終点
490
+ #
491
+ def initialize(start, ended)
492
+ super()
493
+ @start = start
494
+ @end = ended
495
+ @geometry = Period.new(@start.geometry, @end.geometry)
496
+ @geometry.topology = self
497
+ @start.next_edge << self
498
+ @end.previous_edge << self
499
+ end
500
+ end
501
+
502
+ # 時間次元における長さ又は距離を記述するために使うデータ型
503
+ #
504
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#duration gml schema}
505
+ #
506
+ class Duration
507
+
508
+ #
509
+ # When::TM::IntervalLength への変換
510
+ #
511
+ # @return [When::TM::IntervalLength]
512
+ #
513
+ def to_interval_length
514
+ [['week', WEEK], ['day', DAY], ['hour', HOUR], ['minute', MINUTE], ['second', SECOND]].each do |unit|
515
+ div, mod = duration.divmod(unit[1])
516
+ return When::TM::IntervalLength.new(div, unit[0]) if mod == 0
517
+ end
518
+ When::TM::IntervalLength.new(duration / SECOND, 'second')
519
+ end
520
+
521
+ #
522
+ # When::TM::PeriodDuration への変換
523
+ #
524
+ # @return [When::TM::PeriodDuration]
525
+ #
526
+ def to_period_duration
527
+ [[When::WEEK, WEEK], [When::DAY, DAY], [When::HOUR, HOUR], [When::MINUTE, MINUTE], [When::SECOND, SECOND]].each do |unit|
528
+ div, mod = duration.divmod(unit[1])
529
+ return When::TM::PeriodDuration.new(div, unit[0]) if mod == 0
530
+ end
531
+ When::TM::PeriodDuration.new(duration / SECOND, When::SECOND)
532
+ end
533
+
534
+ #
535
+ # Duration 用の Enumerator
536
+ #
537
+ class Enumerator < When::Parts::Enumerator
538
+
539
+ # 次の時間位置を取得する
540
+ #
541
+ # @return [When::TM::TemporalPosition] 次の時間位置
542
+ #
543
+ def succ
544
+ value = @current
545
+ @current = (@count_limit.kind_of?(Numeric) && @count >= @count_limit) ? nil :
546
+ (@current==:first) ? @first :
547
+ (@direction==:forward) ? @first + @parent * @count : @first - @parent * @count
548
+ @count += 1
549
+ return value
550
+ end
551
+ end
552
+
553
+ # Enumerator の生成
554
+ #
555
+ # @overload initialize(range, count_limit=nil))
556
+ # @param [Range, When::Parts::GeometricComplex] range
557
+ # [ 始点 - range.first ]
558
+ # [ 終点 - range.last ]
559
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
560
+ #
561
+ # @overload initialize(first, direction, count_limit=nil))
562
+ # @param [When::TM::TemporalPosition] first 始点
563
+ # @param [Symbol] direction
564
+ # [ :forward - 昇順 ]
565
+ # [ :reverse - 降順 ]
566
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
567
+ #
568
+ def _enumerator(*args)
569
+ return Enumerator.new(*args.unshift(self))
570
+ end
571
+ alias :to_enum :_enumerator
572
+ alias :enum_for :_enumerator
573
+ end
574
+
575
+ #
576
+ # ISO 11404 の時間間隔に基づいて定義された When::TM::Duration の subclass
577
+ #
578
+ # see {http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd#timeIntervalLengthType gml schema}
579
+ #
580
+ class IntervalLength < Duration
581
+
582
+ Alias = {'Y'=>'year', 'M'=>'month' , 'D'=>'day', 'W'=>'week', 'S'=>'system',
583
+ 'h'=>'hour', 'm'=>'minute', 's'=>'second'}
584
+
585
+ # Interval Length 形式の表現を分解して配列化する
586
+ #
587
+ # @param [String] interval
588
+ #
589
+ # @return [Array<Numeric, String>] ( value, unit_name, factor, radix )
590
+ # [ value [Numeric] - 時間間隔 / 単位 ]
591
+ # [ unit_name [String] - 単位名 ]
592
+ # [ factor [Numeric] - 冪乗 ]
593
+ # [ radix [Numeric] - 冪乗の基数 ]
594
+ #
595
+ def self._to_array(interval)
596
+ return nil unless interval =~ /^([-+]?[\d.]+)(?:(E|X|\((\d+)\))([-+]?\d+))?([A-Za-z]+|\*([\d.]+)S)$/
597
+ value, radix, radix_quantity, factor, unit, unit_quantity = $~[1..6]
598
+ value = When::Coordinates::Pair._en_number(value)
599
+ radix = case radix
600
+ when 'E', nil ; 10
601
+ when 'X' ; 60
602
+ else ; radix_quantity.to_i
603
+ end
604
+ factor = factor ? -factor.to_i : 0
605
+ return [value, unit_quantity, factor, radix] if unit_quantity
606
+ unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]]
607
+ return [value, UnitName[unit_quantity], factor, radix] if unit_quantity
608
+ return nil
609
+ end
610
+
611
+ # 時間間隔の長さ (128秒単位)
612
+ #
613
+ # @return [Numeric]
614
+ #
615
+ protected :duration=
616
+
617
+ # 時間間隔を表現するために使用した測定単位の名称
618
+ #
619
+ # @return [String] (year|month|week|day|hour|minute|second|system)
620
+ #
621
+ attr_reader :unit
622
+
623
+ # 時間単位となる乗数の基底となる正の整数
624
+ #
625
+ # @return [Integer]
626
+ #
627
+ attr_reader :radix
628
+
629
+ # 基底のべき乗を行う指数
630
+ #
631
+ # @return [Integer]
632
+ #
633
+ attr_reader :factor
634
+
635
+ # 時間間隔の長さ / 測定単位
636
+ #
637
+ # @return [Numeric]
638
+ #
639
+ attr_accessor :value
640
+ protected :value=
641
+
642
+ #
643
+ # 測定単位の大きさ
644
+ #
645
+ # @return [Numeric]
646
+ #
647
+ attr_reader :unit_quantity
648
+
649
+ # 時刻配列
650
+ #
651
+ # @return [Numeric]
652
+ # When::TM::PeriodDuration との互換性のために提供
653
+ #
654
+ # @private
655
+ #
656
+ def time
657
+ [0, 0, @duration / SECOND]
658
+ end
659
+
660
+ # 日付配列
661
+ #
662
+ # @return [nil]
663
+ # When::TM::PeriodDuration との互換性のために提供
664
+ #
665
+ # @private
666
+ #
667
+ def date
668
+ nil
669
+ end
670
+
671
+ # 暦週配列
672
+ #
673
+ # @return [nil]
674
+ # When::TM::PeriodDuration との互換性のために提供
675
+ #
676
+ # @private
677
+ #
678
+ def weeks
679
+ nil
680
+ end
681
+
682
+ # 符号反転
683
+ #
684
+ # @return [When::TM::IntervalLength]
685
+ #
686
+ def -@
687
+ interval = self.dup
688
+ interval.value = -@value
689
+ interval.duration = -@duration
690
+ return interval
691
+ end
692
+
693
+ #
694
+ # 加算
695
+ #
696
+ # @param [When::TM::Duration] other
697
+ # @param [Numeric] other 秒数
698
+ # @param [その他] other 日時とみなす
699
+ #
700
+ # @return [When::TM::IntervalLength] (other が Numeric, When::TM::Duration の場合)
701
+ # @return [other と同じクラス] (other がその他の場合)
702
+ #
703
+ def +(other)
704
+ case other
705
+ when Duration ; diff = other.duration
706
+ when Numeric ; diff = other * SECOND
707
+ else ; return other + self
708
+ end
709
+ interval = self.dup
710
+ interval.duration = @duration + diff
711
+ internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
712
+ return interval
713
+ end
714
+
715
+ #
716
+ # 減算
717
+ #
718
+ # @param [When::TM::IntervalLength] other
719
+ # @param [Numeric] other 秒数
720
+ #
721
+ # @return [When::TM::IntervalLength]
722
+ #
723
+ def -(other)
724
+ interval = self.dup
725
+ interval.duration = @duration - (other.kind_of?(Duration) ? other.duration : other * SECOND)
726
+ internal.value = interval.duration / (@radix ** (-@factor) * @unit_quantity)
727
+ return interval
728
+ end
729
+
730
+ # 乗算
731
+ #
732
+ # @param [Numeric] times
733
+ #
734
+ # @return [When::TM::IntervalLength]
735
+ #
736
+ def *(times)
737
+ interval = self.dup
738
+ interval.value = times * @value
739
+ interval.duration = times * @duration
740
+ return interval
741
+ end
742
+
743
+ #
744
+ # 除算
745
+ #
746
+ # @param [When::TM::IntervalLength] other
747
+ # @param [Numeric] other 秒数
748
+ #
749
+ # @return [When::TM::IntervalLength] (other が Numeric の場合)
750
+ # @return [Numeric] (other が When::TM::Duration の場合)
751
+ #
752
+ def /(other)
753
+ other.kind_of?(Duration) ? @duration / other.duration : self * (1.0 / other)
754
+ end
755
+
756
+ # 文字列化
757
+ #
758
+ # @return [String]
759
+ #
760
+ def to_s
761
+ expression = @value.to_s
762
+ unless @factor == 0
763
+ case @radix
764
+ when 10 ; expression += 'E'
765
+ when 60 ; expression += 'X'
766
+ else ; expression += '(%d)' % @radix
767
+ end
768
+ expression += '%+d' % (-@factor)
769
+ end
770
+ expression += Alias.invert[@unit] || "*#{When::Coordinates::Pair._en_number(@unit)}S"
771
+ return expression
772
+ end
773
+
774
+ #
775
+ # When::TM::IntervalLength への変換
776
+ #
777
+ # 単なるオブジェクトのコピー
778
+ #
779
+ # @return [When::TM::IntervalLength]
780
+ #
781
+ def to_interval_length
782
+ self.dup
783
+ end
784
+
785
+ # オブジェクトの生成
786
+ #
787
+ # @param [Numeric] value 時間間隔の長さ / 測定単位(省略不可)
788
+ # @param [String] unit 時間間隔を表現するために使用した測定単位の名称(デフォルト : system)
789
+ # ('year'|'month'|'week'|'day'|'hour'|'minute'|'second'|'system')
790
+ # @param [Integer] factor 基底の冪乗を行う指数(デフォルト : 0)
791
+ # @param [Integer] radix 時間単位となる乗数の基底となる正の整数(デフォルト : 10)
792
+ #
793
+ def initialize(value, unit='system', factor=0, radix=10)
794
+ @value, @factor, @radix = value, factor, radix
795
+ @unit_quantity = Unit[unit.downcase] || Unit[Alias[unit[0..0]]] if unit.kind_of?(String)
796
+ @unit_quantity ||= unit.to_f
797
+ raise TypeError, "Wrong Unit Type: #{unit}" unless @unit_quantity.kind_of?(Numeric)
798
+ @unit = UnitName[@unit_quantity] ||
799
+ When::Coordinates::Pair._en_number(@unit_quantity).to_s
800
+ @duration = @value * @radix ** (-@factor) * @unit_quantity
801
+ end
802
+
803
+ # オブジェクトの生成(終点と始点を指定)
804
+ #
805
+ # @param [When::TM::TemporalPosition] ended 終点
806
+ # @param [When::TM::TemporalPosition] begun 始点
807
+ #
808
+ # @return [When::TM::IntervalLength]
809
+ # [ 日単位の精度 - 終点と始点の分解能のいずれかが“日”またはそれより粗い場合 ]
810
+ # [ システム精度 - 終点と始点の分解能がともに“日”より細かい場合 ]
811
+ #
812
+ def self.difference(ended, begun)
813
+ precision = [ended.precision, begun.precision].min
814
+ return new(ended-begun) if precision > When::DAY
815
+ return new(ended.to_i - begun.to_i, unit='day')
816
+ end
817
+
818
+ private
819
+
820
+ # その他のメソッド
821
+ #
822
+ # @note
823
+ # When::TM::IntervalLength で定義されていないメソッドは
824
+ # 処理を @duration (type:Numeric) に委譲する
825
+ #
826
+ def method_missing(name, *args, &block)
827
+ @duration.send(name.to_sym, *args, &block)
828
+ end
829
+ end
830
+
831
+ #
832
+ # ISO 8601 (JIS X0301) の時間間隔に基づいて定義された When::TM::Duration の subclass
833
+ #
834
+ class PeriodDuration < Duration
835
+
836
+ include When
837
+ include Coordinates
838
+
839
+ #
840
+ # When::TM::PeriodDuration オブジェクトが月や年などの可変長の単位に依存する場合
841
+ # に @duration 属性の参照を禁止するために用いる
842
+ #
843
+ module NoDuration
844
+ #
845
+ # 属性 @duration が定義できないとをエラーで示す
846
+ #
847
+ # @return [Numeric]
848
+ #
849
+ def duration
850
+ raise TypeError, "This PeriodDuration object does't have duration value"
851
+ end
852
+ end
853
+
854
+ # ISO 8601 形式の表現を分解して配列化する
855
+ #
856
+ # @param [String] period
857
+ #
858
+ # @return [Array<Numeric, Array<Numeric>>] ( sign, date, time, week )
859
+ # [ sign [Numeric] - +1 , -1 ]
860
+ # [ date [Array<Numeric>] - 年月日 ]
861
+ # [ time [Array<Numeric>] - 時分秒 ]
862
+ # [ week [Array<Numeric>] - 週日 ]
863
+ #
864
+ def self._to_array(period)
865
+
866
+ return nil unless period.gsub(/_+/, '') =~ /^([-+])?P(.*?)?(?:T(.+))?$/
867
+
868
+ sign = ($1 == '-') ? -1 : +1
869
+ pdate, ptime = $~[2..3]
870
+
871
+ # 時分秒形式
872
+ if (ptime =~ /^(?:([.,\d]+)?([:*=])?H)?(?:([.,\d]+)?([:*=])?M)?(?:([.,\d]+)?([:*=])?S)?((?:[.,\d]*[:*=]?X)*)$/)
873
+ trunk = [1,3,5].map {|i|
874
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
875
+ }
876
+ extra = $7 ? $7.scan(/([.,\d]+)?([:*=])?X/).map {|d|
877
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
878
+ } : []
879
+ time = [0] + trunk + extra
880
+ time = nil if time.uniq == [0]
881
+ end
882
+
883
+ case pdate
884
+ # 年月日形式
885
+ when /^((?:[.,\d]*[-*=]?X)*)(?:([.,\d]+)?([-*=])?Y)?(?:([.,\d]+)?([-+*&%!>=<?])?M)?(?:([.,\d]+)?([-*=?%])?D)?$/
886
+ trunk = [2,4,6].map {|i|
887
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
888
+ }
889
+ extra = $1 ? $1.scan(/([.,\d]+)?([:*=])?X/).map {|d|
890
+ d[0] ? Pair._en_pair(d[0], d[1]) : 0
891
+ } : []
892
+ date = extra + trunk
893
+ date = nil if date.uniq == [0]
894
+ return sign, date, time
895
+
896
+ # 週日形式
897
+ when /^(?:([.,\d]+)?([:*=])?W)(?:([.,\d]+)?([-*=?%])?D)?$/
898
+ week = [1,3].map {|i|
899
+ $~[i] ? Pair._en_pair($~[i], $~[i+1]) : 0
900
+ }
901
+ return sign, nil, time if week.uniq == [0]
902
+ date = [0, 0, week[1] + 7*week[0]]
903
+ return sign, date, time, week
904
+
905
+ # 代用形式
906
+ else
907
+ pdate += 'T' + ptime if ptime
908
+ f, d, t, z, e = When::BasicTypes::DateTime._to_array(pdate, {:abbr=>[0]*20})
909
+ return nil if e
910
+ if d
911
+ case f
912
+ when :day ; date = [d[0], 0, d[1]]
913
+ when :century, nil ; date = (0..2).map {|i| d[i]||0}
914
+ when :week ; date, week = [0,0,d[0]*7+(d[1]||0)], [d[0], d[1]||0]
915
+ end
916
+ end
917
+ time = t ? (t.map {|v| v||0}) : nil
918
+ return sign, date, time, week
919
+ end
920
+ end
921
+
922
+ # 期間の日付要素
923
+ #
924
+ # @return [Array<Numeric>]
925
+ #
926
+ attr_accessor :date
927
+ protected :date=
928
+
929
+ # 期間の週日要素
930
+ #
931
+ # @return [Array<Numeric>]
932
+ #
933
+ attr_accessor :week
934
+ protected :week=
935
+
936
+ # 期間の時刻要素
937
+ #
938
+ # @return [Array<Numeric>]
939
+ #
940
+ attr_accessor :time
941
+ protected :time=
942
+
943
+ # 要素の参照
944
+ #
945
+ # @param [Numeric] index When::Coordinates で定義している分解能定数に対応する列挙型( YEAR, ... , SECOND)
946
+ #
947
+ # @return [Numeric]
948
+ #
949
+ def [](index)
950
+ if (index == WEEK)
951
+ return nil unless (@week)
952
+ return @week[0]
953
+ elsif (index <= 0)
954
+ return nil unless (@date)
955
+ return @date[index-1]
956
+ else
957
+ return nil unless (@time)
958
+ return @time[index]
959
+ end
960
+ end
961
+
962
+ # 持続期間であることを文字'P'で示す
963
+ #
964
+ # @return [String]
965
+ #
966
+ def designator
967
+ return 'P'
968
+ end
969
+
970
+ # 期間に含まれる年数を示す
971
+ #
972
+ # @return [Numeric]
973
+ #
974
+ def years
975
+ return nil unless (@date)
976
+ return @date[YEAR-1].to_s
977
+ end
978
+
979
+ # 期間に含まれる月数を示す
980
+ #
981
+ # @return [Numeric]
982
+ #
983
+ def months
984
+ return nil unless (@date)
985
+ return @date[MONTH-1].to_s
986
+ end
987
+
988
+ # 期間に含まれる週数を示す
989
+ #
990
+ # @return [Numeric]
991
+ #
992
+ def weeks
993
+ return nil unless (@week)
994
+ return @week[0].to_s
995
+ end
996
+
997
+ # 期間に含まれる日数を示す
998
+ #
999
+ # @return [Numeric]
1000
+ #
1001
+ def days
1002
+ return nil unless (@date)
1003
+ return @date[DAY-1].to_s
1004
+ end
1005
+
1006
+ # 期間が1日より短い時間単位を含むとき文字'T'で示す
1007
+ #
1008
+ # @return [String]
1009
+ #
1010
+ def time_indicator
1011
+ return (@time) ? 'T' : nil
1012
+ end
1013
+ alias :timeIndicator :time_indicator
1014
+
1015
+ # 期間に含まれる時間数を示す
1016
+ #
1017
+ # @return [Numeric]
1018
+ #
1019
+ def hours
1020
+ return nil unless (@time)
1021
+ return @time[HOUR].to_s
1022
+ end
1023
+
1024
+ # 期間に含まれる分数を示す
1025
+ #
1026
+ # @return [Numeric]
1027
+ #
1028
+ def minutes
1029
+ return nil unless (@time)
1030
+ return @time[MINUTE].to_s
1031
+ end
1032
+
1033
+ # 期間に含まれる秒数を示す
1034
+ #
1035
+ # @return [Numeric]
1036
+ #
1037
+ def seconds
1038
+ return nil unless (@time)
1039
+ return @time[SECOND].to_s
1040
+ end
1041
+
1042
+ # 符号反転
1043
+ #
1044
+ # @return [When::TM::PeriodDuration]
1045
+ #
1046
+ def -@
1047
+ period = self.dup
1048
+ period.date = @date.map {|v| -v} if @date
1049
+ period.week = @week.map {|v| -v} if @week
1050
+ period.time = @time.map {|v| -v} if @time
1051
+ return period
1052
+ end
1053
+
1054
+ # 符号
1055
+ #
1056
+ # @return [Integer] 0 との比較により、負,0,正の値を返す
1057
+ #
1058
+ def sign
1059
+ ((@week || @date || []) + (@time || [])).each do |v|
1060
+ return -1 if +v < 0
1061
+ end
1062
+ return +1
1063
+ end
1064
+
1065
+ # 比較
1066
+ #
1067
+ # @param [When::TM::PeriodDuration] other
1068
+ #
1069
+ # @return [Integer] other との比較により、負,0,正の値を返す
1070
+ #
1071
+ def <=>(other)
1072
+ unless (@date && @date.size) == (other.date && other.date.size) &&
1073
+ (@week && @week.size) == (other.week && other.week.size) &&
1074
+ (@time && @time.size) == (other.time && other.time.size)
1075
+ raise ArgumentError, "PeriodDuration structure mismatch"
1076
+ end
1077
+
1078
+ (0...@week.size).each do |i|
1079
+ sgn = +@week[i] <=> +other.week[i]
1080
+ return sgn unless sgn == 0
1081
+ end if @week
1082
+
1083
+ (0...@date.size).each do |i|
1084
+ sgn = +@date[i] <=> +other.date[i]
1085
+ return sgn unless sgn == 0
1086
+ end if @date
1087
+
1088
+ (0...@time.size).each do |i|
1089
+ sgn = +@time[i] <=> +other.time[i]
1090
+ return sgn unless sgn == 0
1091
+ end if @time
1092
+
1093
+ return 0
1094
+ end
1095
+
1096
+ # オブジェクトの同値
1097
+ #
1098
+ # @param [比較先] other
1099
+ #
1100
+ # @return [Boolean]
1101
+ # [ true - 同値 ]
1102
+ # [ false - 非同値 ]
1103
+ #
1104
+ def ==(other)
1105
+ (self <=> other) == 0
1106
+ rescue
1107
+ false
1108
+ end
1109
+
1110
+ # 加算
1111
+ #
1112
+ # @param [When::TM::PeriodDuration] other
1113
+ # @param [その他] other 日時とみなす
1114
+ #
1115
+ # @return [WWhen::TM::PeriodDuration] (other が When::TM::PeriodDuration の場合)
1116
+ # @return [other と同じクラス] (other がその他の場合)
1117
+ #
1118
+ def +(other)
1119
+ other.kind_of?(When::TM::PeriodDuration) ? _plus(other, +1) : other + self
1120
+ end
1121
+
1122
+ # 減算
1123
+ #
1124
+ # @param [When::TM::PeriodDuration] other
1125
+ #
1126
+ # @return [When::TM::PeriodDuration]
1127
+ #
1128
+ def -(other)
1129
+ _plus(other, -1)
1130
+ end
1131
+
1132
+ # 乗算
1133
+ #
1134
+ # @param [Numeric] times
1135
+ #
1136
+ # @return [When::TM::PeriodDuration]
1137
+ #
1138
+ def *(times)
1139
+ period = self.dup
1140
+ period.date = @date.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @date
1141
+ period.week = @week.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @week
1142
+ period.time = @time.map {|v| v *= times; v.to_i==v.to_f ? v.to_i : v} if @time
1143
+ return period
1144
+ end
1145
+
1146
+ # 除算
1147
+ #
1148
+ # @param [Numeric] divisor
1149
+ #
1150
+ # @return [When::TM::PeriodDuration]
1151
+ #
1152
+ def /(divisor)
1153
+ self * (1.0 / divisor)
1154
+ end
1155
+
1156
+ # 文字列化
1157
+ #
1158
+ # @return [String]
1159
+ #
1160
+ def to_s
1161
+ period = 'P'
1162
+ if @week
1163
+ period += @week[0].abs.to_s + 'W'
1164
+ period += @week[1].abs.to_s + 'D' unless @week[1] == 0
1165
+ elsif @date
1166
+ (-@date.length..-1).each do |i|
1167
+ period += @date[i].abs.to_s + PRECISION_NAME[i+1][0..0] unless @date[i] == 0
1168
+ end
1169
+ end
1170
+ if @time
1171
+ period += 'T'
1172
+ (1..@time.length-1).each do |i|
1173
+ period += @time[i].abs.to_s + PRECISION_NAME[i][0..0] unless @time[i] == 0
1174
+ end
1175
+ end
1176
+ period = '-' + period if sign < 0
1177
+ period == 'P' ? 'P0D' : period
1178
+ end
1179
+
1180
+ #
1181
+ # When::TM::PeriodDuration への変換
1182
+ #
1183
+ # 単なるオブジェクトのコピー
1184
+ #
1185
+ # @return [When::TM::PeriodDuration]
1186
+ #
1187
+ def to_period_duration
1188
+ self.dup
1189
+ end
1190
+
1191
+ # オブジェクトの生成
1192
+ #
1193
+ # @overload initialize(date=nil, time=nil, week=nil)
1194
+ # @param [Array<Numeric>] date 期間の日付要素
1195
+ # @param [Array<Numeric>] time 期間の時刻要素
1196
+ # @param [Array<Numeric>] week 期間の週日要素
1197
+ #
1198
+ # @overload initialize(value, index, range=YEAR..SECOND)
1199
+ # @param [Numeric] value ndex に対応する桁での)時間間隔
1200
+ # @param [Numeric] index When で定義している分解能定数(YEAR, ... ,SECOND)
1201
+ # @param [Range] range 生成する桁の範囲
1202
+ #
1203
+ def initialize(*args)
1204
+ @options = (args[-1].kind_of?(Hash)) ? (args.pop.reject {|key,value| value == nil}) : {}
1205
+ if args[0].kind_of?(Numeric)
1206
+ _initialize_by_unit(*args)
1207
+ else
1208
+ @date, @time, @week = args
1209
+ end
1210
+ _duration
1211
+ end
1212
+
1213
+ private
1214
+
1215
+ #
1216
+ # 引数パターン2での初期化
1217
+ #
1218
+ def _initialize_by_unit(value, index, range=YEAR..SECOND)
1219
+ max = range.first
1220
+ min = range.last
1221
+ min += 1 if (range.exclude_end?)
1222
+ if (index < max)
1223
+ if (index > MONTH)
1224
+ max = index.floor
1225
+ else
1226
+ value *= 10**(max-index)
1227
+ index = max
1228
+ end
1229
+ elsif (index > min)
1230
+ if (index <= DAY)
1231
+ min = index.ceil
1232
+ else
1233
+ value *= 0.1**(index-min)
1234
+ index = min
1235
+ end
1236
+ end
1237
+ value = value.to_i unless value.kind_of?(Pair) || value.to_i != value.to_f
1238
+ @date = Array.new(1-max, 0) if (max <= DAY) && (index <= DAY)
1239
+ @time = Array.new(1+min, 0) if (min > DAY) && (index > DAY)
1240
+ if (index == WEEK)
1241
+ @week = [value, 0]
1242
+ @date[DAY-1] = 7 * value
1243
+ elsif (index <= DAY)
1244
+ @date[index-1] = value
1245
+ else
1246
+ @time[index] = value
1247
+ end
1248
+ end
1249
+
1250
+ #
1251
+ # 属性 @duration の計算
1252
+ #
1253
+ def _duration
1254
+ if @time
1255
+ @duration = +@time[HOUR ] * Duration::HOUR
1256
+ @duration += +@time[MINUTE] * Duration::MINUTE if @time[MINUTE]
1257
+ @duration += +@time[SECOND] * Duration::SECOND if @time[SECOND]
1258
+ end
1259
+ if @week
1260
+ @duration = +@week[0] * Duration::WEEK + +@week[1] * Duration::DAY + (@duration||0)
1261
+ elsif @date
1262
+ date = @date.dup
1263
+ date.shift while date[0] == 0
1264
+ case date.size
1265
+ when 0 ; @duration ||= 0
1266
+ when 1 ; @duration = +@date[DAY-1] * Duration::DAY + (@duration||0)
1267
+ else ; @duration = nil
1268
+ end
1269
+ end
1270
+ unless @duration
1271
+ class << self; include NoDuration; end
1272
+ end
1273
+ end
1274
+
1275
+ # 加減算共通処理
1276
+ #
1277
+ # @param [When::TM::PeriodDuration] other
1278
+ # @param [Numeric] sgn +1, -1
1279
+ #
1280
+ # @return [When::TM::PeriodDuration]
1281
+ #
1282
+ def _plus(other, sgn)
1283
+ unless (@week && @week.size) == (other.week && other.week.size) &&
1284
+ (@date && @date.size) == (other.date && other.date.size) &&
1285
+ (@time && @time.size) == (other.time && other.time.size)
1286
+ raise ArgumentError, "PeriodDuration structure mismatch"
1287
+ end
1288
+ period = self.dup
1289
+ period.week = (0...@week.size).to_a.map {|i| @week[i] + sgn * other.week[i]} if @week
1290
+ period.date = (0...@date.size).to_a.map {|i| @date[i] + sgn * other.date[i]} if @date
1291
+ period.time = (0...@time.size).to_a.map {|i| @time[i] + sgn * other.time[i]} if @time
1292
+ return period
1293
+ end
1294
+ end
1295
+ end