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.
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