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,379 @@
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2013 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ #
9
+ # 本ライブラリのための諸々の部品
10
+ #
11
+ module When::Parts
12
+
13
+ #
14
+ # 任意個の端点から構成する [Range] の subclass
15
+ #
16
+ class GeometricComplex < Range
17
+
18
+ include Comparable
19
+
20
+ # 範囲の反転
21
+ # @return [Boolean]
22
+ # [ true - 反転する ]
23
+ # [ false - 反転しない ]
24
+ #
25
+ # @note
26
+ # 無限の過去(-Infinity)を範囲に含むか否かと同値である
27
+ #
28
+ attr_reader :reverse
29
+
30
+ #
31
+ # When::Parts::GeometricComplex を構成する端点の Array
32
+ #
33
+ # @return [Array<Array<Comparable, Boolean>>]
34
+ # - Comparable - 端点
35
+ # - Boolean
36
+ # @reverse == true の場合
37
+ # true - 範囲に含まない
38
+ # false - 範囲に含む
39
+ # @reverse == false の場合
40
+ # true - 範囲に含む
41
+ # false - 範囲に含まない
42
+ #
43
+ # @example +[[3,true],[4,false]] は Range(3+...4)に対応する
44
+ #
45
+ attr_reader :node
46
+
47
+ # 最小の端点
48
+ #
49
+ # @param [Comparable] default 端点が-∞の場合に返すべき値(指定がなければ nil)
50
+ #
51
+ # @return [Comparable] 最小の端点
52
+ #
53
+ # @note
54
+ # 含むか否かに関わらず、最小の端点を返す。
55
+ # default が指定されているが有効な区間がない場合、nil を返す。
56
+ #
57
+ def first(default=nil)
58
+ return (@node.length==0) ? nil : @node[0][0] unless default # 互換性
59
+ if reverse
60
+ return default
61
+ else
62
+ (@node.length==0) ? nil : @node[0][0]
63
+ end
64
+ end
65
+ alias :begin :first
66
+
67
+ # 最大の端点
68
+ #
69
+ # @param [Comparable] default 端点が+∞場合に返すべき値(指定がなければ nil)
70
+ #
71
+ # @return [Comparable] 最大の端点
72
+ #
73
+ # @note
74
+ # 含むか否かに関わらず、最大の端点を返す
75
+ # default が指定されているが有効な区間がない場合、nil を返す
76
+ #
77
+ def last(default=nil)
78
+ return (@node.length==0) ? nil : @node[-1][0] unless default # 互換性
79
+ if reverse
80
+ return (@node.length[0]==0) ? default : @node[-1][0]
81
+ else
82
+ return nil if (@node.length==0)
83
+ return (@node.length[0]==1) ? default : @node[-1][0]
84
+ end
85
+ end
86
+ alias :end :last
87
+
88
+ # 端点が範囲に含まれるか?
89
+ #
90
+ # @param [Integer] index 端点の番号(デフォルト : -1 - 最大の端点)
91
+ #
92
+ # @return [Boolean]
93
+ # [ true - 含まれる ]
94
+ # [ false - 含まれない ]
95
+ #
96
+ def exclude_end?(index=-1)
97
+ (@node.length==0) ? nil : !@node[index][1] ^ @reverse
98
+ end
99
+
100
+ # 分解能
101
+ #
102
+ # @return [Integer] 最小の端点の分解能を返す
103
+ #
104
+ # @note
105
+ # 分解能がない場合は、When::SYSTEM を返す
106
+ #
107
+ def precision
108
+ @node[0] && @node[0][0].respond_to?(:precision) ? @node[0][0].precision : Coordinates::SYSTEM
109
+ end
110
+
111
+ # 範囲を反転する
112
+ #
113
+ # @return [When::Parts::GeometricComplex]
114
+ #
115
+ def -@
116
+ GeometricComplex.new(self, true)
117
+ end
118
+
119
+ # 最小の端点と other を比較する
120
+ #
121
+ # @param [Comparable] other 比較対象
122
+ #
123
+ # @return [Integer] 比較結果を 負, 0, 正の値で返す
124
+ #
125
+ def <=>(other)
126
+ first <=> other
127
+ end
128
+
129
+ # 和集合
130
+ #
131
+ # @param [Range, When::Parts::GeometricComplex] other
132
+ #
133
+ # @return [When::Parts::GeometricComplex] self と other の和集合を返す
134
+ #
135
+ def |(other)
136
+ other = GeometricComplex.new(other) unless other.kind_of?(GeometricComplex)
137
+ return self if self.reverse && self.node.length==0
138
+ return other | self if !self.reverse && other.reverse
139
+ copy = self.node.dup
140
+ ref = other.node.dup
141
+ max = _max(copy.shift.dup, ref.shift.dup) if (other.reverse)
142
+ rev = max ? false : @reverse
143
+ while (ref.length > 0) do
144
+ first, last, *ref = ref
145
+ updated = _upper(copy, first, rev)
146
+ updated += _lower(copy, last, rev) if last
147
+ copy = updated
148
+ end
149
+ copy = _lower(copy, max, true) if max
150
+ return GeometricComplex.new(copy, self.reverse)
151
+ end
152
+
153
+ # ISO19108 の TM オブジェクトに変換する
154
+ #
155
+ # @param [Hash] options When::TM::TemporalPosition の生成を行う場合に使用する
156
+ # (see {When::TM::TemporalPosition._instance})
157
+ #
158
+ # @return [When::TM::Node, When::TM::Edge, When::TM::TopologicalComplex]
159
+ #
160
+ def to_tm_object(options={})
161
+ return nil unless !@reverse && @node.length>0 && @node.length[0]==0
162
+ objects = []
163
+ primitives = @node.dup
164
+ while (primitives) do
165
+ first, last, primitives = primitives
166
+ if (first[0].eql?(last[0]))
167
+ objects = When::TM::Node.new(When::TM::Instant.new(When.when?(first[0],options)))
168
+ else
169
+ objects = When::TM::Edge.new(When::TM::Node.new(When::TM::Instant.new(When.when?(first[0],options))),
170
+ When::TM::Node.new(When::TM::Instant.new(When.when?(last[0],options))))
171
+ end
172
+ end
173
+ return objects[0] if objects.length==1
174
+ return When::TM::TopologicalComplex.new(objects)
175
+ end
176
+
177
+ # 範囲に含まれるか?
178
+ #
179
+ # @param [Comparable] other 判断する Comparable
180
+ #
181
+ # @return [Boolean]
182
+ # [ true - 範囲に含まれる ]
183
+ # [ false - 範囲に含まれない ]
184
+ #
185
+ # @note 制限事項
186
+ # When::TM::TopologicalComplex どうしの包含判定は、和集合がもとの範囲と等しいか
187
+ # で判断している。分解能が When::SYSTEM でない場合、論理的には等しいものが、
188
+ # 内部表現が異なるために等しくないとみなされる事があり、その場合 true であるべき
189
+ # ものを false と誤判断する。実行速度上の制約もあり、現時点では対策しない。
190
+ #
191
+ def include?(other)
192
+ if (other.kind_of?(Comparable) && !other.kind_of?(GeometricComplex))
193
+ return (_include_point?(other) != false)
194
+ else
195
+ other = GeometricComplex.new(other) unless other.kind_of?(GeometricComplex)
196
+ return _include_range?(other)
197
+ end
198
+ end
199
+ alias :=== :include?
200
+
201
+ # Enumerator._exclude 専用
202
+ # @private
203
+ def _include?(other)
204
+ if (other.kind_of?(Comparable) && !other.kind_of?(GeometricComplex))
205
+ return _include_point?(other)
206
+ else
207
+ other = GeometricComplex.new(other) unless other.kind_of?(GeometricComplex)
208
+ return _include_range?(other) && _include_point?(other.first)
209
+ end
210
+ end
211
+
212
+ # オブジェクトの生成
213
+ #
214
+ # @overload initialize(range, reverse=false)
215
+ # @param [Range] range
216
+ #
217
+ # @overload initialize(point, reverse=false)
218
+ # range = Range(point..point) と同じ
219
+ # @param [Comparable] point
220
+ #
221
+ # @overload initialize(first, last, reverse=false)
222
+ # range = Range(first...last) と同じ
223
+ # @param [Comparable] first
224
+ # @param [Comparable] last
225
+ #
226
+ # @overload initialize(first, duration, reverse=false)
227
+ # range = Range(first...(first+duration)) と同じ
228
+ # @param [Comparable] first
229
+ # @param [When::TM::Duration] duration
230
+ #
231
+ # @overload initialize(other, reverse=false)
232
+ # もとの When::Parts::GeometricComplex のコピー
233
+ # @param [When::Parts::GeometricComplex] other
234
+ #
235
+ # @overload initialize(node, reverse=false)
236
+ # 指定した node 構造の When::Parts::GeometricComplex を生成
237
+ # @param [Array<Array<Comparable, Boolean>>] note
238
+ # - Comparable - 端点
239
+ # - Boolean
240
+ # @reverse == true の場合
241
+ # true - 範囲に含まない
242
+ # false - 範囲に含む
243
+ # @reverse == false の場合
244
+ # true - 範囲に含む
245
+ # false - 範囲に含まない
246
+ # @note
247
+ # すべての呼び出しパターンに共通の最終引数 reverse を付けることができる
248
+ # reverse [Boolean]
249
+ # true - 反転する
250
+ # false - 反転しない
251
+ #
252
+ def initialize(*args)
253
+
254
+ @reverse = (args[-1]==true || args[-1]==false) ? args.pop : false
255
+
256
+ case args[0]
257
+ when GeometricComplex
258
+ @node = args[0].node
259
+ @reverse ^= args[0].reverse
260
+ super(self.first, self.last, exclude_end?) if self.first && self.last
261
+ return
262
+
263
+ when Array
264
+ @node = args[0]
265
+ super(self.first, self.last, exclude_end?) if self.first && self.last
266
+ return
267
+
268
+ when Range
269
+ first = [args[0].first, true]
270
+ last = [args[0].last, !args[0].exclude_end?]
271
+
272
+ when Comparable
273
+ first, last, rest = args
274
+ raise ArgumentError, "Too many argument: #{rest}" if rest
275
+ first = [first, true]
276
+ case last
277
+ when Comparable ; last = [last, false]
278
+ when When::TM::Duration ; last = [first[0] + last, false]
279
+ when nil ; last = first
280
+ else ; raise TypeError, "Irregal GeometricComplex Type for last element: #{last.class}"
281
+ end
282
+
283
+ when nil ;
284
+ else ; raise TypeError, "Irregal GeometricComplex Type: #{first.class}"
285
+ end
286
+
287
+ first, last = last, first if (first && last && first[0] > last[0])
288
+ @node = []
289
+ @node << first if first
290
+ @node << last if last
291
+ super(self.first, self.last, exclude_end?) if first && last
292
+ end
293
+
294
+ private
295
+
296
+ def _include_range?(other)
297
+ union = self | other
298
+ return false unless self.node == union.node
299
+ return self.reverse == union.reverse
300
+ end
301
+
302
+ def _include_point?(other)
303
+ @node.each_index do |i|
304
+ current = @node[i]
305
+ verify = other <=> current[0]
306
+ if (verify < 0)
307
+ return false if ((i[0]==0) ^ @reverse)
308
+ return @node[[0,i-1].max][0]
309
+ elsif (verify == 0)
310
+ return false unless (@reverse ^ current[1])
311
+ return current[0]
312
+ end
313
+ end
314
+ return (@reverse ? nil : false) if @node.length==0
315
+ return false if ((@node.length[0]==0) ^ @reverse)
316
+ return @node[-1][0]
317
+ end
318
+
319
+ def _upper(node, point, reverse)
320
+ node = node.dup
321
+ point = point.dup
322
+ point[1] = !point[1] if reverse
323
+ node.each_index do |i|
324
+ if (_verify(point, node[i], reverse) <= 0)
325
+ node[i..-1] = ((i[0]==0) ^ reverse) ? [point] : []
326
+ return node
327
+ end
328
+ end
329
+ node.push(point) if (node.length[0]==0) ^ @everse
330
+ return node
331
+ end
332
+
333
+ def _lower(node, point, reverse)
334
+ node = node.dup
335
+ point = point.dup
336
+ point[1] = !point[1] if reverse
337
+ (node.length-1).downto(0) do |i|
338
+ if (_verify(point, node[i], reverse) >= 0)
339
+ node[0..i] = ((i[0]==1) ^ reverse) ? [point] : []
340
+ return node
341
+ end
342
+ end
343
+ node.unshift(point) if (node.length[0]==0) ^ reverse
344
+ return node
345
+ end
346
+
347
+ def _verify(point, node, reverse)
348
+ verify = point[0] <=> node[0]
349
+ return verify unless verify == 0
350
+ if point[0].respond_to?(:precision) && node[0].respond_to?(:precision)
351
+ point[0] = node[0] if point[0].precision >= node[0].precision
352
+ end
353
+ if reverse
354
+ point[1] &= node[1]
355
+ else
356
+ point[1] |= node[1]
357
+ end
358
+ return verify
359
+ end
360
+
361
+ def _max(p1, p2)
362
+ p1[1] = !p1[1]
363
+ p2[1] = !p2[1]
364
+ verify = p1[0] <=> p2[0]
365
+ return p1 if (verify>0)
366
+ return p2 if (verify<0)
367
+ p1[1] |= p2[1]
368
+ return p1
369
+ end
370
+
371
+ # その他のメソッド
372
+ # When::Parts::GeometricComplex で定義されていないメソッドは
373
+ # 処理を first (type: When::TM::(Temporal)Position) に委譲する
374
+ #
375
+ def method_missing(name, *args, &block)
376
+ first.send(name.to_sym, *args, &block)
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,513 @@
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2012 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
+ # Multilingualization(M17n) 対応モジュール
15
+ #
16
+ # When::BasicTypes::M17n の実装のうち When::BasicTypes 内部で
17
+ # 定義すべきでない部分を切り出してモジュールとしている
18
+ #
19
+ module Locale
20
+
21
+ # Locale 読み替えの初期設定
22
+ Alias = {'alias'=>'ja', '日本語'=>'ja', '英語'=>'en'}
23
+
24
+ # 漢字の包摂
25
+ DefaultUnification = {
26
+ '煕' => '熙',
27
+ '廣' => '広',
28
+ '寶' => '宝',
29
+ '國' => '国',
30
+ '應' => '応',
31
+ '觀' => '観',
32
+ '龜' => '亀',
33
+ '齊' => '斉',
34
+ '靈' => '霊',
35
+ '攝' => '摂',
36
+ '壽' => '寿',
37
+ '萬' => '万',
38
+ '廢' => '廃',
39
+ '顯' => '顕',
40
+ '會' => '会',
41
+ '聰' => '聡',
42
+ '總' => '総',
43
+ '證' => '証',
44
+ '禮' => '礼',
45
+ '竜' => '龍',
46
+ }
47
+
48
+ # @private
49
+ Escape = '__!_ESCAPE_%2C_!__'
50
+
51
+ class << self
52
+
53
+ # When::Parts::Locale Module のグローバルな設定を行う
54
+ #
55
+ # @param [Hash] aliases
56
+ # Locale の読み替えパターンを Hash で指定する。
57
+ # aliases の指定がない場合、aliases は Alias(モジュール定数)と解釈する。
58
+ #
59
+ def _setup_(aliases=nil)
60
+ @aliases = aliases || Alias
61
+ end
62
+
63
+ # 特定 locale に対応した文字列の取得
64
+ #
65
+ # @param [String] source もとにする String または M17n
66
+ #
67
+ # @param[String] loc locale の指定 ( lang[-|_]country.encode )
68
+ # [ lang - 言語 ]
69
+ # [ country - 国(省略可) ]
70
+ # [ encode - 文字コード(省略可) ]
71
+ #
72
+ # @return [String] loc に対応した文字列
73
+ #
74
+ # @note source が Hash や Array の場合、その構成要素を変換して返す
75
+ #
76
+ def translate(source, loc='')
77
+ return source unless loc
78
+ case source
79
+ when Hash
80
+ result = {}
81
+ source.each_pair do |key, value|
82
+ result[translate(key, loc)] = translate(value, loc)
83
+ end
84
+ return result
85
+ when Array
86
+ return source.map {|value| translate(value, loc)}
87
+ when Locale
88
+ return source.translate(loc)
89
+ when String
90
+ return source.encode($1) if loc =~ /\.(.+)$/
91
+ end
92
+ source
93
+ end
94
+
95
+ # 包摂リストに登録されている文字を包摂する
96
+ #
97
+ # @param [When::Parts::Locale] source 文字を包摂しようとする国際化文字列
98
+ # @param [String] source 文字を包摂しようとする文字列
99
+ # @param [Regexp] source 文字を包摂しようとする正規表現
100
+ # @param [Hash] pattern 包摂ルール
101
+ #
102
+ # @return [When::Parts::Locale] 文字を包摂した国際化文字列
103
+ # @return [String] 文字を包摂した文字列
104
+ # @return [Regexp] 文字を包摂した正規表現
105
+ #
106
+ def ideographic_unification(source, pattern=DefaultUnification)
107
+ case source
108
+ when When::Parts::Locale
109
+ source.ideographic_unification(pattern)
110
+ when Regexp
111
+ Regexp.compile(ideographic_unification(source.source.encode('UTF-8'), pattern), source.options)
112
+ when String
113
+ source.gsub(/./) do |c|
114
+ pattern[c] ? pattern[c] : c
115
+ end
116
+ else
117
+ source
118
+ end
119
+ end
120
+
121
+ # 文字列で表現された namespace 指定を Hash に変換する
122
+ # @private
123
+ def _namespace(source=nil)
124
+ case source
125
+ when Hash ; return source
126
+ when nil ; return {}
127
+ when String
128
+ namespace = {}
129
+ source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
130
+ source.split(/[\n\r,]+/).each do |v|
131
+ v.strip!
132
+ next if (v=~/^#/)
133
+ pair = [''] + v.split(/\s*=\s*/, 2)
134
+ namespace[pair[-2]] = pair[-1]
135
+ end
136
+ return namespace
137
+ else ; raise TypeError, "Irregal Namespace Type"
138
+ end
139
+ end
140
+
141
+ # locale 指定を Array に変換する
142
+ # @private
143
+ def _locale(source=nil)
144
+ # default の Locale
145
+ return [[nil, '', nil]] unless source
146
+
147
+ # source の配列化
148
+ if source.kind_of?(String)
149
+ source = $1 if (source=~/\A\s*\[?(.+?)\]?\s*\z/m)
150
+ source = source.split(/[\n\r,]+/)
151
+ end
152
+
153
+ # 各Localeの展開
154
+ source.map {|v|
155
+ if v.kind_of?(String)
156
+ v = v.strip
157
+ next if (v=~/^#/)
158
+ (v =~ /^(\*)?(.*?)(?:\s*=\s*(.+))?$/) ? $~[1..3] : [[nil, '', nil]]
159
+ else
160
+ v
161
+ end
162
+ }.compact
163
+ end
164
+
165
+ # 文字列 [.., .., ..] を分割する
166
+ # @private
167
+ def _split(line)
168
+ line = line.dup
169
+ b = d = s = 0
170
+ (line.length-1).downto(0) do |i|
171
+ bs = 0
172
+ (i-1).downto(0) do |k|
173
+ break unless (line[k,1] == '\\')
174
+ bs += 1
175
+ end
176
+ next if (bs[0] == 1)
177
+ case line[i,1]
178
+ when "'" ; s = 1-s if (d == 0)
179
+ when '"' ; d = 1-d if (s == 0)
180
+ when ']' ; b += 1 if (d+s == 0)
181
+ when '[' ; b -= 1 if (d+s == 0 && b > 0)
182
+ when ',' ; line[i,1] = Escape if (b+d+s == 0)
183
+ end
184
+ end
185
+ return (line =='') ? [''] : line.split(Escape, -1)
186
+ end
187
+
188
+ # locale 指定を解析して Hash の値を取り出す
189
+ # @private
190
+ def _hash_value(hash, locale, default='')
191
+ locale = locale.sub(/\..*/, '').sub(/-/,'_')
192
+ return hash[locale] if (hash[locale])
193
+ return _hash_value(hash, _alias[locale], default) if (_alias[locale])
194
+ language = locale.sub(/_.*/, '')
195
+ return hash[language] if (hash[language])
196
+ return hash[default]
197
+ end
198
+
199
+ private
200
+
201
+ def _alias
202
+ @aliases || Alias
203
+ end
204
+ end
205
+
206
+ # ローケール指定時の文字列
207
+ #
208
+ # @return [Hash]
209
+ attr_reader :names
210
+
211
+ # 有効なローケール指定
212
+ #
213
+ # @return [Array<String>]
214
+ attr_reader :keys
215
+
216
+ # 有効な文字列 - additional attribute
217
+ #
218
+ # @return [Array<String>]
219
+ attr_reader :values
220
+
221
+ # 文字列の説明 - additional attribute
222
+ #
223
+ # @return [Hash] { anyURI }
224
+ attr_reader :link
225
+
226
+ # Rails 用 I18n 定義へのアクセス・キー
227
+ #
228
+ # @return [String]
229
+ attr_reader :access_key
230
+ protected :access_key
231
+
232
+ # 特定 locale に対応した文字列の取得
233
+ #
234
+ # @param [String] loc locale の指定 ( lang[-|_]country.encode )
235
+ # [ lang - 言語 ]
236
+ # [ country - 国(省略可) ]
237
+ # [ encode - 文字コード(省略可) ]
238
+ #
239
+ # @return [String] loc に対応した文字列
240
+ #
241
+ def translate(loc='')
242
+ return to_s unless loc
243
+ lang, code = loc.split(/\./)
244
+ result = _label_value(loc)
245
+ return result if !code || @names.member?(loc)
246
+ return result.encode(code)
247
+ end
248
+ alias :/ :translate
249
+
250
+ # 特定 locale に対応した reference URI の取得
251
+ #
252
+ # @param [String] loc locale の指定
253
+ #
254
+ # @return [String] loc に対応した reference URI
255
+ #
256
+ def reference(loc='')
257
+ loc ||= ''
258
+ return Locale._hash_value(@link, loc)
259
+ end
260
+
261
+ # 部分文字列
262
+ #
263
+ # @param [Range] range String#[] と同様の指定方法で範囲を指定する
264
+ #
265
+ # @return [When::Parts::Locale] 指定範囲に対応した部分文字列
266
+ #
267
+ def [](range)
268
+ dup._copy({
269
+ :label => to_s[range],
270
+ :names => @names.keys.inject({}) {|l,k|
271
+ l[k] = @names[k][range]
272
+ l
273
+ }
274
+ })
275
+ end
276
+
277
+ # 文字列の一致
278
+ #
279
+ # @param [String, Regexp] regexp マッチする正規表現
280
+ #
281
+ # @return [Integer] マッチした位置のindex(いずれかの locale でマッチが成功した場合)
282
+ # @return [nil] すべての locale でマッチに失敗した場合
283
+ #
284
+ def =~(regexp)
285
+ @keys.each do |key|
286
+ index = (@names[key] =~ regexp)
287
+ return index if index
288
+ end
289
+ return nil
290
+ end
291
+
292
+ # 文字列の連結
293
+ #
294
+ # @param [String, When::Toos::Locale] other 連結する文字列
295
+ #
296
+ # @return [When::Toos::Locale] 連結された文字列
297
+ #
298
+ def +(other)
299
+ names = {}
300
+ case other
301
+ when Locale
302
+ (@names.keys + other.names.keys).uniq.each do |key|
303
+ names[key] = _label_value(key) + other._label_value(key)
304
+ end
305
+ else
306
+ @names.keys.each do |key|
307
+ names[key] = _label_value(key) + other.to_s
308
+ end
309
+ end
310
+ return dup._copy({:names=>names, :label=>to_s + other.to_s})
311
+ end
312
+
313
+ # 書式指定による文字列化
314
+ #
315
+ # @param [Array<Object>] other 文字列化する Object の Array
316
+ # @param [Array<String>] locale 文字列化を行う locale の指定(デフォルト : すべて)
317
+ #
318
+ # @return [When::Toos::Locale] 文字列化された Object
319
+ #
320
+ def _printf(other, locale=nil)
321
+ # 処理する配列
322
+ terms = other.kind_of?(Array) ? [self] + other : [self, other]
323
+
324
+ # locale key の配列
325
+ if locale == []
326
+ keys = []
327
+ else
328
+ keys = terms.inject([]) {|k,t|
329
+ k += t.keys if t.kind_of?(Locale)
330
+ k
331
+ }.uniq
332
+ if locale
333
+ locale = [locale] unless locale.kind_of?(Array)
334
+ keys = locale | (locale & keys)
335
+ end
336
+ end
337
+ keys << nil if keys.include?('')
338
+
339
+ # names ハッシュ
340
+ names = keys.inject({}) {|l,k|
341
+ l[k] = When::Coordinates::Pair._format(
342
+ (block_given? ? yield(k, *terms) : terms).map {|t|
343
+ t.kind_of?(Locale) ? t.translate(k) : t
344
+ }
345
+ )
346
+ l
347
+ }
348
+
349
+ # 生成
350
+ # @private
351
+ dup._copy({
352
+ :label => keys.include?('') ? names.delete(nil) : (names[''] = names[keys[0]]),
353
+ :names => names
354
+ })
355
+ end
356
+ alias :% :_printf
357
+
358
+ # ローケールの更新
359
+ #
360
+ # @param [Hash] options 下記の通り
361
+ # @option options [String] カントリーコード 表現文字列
362
+ # @option options [Hash] :link { カントリーコード => 参照URL文字列 }
363
+ # @option options [String] :code_space 規格や辞書を特定するコードスペースのURL文字列
364
+ # @option options [String] :label 代表文字列
365
+ # @note Hashキーはすべて Optional で、存在するもののみ更新します
366
+ #
367
+ # @return [self] 更新された Object
368
+ #
369
+ def update(options={})
370
+ options = options.dup
371
+ @link.update(options.delete(:link)) if (options.key?(:link))
372
+ @code_space = options.delete(:code_space) if (options.key?(:code_space))
373
+ self[0..-1] = options.delete(:label) if (options.key?(:label))
374
+ unless (options.empty?)
375
+ @names.update(options)
376
+ @keys = @names.keys.sort
377
+ @values = @names.values.sort.reverse
378
+ end
379
+ return self
380
+ end
381
+
382
+ # 包摂リストに登録されている文字を包摂する(自己破壊)
383
+ #
384
+ # @param [Hash] pattern 包摂ルール
385
+ #
386
+ # @return [When::Parts::Locale] self
387
+ # @private
388
+ def ideographic_unification!(pattern=DefaultUnification)
389
+ names = {}
390
+ @names.each_pair do |key, value|
391
+ names[key] = Locale.ideographic_unification(value, pattern)
392
+ end
393
+ @names = names
394
+ @values = @names.values.sort.reverse
395
+ self[0..-1] = Locale.ideographic_unification(self.to_s[0..-1], pattern)
396
+ return self
397
+ end
398
+ protected :ideographic_unification!
399
+
400
+ # 包摂リストに登録されている文字を包摂する(自己保存)
401
+ #
402
+ # @param [Hash] pattern 包摂ルール
403
+ #
404
+ # @return [When::Parts::Locale] 包摂結果
405
+ #
406
+ def ideographic_unification(pattern=DefaultUnification)
407
+ dup.ideographic_unification!(pattern)
408
+ end
409
+
410
+ # 閏の表記を扱うための書式付整形
411
+ # @private
412
+ def prefix(other, locale=nil)
413
+ return self.dup unless other
414
+ other = m17n(other) unless other.kind_of?(Locale)
415
+ other._printf(self, locale) do |k, *t|
416
+ t[0] = t[0].translate(k)
417
+ t[0] += "%s" unless t[0] =~ /%[-+]?[.\d]*s/
418
+ t
419
+ end
420
+ end
421
+
422
+ protected
423
+
424
+ # @private
425
+ def _copy(options={})
426
+ if (options.key?(:names))
427
+ @names = options[:names]
428
+ @keys = @names.keys.sort
429
+ @values = @names.values.compact.sort.reverse
430
+ end
431
+ @link = options[:link] if (options.key?(:link))
432
+ @code_space = options[:code_space] if (options.key?(:code_space))
433
+ @access_key = options[:access_key] if (options.key?(:access_key))
434
+ self[0..-1] = options[:label] if (options.key?(:label))
435
+ return self
436
+ end
437
+
438
+ # @private
439
+ def _copy_all(other)
440
+ _copy({:names => other.names,
441
+ :link => other.link,
442
+ :code_space => other.code_space,
443
+ :access_key => other.access_key,
444
+ :label => other.to_s
445
+ })
446
+ end
447
+
448
+ # locale 指定を解析して @names の値を取り出す
449
+ # @private
450
+ def _label_value(locale)
451
+ label = Locale._hash_value(@names, locale, nil)
452
+ return label if label
453
+ addition = When::BasicTypes::M17n._get_locale(locale, @access_key)
454
+ return @names[''] unless addition
455
+ update(addition)
456
+ return Locale._hash_value(@names, locale)
457
+ end
458
+
459
+ private
460
+
461
+ def _names(names, namespace, default_locale)
462
+
463
+ # names, link の組み立て
464
+ @names = {}
465
+ @link = {}
466
+
467
+ if (names.kind_of?(String))
468
+ unless (names=~/\A\s*\[(.+?)\]\s*\z/m)
469
+ names = names.strip
470
+ @names[''] = names
471
+ @keys = ['']
472
+ @values = [names]
473
+ return names
474
+ end
475
+ names = $1.split(/[\n\r,]+/)
476
+ end
477
+
478
+ mark = []
479
+ asterisk = []
480
+ default_locale = default_locale.dup
481
+ names.each do |v|
482
+ v.strip!
483
+ case v
484
+ when '', /^#/ ;
485
+ when /^\/(.+)/; @access_key = $1
486
+ when /^(\*)?(?:([^=%]*?)\s*:)?\s*(.+?)\s*(=\s*(.+?)?)?$/
487
+ asterisk[0], locale, name, assignment, ref = $~[1..5]
488
+ asterisk[1], locale, default_ref = default_locale.shift unless locale
489
+ locale ||= ''
490
+ ref ||= default_ref unless (assignment)
491
+ ref ||= ''
492
+ mark[0] = locale if asterisk[0]
493
+ mark[1] = locale if asterisk[1]
494
+ mark[2] = locale unless mark[2]
495
+ @names[locale] = name
496
+ if (ref =~ /^(.+):/)
497
+ prefix = namespace[$1]
498
+ ref.sub!(/^.+:/, prefix) if (prefix)
499
+ end
500
+ ref += URI.encode(name) if (ref =~ /[\/#:]$/)
501
+ @link[locale] = ref
502
+ else ; raise ArgumentError, "Irregal locale format"
503
+ end
504
+ end
505
+
506
+ # keys, values の準備
507
+ @keys = @names.keys.sort
508
+ @values = @names.values.sort.reverse
509
+
510
+ return @names[mark[0] || mark[1] || mark[2]]
511
+ end
512
+ end
513
+ end