when_exe 0.3.7 → 0.3.8

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +210 -171
  3. data/bin/irb.rc +1 -0
  4. data/lib/when_exe.rb +78 -53
  5. data/lib/when_exe/basictypes.rb +27 -8
  6. data/lib/when_exe/calendarnote.rb +848 -805
  7. data/lib/when_exe/calendartypes.rb +110 -240
  8. data/lib/when_exe/coordinates.rb +2440 -2175
  9. data/lib/when_exe/core/compatibility.rb +1 -1
  10. data/lib/when_exe/core/duration.rb +13 -11
  11. data/lib/when_exe/core/extension.rb +38 -45
  12. data/lib/when_exe/ephemeris.rb +43 -14
  13. data/lib/when_exe/ephemeris/eclipse.rb +149 -0
  14. data/lib/when_exe/ephemeris/notes.rb +39 -7
  15. data/lib/when_exe/icalendar.rb +2 -6
  16. data/lib/when_exe/inspect.rb +1408 -1399
  17. data/lib/when_exe/parts/enumerator.rb +486 -477
  18. data/lib/when_exe/parts/resource.rb +1101 -1069
  19. data/lib/when_exe/parts/timezone.rb +6 -5
  20. data/lib/when_exe/region/babylonian.rb +405 -405
  21. data/lib/when_exe/region/bahai.rb +21 -61
  22. data/lib/when_exe/region/chinese/epochs.rb +81 -81
  23. data/lib/when_exe/region/chinese/twins.rb +51 -51
  24. data/lib/when_exe/region/christian.rb +7 -2
  25. data/lib/when_exe/region/coptic.rb +1 -1
  26. data/lib/when_exe/region/discordian.rb +9 -16
  27. data/lib/when_exe/region/french.rb +1 -1
  28. data/lib/when_exe/region/hanke_henry.rb +57 -0
  29. data/lib/when_exe/region/indian.rb +41 -73
  30. data/lib/when_exe/region/international_fixed.rb +97 -0
  31. data/lib/when_exe/region/iranian.rb +203 -203
  32. data/lib/when_exe/region/japanese.rb +13 -13
  33. data/lib/when_exe/region/japanese/eclipses.rb +1194 -0
  34. data/lib/when_exe/region/japanese/notes.rb +1482 -1383
  35. data/lib/when_exe/region/japanese/residues.rb +726 -721
  36. data/lib/when_exe/region/japanese/twins.rb +37 -37
  37. data/lib/when_exe/region/jewish.rb +2 -2
  38. data/lib/when_exe/region/pax.rb +60 -0
  39. data/lib/when_exe/region/positivist.rb +100 -0
  40. data/lib/when_exe/region/roman.rb +333 -334
  41. data/lib/when_exe/region/shire.rb +3 -20
  42. data/lib/when_exe/region/thai.rb +2 -2
  43. data/lib/when_exe/region/tibetan.rb +3 -3
  44. data/lib/when_exe/region/tranquility.rb +208 -0
  45. data/lib/when_exe/region/vanishing_leprechaun.rb +53 -0
  46. data/lib/when_exe/region/vietnamese.rb +4 -4
  47. data/lib/when_exe/region/world.rb +9 -13
  48. data/lib/when_exe/region/world_season.rb +89 -0
  49. data/lib/when_exe/region/zoroastrian.rb +4 -2
  50. data/lib/when_exe/tmobjects.rb +14 -4
  51. data/lib/when_exe/tmposition.rb +239 -81
  52. data/lib/when_exe/tmreference.rb +57 -28
  53. data/lib/when_exe/version.rb +1 -1
  54. data/link_to_online_documents +6 -3
  55. data/test/examples/today.rb +1 -1
  56. data/test/scripts.rb +23 -0
  57. data/test/scripts/2.ext.rb +169 -0
  58. data/test/scripts/2.rb +169 -0
  59. data/test/scripts/3.ext.rb +133 -0
  60. data/test/scripts/3.rb +134 -0
  61. data/test/scripts/4.ext.rb +112 -0
  62. data/test/scripts/4.min.rb +65 -0
  63. data/test/scripts/4.rb +136 -0
  64. data/test/scripts/5.ext.rb +78 -0
  65. data/test/scripts/5.rb +81 -0
  66. data/test/scripts/6.gcal.rb +131 -0
  67. data/test/scripts/6.rb +205 -0
  68. data/test/scripts/6.tz.rb +105 -0
  69. data/test/scripts/7.phase.rb +109 -0
  70. data/test/scripts/7.rb +95 -0
  71. data/test/scripts/7.term.rb +128 -0
  72. data/test/scripts/7.week.rb +84 -0
  73. data/test/scripts/8.ext.rb +61 -0
  74. data/test/scripts/8.rb +62 -0
  75. data/test/scripts/9.ext.rb +131 -0
  76. data/test/scripts/9.rb +130 -0
  77. data/test/scripts/chinese-luni-solar.rb +52 -0
  78. data/test/{examples → scripts}/geometric_complex.rb +41 -41
  79. data/test/scripts/geometric_complex.txt +18 -0
  80. data/test/scripts/korea.rb +59 -0
  81. data/test/scripts/thai-reviewed.txt +211 -0
  82. data/test/scripts/thai.rb +36 -0
  83. data/test/scripts/thai.txt +210 -0
  84. data/test/test.rb +7 -0
  85. data/test/test/basictypes.rb +22 -0
  86. data/test/test/coordinates.rb +2 -1
  87. data/test/test/ephemeris.rb +34 -2
  88. data/test/test/icalendar.rb +12 -0
  89. data/test/test/inspect.rb +37 -1
  90. data/test/test/parts.rb +4 -3
  91. data/test/test/region/armenian.rb +20 -0
  92. data/test/test/region/bahai.rb +58 -0
  93. data/test/test/region/chinese.rb +14 -3
  94. data/test/test/region/christian.rb +16 -35
  95. data/test/test/region/discordian.rb +20 -0
  96. data/test/test/region/indian.rb +30 -2
  97. data/test/test/region/japanese.rb +24 -0
  98. data/test/test/region/jewish.rb +2 -0
  99. data/test/test/region/m17n.rb +9 -0
  100. data/test/test/region/reforms.rb +121 -0
  101. data/test/test/region/residue.rb +17 -11
  102. data/test/test/region/shire.rb +58 -0
  103. data/test/test/region/swedish.rb +45 -0
  104. data/test/test/region/zoroastrian.rb +58 -0
  105. data/test/test/tmobjects.rb +74 -0
  106. data/test/test/tmposition.rb +468 -397
  107. data/when_exe.gemspec +2 -2
  108. metadata +49 -6
@@ -1,477 +1,486 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2011-2014 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
- # v1.8.x のための互換性確保用
15
- #
16
- # @private
17
- class Enumerator < ::Enumerator ; end if Object.const_defined?(:Enumerator)
18
-
19
- #
20
- # 本ライブラリ用の Enumerator の雛形
21
- #
22
- class Enumerator
23
-
24
- # @private
25
- def self._options(args)
26
- options = args[-1].kind_of?(Hash) ? args.pop.dup : {}
27
- options[:exdate] =
28
- case options[:exdate]
29
- when GeometricComplex ; options[:exdate].dup
30
- when nil ; GeometricComplex.new()
31
- else ; GeometricComplex.new(options[:exdate])
32
- end
33
- return options
34
- end
35
-
36
- # 生成元オブジェクト
37
- # @return [Comparable]
38
- attr_reader :parent
39
-
40
- # オプション
41
- # @return [Hash]
42
- # @private
43
- attr_accessor :options
44
- protected :options=
45
-
46
- # 除外要素
47
- # @return [When::Parts::GeometricComplex]
48
- attr_accessor :exdate
49
- protected :exdate=
50
-
51
- # 処理済み要素
52
- # @return [When::Parts::GeometricComplex]
53
- attr_accessor :processed
54
- protected :processed=
55
-
56
- # 最初の要素
57
- # @return [Comparable]
58
- attr_accessor :first
59
- protected :first=
60
-
61
- # 最後の要素
62
- # @return [Comparable]
63
- attr_accessor :last
64
- protected :last=
65
-
66
- # 繰り返し方向
67
- # @return [Symbol]
68
- # [ :forward - 昇順 ]
69
- # [ :reverse - 降順 ]
70
- attr_reader :direction
71
-
72
- # 最大繰り返し回数
73
- # @return [Integer]
74
- attr_reader :count_limit
75
-
76
- # 現在の繰り返し回数
77
- # @return [Integer]
78
- attr_reader :count
79
-
80
- # 現在の要素
81
- # @return [Comparable]
82
- attr_accessor :current
83
- protected :current=
84
-
85
- # 現在のインデックス
86
- # @return [Integer]
87
- # @private
88
- attr_reader :index
89
-
90
- # with_object メソッドで渡すインスタンス
91
- # @return [Comparable]
92
- # @private
93
- attr_accessor :object
94
- protected :object=
95
-
96
- #
97
- # ブロックを評価する
98
- #
99
- # @return [rewind された self]
100
- #
101
- def each
102
- return self unless block_given?
103
- while (has_next?) do
104
- if @index
105
- yield(succ, @index)
106
- @index += 1
107
- elsif @object
108
- yield(succ, @object)
109
- else
110
- yield(succ)
111
- end
112
- end
113
- @index = @object = nil
114
- rewind
115
- end
116
-
117
- #
118
- # index をブロックに渡して評価する
119
- #
120
- # @param [Integer] offset index の初期値
121
- #
122
- # @return [When::Parts:Enumerator]
123
- # [ ブロックあり - rewind された self ]
124
- # [ ブロックなし - copy ]
125
- #
126
- def with_index(offset=0, &block)
127
- if block_given?
128
- @index = offset||@count
129
- return each(block)
130
- else
131
- copy = _copy
132
- copy.object = nil
133
- copy.index = offset||@count
134
- return copy
135
- end
136
- end
137
-
138
- #
139
- # index をブロックに渡して評価する
140
- #
141
- # @param [Comparable] object ブロックに渡す Object
142
- #
143
- # @return [When::Parts:Enumerator]
144
- # [ ブロックあり - rewind された self ]
145
- # [ ブロックなし - copy ]
146
- #
147
- def with_object(object, &block)
148
- if block_given?
149
- @object = object
150
- each(block)
151
- return object
152
- else
153
- copy = _copy
154
- copy.object = object
155
- copy.index = nil
156
- return copy
157
- end
158
- end
159
-
160
- #
161
- # 巻き戻す
162
- #
163
- # @return [rewind された self]
164
- #
165
- def _rewind
166
- @processed = @exdate.dup
167
- @count = 0
168
- @current = :first
169
- succ
170
- self
171
- end
172
- alias :rewind :_rewind
173
-
174
- #
175
- # 次の要素があるか?
176
- #
177
- # @return [Boolean]
178
- # [ true - ある ]
179
- # [ false - ない ]
180
- #
181
- def has_next?
182
- return (@current != nil)
183
- end
184
-
185
- #
186
- # 次の要素を取り出す
187
- #
188
- # @return [Comparable] 次の要素
189
- # @raise [StopIteration] 次の要素がない場合 rewind して例外を発生
190
- #
191
- def next
192
- return succ if has_next?
193
- rewind
194
- raise StopIteration, "Iteration Stopped"
195
- end
196
-
197
- #
198
- # 次の要素を取り出す
199
- #
200
- # @return [Comparable]
201
- # [ 次の要素あり - 次の要素 ]
202
- # [ 次の要素なし - nil ]
203
- #
204
- # @note
205
- # 次の要素がない場合 rewind や、StopIteration例外発生は行わない
206
- #
207
- def succ
208
- value = @current
209
- if (@count_limit.kind_of?(Numeric) && @count >= @count_limit)
210
- @current = nil
211
- else
212
- loop do
213
- @current = _succ
214
- break unless (@current)
215
- next if (@current == :next)
216
- @current = GeometricComplex.new(@current, @duration) if @duration
217
- next if _exclude(@current)
218
- case @direction
219
- when :reverse
220
- next if (@current > @first)
221
- @current = nil if (@last && @current < @last)
222
- break
223
- else
224
- next if (@current < @first)
225
- @current = nil if (@last && @current > @last)
226
- break
227
- end
228
- end
229
- @count += 1
230
- _exclude(@current) if (@current)
231
- end
232
- return value
233
- end
234
-
235
- # オブジェクトの生成
236
- #
237
- # @overload initialize(parent, range, count_limit=nil)
238
- # @param [Comparable] parent 生成元
239
- # @param [Range, When::Parts::GeometricComplex] range
240
- # [ 始点 - range.first ]
241
- # [ 終点 - range.last ]
242
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
243
- #
244
- # @overload initialize(parent, first, direction, count_limit=nil)
245
- # @param [Comparable] parent 生成元
246
- # @param [When::TM::TemporalPosition] first 始点
247
- # @param [Symbol] direction (options[:direction]で渡してもよい)
248
- # [ :forward - 昇順 ]
249
- # [ :reverse - 降順 ]
250
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし, options[:count_limit]で渡してもよい)
251
- #
252
- def initialize(*args)
253
- @options = self.class._options(args)
254
- @exdate = @options.delete(:exdate)
255
- @exevent = @options.delete(:exevent)
256
- @parent, *rest = args
257
- _range(rest)
258
- _rewind
259
- end
260
-
261
- private
262
-
263
- def _range(rest)
264
- if (rest[0].instance_of?(Range))
265
- range, @count_limit, others = rest
266
- raise ArgumentError, "Too many arguments" if others
267
- @first = When.when?(range.first)
268
- @last = When.when?(range.last)
269
- @exdate |= @last if (range.exclude_end?)
270
- if (@first > @last)
271
- @first, @last = @last, @first
272
- @direction = :reverse
273
- else
274
- @direction = :forward
275
- end
276
- else
277
- @first, @direction, @count_limit, others = rest
278
- raise ArgumentError, "Too many arguments" if others
279
- raise ArgumentError, "Too few arguments" unless @first
280
- @direction ||= :forward
281
- @last = nil
282
- end
283
- @count_limit = @options[:count_limit] if @options[:count_limit] && (!@count_limit || @count_limit > @options[:count_limit])
284
- @options.delete(:count_limit)
285
- @direction = @options[:direction] if @options[:direction]
286
- @options.delete(:direction)
287
- end
288
-
289
- def _exclude(value)
290
- if @exevent
291
- @exevent.each do |ev|
292
- return true if ev.include?(value)
293
- end
294
- end
295
- previous = @processed._include?(value)
296
- @processed |= value if previous == false
297
- registered = (previous==value) ? previous : value
298
- registered = registered.first if registered.kind_of?(GeometricComplex)
299
- registered.events ||=[]
300
- registered.events << self.parent
301
- registered.events.uniq!
302
- return previous != false
303
- end
304
-
305
- def _copy
306
- copy = dup
307
- copy.options = @options.dup if @options
308
- copy.exdate = @exdate.dup if @exdate
309
- copy.exevent = @exevent.dup if @exevent
310
- copy.processed = @processed.dup if @processed
311
- copy.first = @first.dup if @first
312
- copy.last = @last.dup if @last
313
- copy.current = @current.dup if @current.respond_to?(:dup)
314
- copy.object = @object.dup if @object.respond_to?(:dup)
315
- return copy
316
- end
317
-
318
- #
319
- # 時間位置の Array を順に取り出す Enumerator
320
- #
321
- class Array < Enumerator
322
-
323
- # 整列して、重複した候補を削除
324
- #
325
- # @param [Array] list
326
- # @param [Symbol] direction
327
- # [ :forward - 昇順 ]
328
- # [ :reverse - 降順 ]
329
- #
330
- # @return [Array]
331
- # @note
332
- # eql? はオーバーライドしない
333
- #
334
- def self._sort(list, direction)
335
- list = list.sort
336
- prev = nil
337
- list.delete_if do |x|
338
- if (x == prev)
339
- true
340
- else
341
- prev = x
342
- false
343
- end
344
- end
345
- list.reverse! if (direction == :reverse)
346
- return list
347
- end
348
-
349
- # 初期リスト
350
- # @return [Array]
351
- # @private
352
- attr_accessor :initial_list
353
- protected :initial_list=
354
-
355
- # 現在リスト
356
- # @return [Array]
357
- # @private
358
- attr_accessor :current_list
359
- protected :current_list=
360
-
361
- #
362
- # 巻き戻す
363
- #
364
- # @return [rewind された self]
365
- # @private
366
- def _rewind
367
- @current_list = @initial_list.dup
368
- super
369
- end
370
-
371
- # オブジェクトの生成
372
- #
373
- # @overload initialize(parent, list, count_limit=nil))
374
- # @param [Comparable] parent 生成元
375
- # @param [Array<When::TM::TemporalPosition>] list 順に取り出す時間位置の Array
376
- # @param [Symbol] direction
377
- # [ :forward - 昇順 ]
378
- # [ :reverse - 降順 ]
379
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
380
- #
381
- def initialize(*args)
382
- parent, list, direction, *args = args
383
- raise ArgumentError, "Too few arguments" unless list
384
- @initial_list = self.class._sort(list, direction||:forward)
385
- super(parent, @initial_list[0], direction, *args)
386
- end
387
-
388
- private
389
-
390
- def _succ
391
- return @current_list.shift
392
- end
393
-
394
- def _copy
395
- copy = super
396
- copy.initial_list = @initial_list.dup
397
- copy.current_list = @current_list.dup
398
- return copy
399
- end
400
- end
401
-
402
- #
403
- # 複数の下位 Enumerator の結果を順に取り出す Enumerator
404
- #
405
- class Integrated < Enumerator
406
-
407
- #
408
- # 下位 Enumerator
409
- #
410
- # @return [Array<When::Parts::Enumerator>]
411
- #
412
- attr_accessor :enumerators
413
- protected :enumerators=
414
-
415
- #
416
- # 巻き戻す
417
- #
418
- # @return [rewind された self]
419
- #
420
- def rewind
421
- @enumerators.each do |enum|
422
- enum._rewind
423
- end
424
- super
425
- end
426
-
427
- # オブジェクトの生成
428
- #
429
- # @overload initialize(parent, enumerators, first, count_limit=nil))
430
- # @param [Comparable] parent 生成元
431
- # @param [Array<When::Parts::Enumerator>] list 順に取り出す下位 Enumeratorの Array
432
- # @param [When::TM::TemporalPosition] first 始点
433
- # @param [Symbol] direction
434
- # [ :forward - 昇順 ]
435
- # [ :reverse - 降順 ]
436
- # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
437
- #
438
- def initialize(*args)
439
- parent, @enumerators, *rest = args
440
- raise ArgumentError, "Too few arguments" unless @enumerators.kind_of?(::Array)
441
- super(parent, *rest)
442
- end
443
-
444
- private
445
-
446
- def _copy
447
- copy = super
448
- copy.enumerators = @enumerators.map {|e| e._copy}
449
- return copy
450
- end
451
-
452
- def _succ
453
- current = nil
454
- selected = nil
455
- @enumerators.each_index do |i|
456
- value = @enumerators[i].current
457
- next unless (value)
458
- if (current)
459
- verify = current <=> value
460
- case @direction
461
- when :reverse ; next if (verify > 0)
462
- else ; next if (verify < 0)
463
- end
464
- if (verify == 0)
465
- next if current.kind_of?(GeometricComplex) && current.include?(value)
466
- #next if current.precision <= value.precision # TODO
467
- end
468
- end
469
- current = value
470
- selected = i
471
- end
472
- @enumerators[selected].succ if (selected)
473
- return current
474
- end
475
- end
476
- end
477
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2014 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
+ # v1.8.x のための互換性確保用
15
+ #
16
+ # @private
17
+ class Enumerator < ::Enumerator ; end if Object.const_defined?(:Enumerator)
18
+
19
+ #
20
+ # 本ライブラリ用の Enumerator の雛形
21
+ #
22
+ class Enumerator
23
+
24
+ # @private
25
+ def self._options(args)
26
+ options = args[-1].kind_of?(Hash) ? args.pop.dup : {}
27
+ options[:exdate] =
28
+ case options[:exdate]
29
+ when GeometricComplex ; options[:exdate].dup
30
+ when nil ; GeometricComplex.new()
31
+ else ; GeometricComplex.new(options[:exdate])
32
+ end
33
+ return options
34
+ end
35
+
36
+ # 生成元オブジェクト
37
+ # @return [Comparable]
38
+ attr_reader :parent
39
+
40
+ # オプション
41
+ # @return [Hash]
42
+ # @private
43
+ attr_accessor :options
44
+ protected :options=
45
+
46
+ # 除外要素
47
+ # @return [When::Parts::GeometricComplex]
48
+ attr_accessor :exdate
49
+ protected :exdate=
50
+
51
+ # 処理済み要素
52
+ # @return [When::Parts::GeometricComplex]
53
+ attr_accessor :processed
54
+ protected :processed=
55
+
56
+ # 最初の要素
57
+ # @return [Comparable]
58
+ attr_accessor :first
59
+ protected :first=
60
+
61
+ # 最後の要素
62
+ # @return [Comparable]
63
+ attr_accessor :last
64
+ protected :last=
65
+
66
+ # 繰り返し方向
67
+ # @return [Symbol]
68
+ # [ :forward - 昇順 ]
69
+ # [ :reverse - 降順 ]
70
+ attr_reader :direction
71
+
72
+ # 最大繰り返し回数
73
+ # @return [Integer]
74
+ attr_reader :count_limit
75
+
76
+ # 現在の繰り返し回数
77
+ # @return [Integer]
78
+ attr_reader :count
79
+
80
+ # 現在の要素
81
+ # @return [Comparable]
82
+ attr_accessor :current
83
+ protected :current=
84
+
85
+ # 現在のインデックス
86
+ # @return [Integer]
87
+ # @private
88
+ attr_reader :index
89
+
90
+ # with_object メソッドで渡すインスタンス
91
+ # @return [Comparable]
92
+ # @private
93
+ attr_accessor :object
94
+ protected :object=
95
+
96
+ #
97
+ # ブロックを評価する
98
+ #
99
+ # @param [Hash] options 以下の通り
100
+ # @option options [Symbol] :direction 方向(:forward/:reverse)
101
+ # @option options [Comparable] :until 終了閾値
102
+ # @option options [Integer] :count_limit 繰り返し回数
103
+ #
104
+ # @return [rewind された self]
105
+ #
106
+ def each(options={})
107
+ @direction = options[:direction] if options.key?(:direction)
108
+ @last = @direction == :reverse ? [options[:until], @last].compact.max :
109
+ [options[:until], @last].compact.min
110
+ @count_limit = [options[:count_limit], @count_limit].compact.min
111
+ return self unless block_given?
112
+ while (has_next?) do
113
+ if @index
114
+ yield(succ, @index)
115
+ @index += 1
116
+ elsif @object
117
+ yield(succ, @object)
118
+ else
119
+ yield(succ)
120
+ end
121
+ end
122
+ @index = @object = nil
123
+ rewind
124
+ end
125
+
126
+ #
127
+ # index をブロックに渡して評価する
128
+ #
129
+ # @param [Integer] offset index の初期値
130
+ #
131
+ # @return [When::Parts:Enumerator]
132
+ # [ ブロックあり - rewind された self ]
133
+ # [ ブロックなし - copy ]
134
+ #
135
+ def with_index(offset=0, &block)
136
+ if block_given?
137
+ @index = offset||@count
138
+ return each(block)
139
+ else
140
+ copy = _copy
141
+ copy.object = nil
142
+ copy.index = offset||@count
143
+ return copy
144
+ end
145
+ end
146
+
147
+ #
148
+ # index をブロックに渡して評価する
149
+ #
150
+ # @param [Comparable] object ブロックに渡す Object
151
+ #
152
+ # @return [When::Parts:Enumerator]
153
+ # [ ブロックあり - rewind された self ]
154
+ # [ ブロックなし - copy ]
155
+ #
156
+ def with_object(object, &block)
157
+ if block_given?
158
+ @object = object
159
+ each(block)
160
+ return object
161
+ else
162
+ copy = _copy
163
+ copy.object = object
164
+ copy.index = nil
165
+ return copy
166
+ end
167
+ end
168
+
169
+ #
170
+ # 巻き戻す
171
+ #
172
+ # @return [rewind された self]
173
+ #
174
+ def _rewind
175
+ @processed = @exdate.dup
176
+ @count = 0
177
+ @current = :first
178
+ succ
179
+ self
180
+ end
181
+ alias :rewind :_rewind
182
+
183
+ #
184
+ # 次の要素があるか?
185
+ #
186
+ # @return [Boolean]
187
+ # [ true - ある ]
188
+ # [ false - ない ]
189
+ #
190
+ def has_next?
191
+ return (@count_limit != 0) && (@current != nil)
192
+ end
193
+
194
+ #
195
+ # 次の要素を取り出す
196
+ #
197
+ # @return [Comparable] 次の要素
198
+ # @raise [StopIteration] 次の要素がない場合 rewind して例外を発生
199
+ #
200
+ def next
201
+ return succ if has_next?
202
+ rewind
203
+ raise StopIteration, "Iteration Stopped"
204
+ end
205
+
206
+ #
207
+ # 次の要素を取り出す
208
+ #
209
+ # @return [Comparable]
210
+ # [ 次の要素あり - 次の要素 ]
211
+ # [ 次の要素なし - nil ]
212
+ #
213
+ # @note
214
+ # 次の要素がない場合 rewind や、StopIteration例外発生は行わない
215
+ #
216
+ def succ
217
+ value = @current
218
+ if @count_limit.kind_of?(Numeric) && @count >= @count_limit
219
+ @current = nil
220
+ else
221
+ loop do
222
+ @current = _succ
223
+ break unless @current
224
+ next if (@current == :next)
225
+ @current = GeometricComplex.new(@current, @duration) if @duration
226
+ next if _exclude(@current)
227
+ case @direction
228
+ when :reverse
229
+ next if @current > @first
230
+ @current = nil if @last && @current < @last
231
+ break
232
+ else
233
+ next if @current < @first
234
+ @current = nil if @last && @current > @last
235
+ break
236
+ end
237
+ end
238
+ @count += 1
239
+ _exclude(@current) if @current
240
+ end
241
+ return value
242
+ end
243
+
244
+ # オブジェクトの生成
245
+ #
246
+ # @overload initialize(parent, range, count_limit=nil)
247
+ # @param [Comparable] parent 生成元
248
+ # @param [Range, When::Parts::GeometricComplex] range
249
+ # [ 始点 - range.first ]
250
+ # [ 終点 - range.last ]
251
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
252
+ #
253
+ # @overload initialize(parent, first, direction, count_limit=nil)
254
+ # @param [Comparable] parent 生成元
255
+ # @param [When::TM::TemporalPosition] first 始点
256
+ # @param [Symbol] direction (options[:direction]で渡してもよい)
257
+ # [ :forward - 昇順 ]
258
+ # [ :reverse - 降順 ]
259
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし, options[:count_limit]で渡してもよい)
260
+ #
261
+ def initialize(*args)
262
+ @options = self.class._options(args)
263
+ @exdate = @options.delete(:exdate)
264
+ @exevent = @options.delete(:exevent)
265
+ @parent, *rest = args
266
+ _range(rest)
267
+ _rewind
268
+ end
269
+
270
+ private
271
+
272
+ def _range(rest)
273
+ if rest[0].instance_of?(Range)
274
+ range, @count_limit, others = rest
275
+ raise ArgumentError, "Too many arguments" if others
276
+ @first = When.when?(range.first)
277
+ @last = When.when?(range.last)
278
+ @exdate |= @last if (range.exclude_end?)
279
+ if (@first > @last)
280
+ @first, @last = @last, @first
281
+ @direction = :reverse
282
+ else
283
+ @direction = :forward
284
+ end
285
+ else
286
+ @first, @direction, @count_limit, others = rest
287
+ raise ArgumentError, "Too many arguments" if others
288
+ raise ArgumentError, "Too few arguments" unless @first
289
+ @direction ||= :forward
290
+ @last = nil
291
+ end
292
+ @count_limit = @options[:count_limit] if @options[:count_limit] && (!@count_limit || @count_limit > @options[:count_limit])
293
+ @options.delete(:count_limit)
294
+ @direction = @options[:direction] if @options[:direction]
295
+ @options.delete(:direction)
296
+ end
297
+
298
+ def _exclude(value)
299
+ if @exevent
300
+ @exevent.each do |ev|
301
+ return true if ev.include?(value)
302
+ end
303
+ end
304
+ previous = @processed._include?(value)
305
+ @processed |= value if previous == false
306
+ registered = (previous==value) ? previous : value
307
+ registered = registered.first if registered.kind_of?(GeometricComplex)
308
+ registered.events ||=[]
309
+ registered.events << self.parent
310
+ registered.events.uniq!
311
+ return previous != false
312
+ end
313
+
314
+ def _copy
315
+ copy = dup
316
+ copy.options = @options.dup if @options
317
+ copy.exdate = @exdate.dup if @exdate
318
+ copy.exevent = @exevent.dup if @exevent
319
+ copy.processed = @processed.dup if @processed
320
+ copy.first = @first.dup if @first
321
+ copy.last = @last.dup if @last
322
+ copy.current = @current.dup if @current.respond_to?(:dup)
323
+ copy.object = @object.dup if @object.respond_to?(:dup)
324
+ return copy
325
+ end
326
+
327
+ #
328
+ # 時間位置の Array を順に取り出す Enumerator
329
+ #
330
+ class Array < Enumerator
331
+
332
+ # 整列して、重複した候補を削除
333
+ #
334
+ # @param [Array] list
335
+ # @param [Symbol] direction
336
+ # [ :forward - 昇順 ]
337
+ # [ :reverse - 降順 ]
338
+ #
339
+ # @return [Array]
340
+ # @note
341
+ # eql? はオーバーライドしない
342
+ #
343
+ def self._sort(list, direction)
344
+ list = list.sort
345
+ prev = nil
346
+ list.delete_if do |x|
347
+ if (x == prev)
348
+ true
349
+ else
350
+ prev = x
351
+ false
352
+ end
353
+ end
354
+ list.reverse! if (direction == :reverse)
355
+ return list
356
+ end
357
+
358
+ # 初期リスト
359
+ # @return [Array]
360
+ # @private
361
+ attr_accessor :initial_list
362
+ protected :initial_list=
363
+
364
+ # 現在リスト
365
+ # @return [Array]
366
+ # @private
367
+ attr_accessor :current_list
368
+ protected :current_list=
369
+
370
+ #
371
+ # 巻き戻す
372
+ #
373
+ # @return [rewind された self]
374
+ # @private
375
+ def _rewind
376
+ @current_list = @initial_list.dup
377
+ super
378
+ end
379
+
380
+ # オブジェクトの生成
381
+ #
382
+ # @overload initialize(parent, list, count_limit=nil))
383
+ # @param [Comparable] parent 生成元
384
+ # @param [Array<When::TM::TemporalPosition>] list 順に取り出す時間位置の Array
385
+ # @param [Symbol] direction
386
+ # [ :forward - 昇順 ]
387
+ # [ :reverse - 降順 ]
388
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
389
+ #
390
+ def initialize(*args)
391
+ parent, list, direction, *args = args
392
+ raise ArgumentError, "Too few arguments" unless list
393
+ @initial_list = self.class._sort(list, direction||:forward)
394
+ super(parent, @initial_list[0], direction, *args)
395
+ end
396
+
397
+ private
398
+
399
+ def _succ
400
+ return @current_list.shift
401
+ end
402
+
403
+ def _copy
404
+ copy = super
405
+ copy.initial_list = @initial_list.dup
406
+ copy.current_list = @current_list.dup
407
+ return copy
408
+ end
409
+ end
410
+
411
+ #
412
+ # 複数の下位 Enumerator の結果を順に取り出す Enumerator
413
+ #
414
+ class Integrated < Enumerator
415
+
416
+ #
417
+ # 下位 Enumerator
418
+ #
419
+ # @return [Array<When::Parts::Enumerator>]
420
+ #
421
+ attr_accessor :enumerators
422
+ protected :enumerators=
423
+
424
+ #
425
+ # 巻き戻す
426
+ #
427
+ # @return [rewind された self]
428
+ #
429
+ def rewind
430
+ @enumerators.each do |enum|
431
+ enum._rewind
432
+ end
433
+ super
434
+ end
435
+
436
+ # オブジェクトの生成
437
+ #
438
+ # @overload initialize(parent, enumerators, first, count_limit=nil))
439
+ # @param [Comparable] parent 生成元
440
+ # @param [Array<When::Parts::Enumerator>] list 順に取り出す下位 Enumeratorの Array
441
+ # @param [When::TM::TemporalPosition] first 始点
442
+ # @param [Symbol] direction
443
+ # [ :forward - 昇順 ]
444
+ # [ :reverse - 降順 ]
445
+ # @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
446
+ #
447
+ def initialize(*args)
448
+ parent, @enumerators, *rest = args
449
+ raise ArgumentError, "Too few arguments" unless @enumerators.kind_of?(::Array)
450
+ super(parent, *rest)
451
+ end
452
+
453
+ private
454
+
455
+ def _copy
456
+ copy = super
457
+ copy.enumerators = @enumerators.map {|e| e._copy}
458
+ return copy
459
+ end
460
+
461
+ def _succ
462
+ current = nil
463
+ selected = nil
464
+ @enumerators.each_index do |i|
465
+ value = @enumerators[i].current
466
+ next unless (value)
467
+ if (current)
468
+ verify = current <=> value
469
+ case @direction
470
+ when :reverse ; next if (verify > 0)
471
+ else ; next if (verify < 0)
472
+ end
473
+ if (verify == 0)
474
+ next if current.kind_of?(GeometricComplex) && current.include?(value)
475
+ #next if current.precision <= value.precision # TODO
476
+ end
477
+ end
478
+ current = value
479
+ selected = i
480
+ end
481
+ @enumerators[selected].succ if (selected)
482
+ return current
483
+ end
484
+ end
485
+ end
486
+ end