rhodes 0.1.0

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 (53) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +4 -0
  3. data/Manifest.txt +52 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +33 -0
  6. data/bin/rhogen +8 -0
  7. data/generators/rhogen.rb +99 -0
  8. data/generators/templates/application/application.rb +4 -0
  9. data/generators/templates/application/index.html +25 -0
  10. data/generators/templates/model/config.rb +3 -0
  11. data/generators/templates/model/controller.rb +48 -0
  12. data/generators/templates/model/edit.erb +21 -0
  13. data/generators/templates/model/index.erb +10 -0
  14. data/generators/templates/model/new.erb +16 -0
  15. data/lib/ServeME.rb +7 -0
  16. data/lib/TestServe.rb +9 -0
  17. data/lib/builtinME.rb +481 -0
  18. data/lib/date.rb +1781 -0
  19. data/lib/date/format.rb +1313 -0
  20. data/lib/erb.rb +896 -0
  21. data/lib/find.rb +81 -0
  22. data/lib/rational.rb +19 -0
  23. data/lib/rho.rb +1 -0
  24. data/lib/rho/render.rb +9 -0
  25. data/lib/rho/renderME.rb +8 -0
  26. data/lib/rho/rho.rb +173 -0
  27. data/lib/rho/rhoapplication.rb +36 -0
  28. data/lib/rho/rhocontroller.rb +51 -0
  29. data/lib/rho/rhofsconnector.rb +39 -0
  30. data/lib/rho/rhofsconnectorME.rb +36 -0
  31. data/lib/rho/rhosupport.rb +139 -0
  32. data/lib/rhodes.rb +5 -0
  33. data/lib/rhofsconnector.rb +5 -0
  34. data/lib/rhom.rb +1 -0
  35. data/lib/rhom/rhom.rb +41 -0
  36. data/lib/rhom/rhom_db_adapter.rb +183 -0
  37. data/lib/rhom/rhom_db_adapterME.rb +91 -0
  38. data/lib/rhom/rhom_object.rb +53 -0
  39. data/lib/rhom/rhom_object_factory.rb +246 -0
  40. data/lib/singleton.rb +313 -0
  41. data/lib/time.rb +839 -0
  42. data/rhodes.gemspec +18 -0
  43. data/spec/app_generator_spec.rb +27 -0
  44. data/spec/generator_spec_helper.rb +12 -0
  45. data/spec/model_generator_spec.rb +28 -0
  46. data/spec/rho_spec.rb +28 -0
  47. data/spec/rhom_object_factory_spec.rb +147 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +14 -0
  50. data/spec/stubs.rb +17 -0
  51. data/spec/syncdbtest.sqlite +0 -0
  52. data/tasks/rspec.rake +34 -0
  53. metadata +157 -0
@@ -0,0 +1,1313 @@
1
+ # format.rb: Written by Tadayoshi Funaba 1999-2008
2
+ # $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
3
+
4
+ require 'rational'
5
+
6
+ class Date
7
+
8
+ module Format # :nodoc:
9
+
10
+ MONTHS = {
11
+ 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
12
+ 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
13
+ 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
14
+ }
15
+
16
+ DAYS = {
17
+ 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
18
+ 'thursday' => 4, 'friday' => 5, 'saturday' => 6
19
+ }
20
+
21
+ ABBR_MONTHS = {
22
+ 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
23
+ 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
24
+ 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
25
+ }
26
+
27
+ ABBR_DAYS = {
28
+ 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
29
+ 'thu' => 4, 'fri' => 5, 'sat' => 6
30
+ }
31
+
32
+ ZONES = {
33
+ 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
34
+ 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
35
+ 'pst' => -8*3600, 'pdt' => -7*3600,
36
+ 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
37
+ 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
38
+ 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
39
+ 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
40
+ 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
41
+ 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
42
+ 'z' => 0*3600,
43
+
44
+ 'utc' => 0*3600, 'wet' => 0*3600,
45
+ 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800),
46
+ 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600,
47
+ 'nst' => -(3*3600+1800),
48
+ 'ast' => -4*3600, 'clt' => -4*3600,
49
+ 'akdt'=> -8*3600, 'ydt' => -8*3600,
50
+ 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600,
51
+ 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600,
52
+ 'nt' =>-11*3600,
53
+ 'idlw'=>-12*3600,
54
+ 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600,
55
+ 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600,
56
+ 'west'=> 1*3600,
57
+ 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600,
58
+ 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600,
59
+ 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600,
60
+ 'msd' => 4*3600, 'zp4' => 4*3600,
61
+ 'zp5' => 5*3600, 'ist' => (5*3600+1800),
62
+ 'zp6' => 6*3600,
63
+ 'wast'=> 7*3600,
64
+ 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600,
65
+ 'jst' => 9*3600, 'kst' => 9*3600,
66
+ 'east'=> 10*3600, 'gst' => 10*3600,
67
+ 'eadt'=> 11*3600,
68
+ 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600,
69
+ 'nzdt'=> 13*3600,
70
+
71
+ 'afghanistan' => 16200, 'alaskan' => -32400,
72
+ 'arab' => 10800, 'arabian' => 14400,
73
+ 'arabic' => 10800, 'atlantic' => -14400,
74
+ 'aus central' => 34200, 'aus eastern' => 36000,
75
+ 'azores' => -3600, 'canada central' => -21600,
76
+ 'cape verde' => -3600, 'caucasus' => 14400,
77
+ 'cen. australia' => 34200, 'central america' => -21600,
78
+ 'central asia' => 21600, 'central europe' => 3600,
79
+ 'central european' => 3600, 'central pacific' => 39600,
80
+ 'central' => -21600, 'china' => 28800,
81
+ 'dateline' => -43200, 'e. africa' => 10800,
82
+ 'e. australia' => 36000, 'e. europe' => 7200,
83
+ 'e. south america' => -10800, 'eastern' => -18000,
84
+ 'egypt' => 7200, 'ekaterinburg' => 18000,
85
+ 'fiji' => 43200, 'fle' => 7200,
86
+ 'greenland' => -10800, 'greenwich' => 0,
87
+ 'gtb' => 7200, 'hawaiian' => -36000,
88
+ 'india' => 19800, 'iran' => 12600,
89
+ 'jerusalem' => 7200, 'korea' => 32400,
90
+ 'mexico' => -21600, 'mid-atlantic' => -7200,
91
+ 'mountain' => -25200, 'myanmar' => 23400,
92
+ 'n. central asia' => 21600, 'nepal' => 20700,
93
+ 'new zealand' => 43200, 'newfoundland' => -12600,
94
+ 'north asia east' => 28800, 'north asia' => 25200,
95
+ 'pacific sa' => -14400, 'pacific' => -28800,
96
+ 'romance' => 3600, 'russian' => 10800,
97
+ 'sa eastern' => -10800, 'sa pacific' => -18000,
98
+ 'sa western' => -14400, 'samoa' => -39600,
99
+ 'se asia' => 25200, 'malay peninsula' => 28800,
100
+ 'south africa' => 7200, 'sri lanka' => 21600,
101
+ 'taipei' => 28800, 'tasmania' => 36000,
102
+ 'tokyo' => 32400, 'tonga' => 46800,
103
+ 'us eastern' => -18000, 'us mountain' => -25200,
104
+ 'vladivostok' => 36000, 'w. australia' => 28800,
105
+ 'w. central africa' => 3600, 'w. europe' => 3600,
106
+ 'west asia' => 18000, 'west pacific' => 36000,
107
+ 'yakutsk' => 32400
108
+ }
109
+
110
+ [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
111
+ x.freeze
112
+ end
113
+
114
+ class Bag # :nodoc:
115
+
116
+ def initialize
117
+ @elem = {}
118
+ end
119
+
120
+ def method_missing(t, *args, &block)
121
+ t = t.to_s
122
+ set = t.chomp!('=')
123
+ t = t.intern
124
+ if set
125
+ @elem[t] = args[0]
126
+ else
127
+ @elem[t]
128
+ end
129
+ end
130
+
131
+ def to_hash
132
+ @elem.reject{|k, v| /\A_/ =~ k.to_s || v.nil?}
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+
139
+ def emit(e, f) # :nodoc:
140
+ case e
141
+ when Numeric
142
+ sign = %w(+ + -)[e <=> 0]
143
+ e = e.abs
144
+ end
145
+
146
+ s = e.to_s
147
+
148
+ if f[:s] && f[:p] == '0'
149
+ f[:w] -= 1
150
+ end
151
+
152
+ if f[:s] && f[:p] == "\s"
153
+ s[0,0] = sign
154
+ end
155
+
156
+ if f[:p] != '-'
157
+ s = s.rjust(f[:w], f[:p])
158
+ end
159
+
160
+ if f[:s] && f[:p] != "\s"
161
+ s[0,0] = sign
162
+ end
163
+
164
+ s = s.upcase if f[:u]
165
+ s = s.downcase if f[:d]
166
+ s
167
+ end
168
+
169
+ def emit_w(e, w, f) # :nodoc:
170
+ f[:w] = [f[:w], w].compact.max
171
+ emit(e, f)
172
+ end
173
+
174
+ def emit_n(e, w, f) # :nodoc:
175
+ f[:p] ||= '0'
176
+ emit_w(e, w, f)
177
+ end
178
+
179
+ def emit_sn(e, w, f) # :nodoc:
180
+ if e < 0
181
+ w += 1
182
+ f[:s] = true
183
+ end
184
+ emit_n(e, w, f)
185
+ end
186
+
187
+ def emit_z(e, w, f) # :nodoc:
188
+ w += 1
189
+ f[:s] = true
190
+ emit_n(e, w, f)
191
+ end
192
+
193
+ def emit_a(e, w, f) # :nodoc:
194
+ f[:p] ||= "\s"
195
+ emit_w(e, w, f)
196
+ end
197
+
198
+ def emit_ad(e, w, f) # :nodoc:
199
+ if f[:x]
200
+ f[:u] = true
201
+ f[:d] = false
202
+ end
203
+ emit_a(e, w, f)
204
+ end
205
+
206
+ def emit_au(e, w, f) # :nodoc:
207
+ if f[:x]
208
+ f[:u] = false
209
+ f[:d] = true
210
+ end
211
+ emit_a(e, w, f)
212
+ end
213
+
214
+ private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
215
+ :emit_a, :emit_ad, :emit_au
216
+
217
+ def strftime(fmt='%F')
218
+ fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do
219
+ f = {}
220
+ m = $&
221
+ s, w, c = $1, $2, $3
222
+ if s
223
+ s.scan(/./) do |k|
224
+ case k
225
+ when '-'; f[:p] = '-'
226
+ when '_'; f[:p] = "\s"
227
+ when '0'; f[:p] = '0'
228
+ when '^'; f[:u] = true
229
+ when '#'; f[:x] = true
230
+ end
231
+ end
232
+ end
233
+ if w
234
+ f[:w] = w.to_i
235
+ end
236
+ case c
237
+ when 'A'; emit_ad(DAYNAMES[wday], 0, f)
238
+ when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
239
+ when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
240
+ when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
241
+ when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
242
+ when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
243
+ when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
244
+ when 'd', 'Od'; emit_n(mday, 2, f)
245
+ when 'e', 'Oe'; emit_a(mday, 2, f)
246
+ when 'F'
247
+ if m == '%F'
248
+ format('%.4d-%02d-%02d', year, mon, mday) # 4p
249
+ else
250
+ emit_a(strftime('%Y-%m-%d'), 0, f)
251
+ end
252
+ when 'G'; emit_sn(cwyear, 4, f)
253
+ when 'g'; emit_n(cwyear % 100, 2, f)
254
+ when 'H', 'OH'; emit_n(hour, 2, f)
255
+ when 'h'; emit_ad(strftime('%b'), 0, f)
256
+ when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
257
+ when 'j'; emit_n(yday, 3, f)
258
+ when 'k'; emit_a(hour, 2, f)
259
+ when 'L'
260
+ w = f[:w] || 3
261
+ u = 10**w
262
+ emit_n((sec_fraction * u).floor, w, f)
263
+ when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
264
+ when 'M', 'OM'; emit_n(min, 2, f)
265
+ when 'm', 'Om'; emit_n(mon, 2, f)
266
+ when 'N'
267
+ w = f[:w] || 9
268
+ u = 10**w
269
+ emit_n((sec_fraction * u).floor, w, f)
270
+ when 'n'; emit_a("\n", 0, f)
271
+ when 'P'; emit_ad(strftime('%p').downcase, 0, f)
272
+ when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
273
+ when 'Q'
274
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
275
+ emit_sn(s, 1, f)
276
+ when 'R'; emit_a(strftime('%H:%M'), 0, f)
277
+ when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
278
+ when 'S', 'OS'; emit_n(sec, 2, f)
279
+ when 's'
280
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
281
+ emit_sn(s, 1, f)
282
+ when 'T'
283
+ if m == '%T'
284
+ format('%02d:%02d:%02d', hour, min, sec) # 4p
285
+ else
286
+ emit_a(strftime('%H:%M:%S'), 0, f)
287
+ end
288
+ when 't'; emit_a("\t", 0, f)
289
+ when 'U', 'W', 'OU', 'OW'
290
+ emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
291
+ when 'u', 'Ou'; emit_n(cwday, 1, f)
292
+ when 'V', 'OV'; emit_n(cweek, 2, f)
293
+ when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
294
+ when 'w', 'Ow'; emit_n(wday, 1, f)
295
+ when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
296
+ when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
297
+ when 'Y', 'EY'; emit_sn(year, 4, f)
298
+ when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
299
+ when 'Z'; emit_au(strftime('%:z'), 0, f)
300
+ when /\A(:{0,3})z/
301
+ t = $1.size
302
+ sign = if offset < 0 then -1 else +1 end
303
+ fr = offset.abs
304
+ ss = fr.div(SECONDS_IN_DAY) # 4p
305
+ hh, ss = ss.divmod(3600)
306
+ mm, ss = ss.divmod(60)
307
+ if t == 3
308
+ if ss.nonzero? then t = 2
309
+ elsif mm.nonzero? then t = 1
310
+ else t = -1
311
+ end
312
+ end
313
+ case t
314
+ when -1
315
+ tail = []
316
+ sep = ''
317
+ when 0
318
+ f[:w] -= 2 if f[:w]
319
+ tail = ['%02d' % mm]
320
+ sep = ''
321
+ when 1
322
+ f[:w] -= 3 if f[:w]
323
+ tail = ['%02d' % mm]
324
+ sep = ':'
325
+ when 2
326
+ f[:w] -= 6 if f[:w]
327
+ tail = ['%02d' % mm, '%02d' % ss]
328
+ sep = ':'
329
+ end
330
+ ([emit_z(sign * hh, 2, f)] + tail).join(sep)
331
+ when '%'; emit_a('%', 0, f)
332
+ when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
333
+ else
334
+ m
335
+ end
336
+ end
337
+ end
338
+
339
+ # alias_method :format, :strftime
340
+
341
+ def asctime() strftime('%c') end
342
+
343
+ alias_method :ctime, :asctime
344
+
345
+ def iso8601() strftime('%F') end
346
+
347
+ def rfc3339() iso8601 end
348
+
349
+ def xmlschema() iso8601 end # :nodoc:
350
+
351
+ def rfc2822() strftime('%a, %-d %b %Y %T %z') end
352
+
353
+ alias_method :rfc822, :rfc2822
354
+
355
+ def httpdate() new_offset(0).strftime('%a, %d %b %Y %T GMT') end # :nodoc:
356
+
357
+ def jisx0301
358
+ if jd < 2405160
359
+ iso8601
360
+ else
361
+ case jd
362
+ when 2405160...2419614
363
+ g = 'M%02d' % (year - 1867)
364
+ when 2419614...2424875
365
+ g = 'T%02d' % (year - 1911)
366
+ when 2424875...2447535
367
+ g = 'S%02d' % (year - 1925)
368
+ else
369
+ g = 'H%02d' % (year - 1988)
370
+ end
371
+ g + strftime('.%m.%d')
372
+ end
373
+ end
374
+
375
+ =begin
376
+ def beat(n=0)
377
+ i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
378
+ ('@%03d' % i) +
379
+ if n < 1
380
+ ''
381
+ else
382
+ '.%0*d' % [n, (f / Rational(1, 10**n)).round]
383
+ end
384
+ end
385
+ =end
386
+
387
+ def self.num_pattern? (s) # :nodoc:
388
+ /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
389
+ end
390
+
391
+ private_class_method :num_pattern?
392
+
393
+ def self._strptime_i(str, fmt, e) # :nodoc:
394
+ fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c|
395
+ a = $&
396
+ if s
397
+ case s
398
+ when 'A', 'a'
399
+ return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
400
+ str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
401
+ val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
402
+ return unless val
403
+ e.wday = val
404
+ when 'B', 'b', 'h'
405
+ return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
406
+ str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
407
+ val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
408
+ return unless val
409
+ e.mon = val
410
+ when 'C', 'EC'
411
+ return unless str.sub!(if num_pattern?($')
412
+ then /\A([-+]?\d{1,2})/
413
+ else /\A([-+]?\d{1,})/
414
+ end, '')
415
+ val = $1.to_i
416
+ e._cent = val
417
+ when 'c', 'Ec'
418
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
419
+ when 'D'
420
+ return unless _strptime_i(str, '%m/%d/%y', e)
421
+ when 'd', 'e', 'Od', 'Oe'
422
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
423
+ val = $1.to_i
424
+ return unless (1..31) === val
425
+ e.mday = val
426
+ when 'F'
427
+ return unless _strptime_i(str, '%Y-%m-%d', e)
428
+ when 'G'
429
+ return unless str.sub!(if num_pattern?($')
430
+ then /\A([-+]?\d{1,4})/
431
+ else /\A([-+]?\d{1,})/
432
+ end, '')
433
+ val = $1.to_i
434
+ e.cwyear = val
435
+ when 'g'
436
+ return unless str.sub!(/\A(\d{1,2})/, '')
437
+ val = $1.to_i
438
+ return unless (0..99) === val
439
+ e.cwyear = val
440
+ e._cent ||= if val >= 69 then 19 else 20 end
441
+ when 'H', 'k', 'OH'
442
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
443
+ val = $1.to_i
444
+ return unless (0..24) === val
445
+ e.hour = val
446
+ when 'I', 'l', 'OI'
447
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
448
+ val = $1.to_i
449
+ return unless (1..12) === val
450
+ e.hour = val
451
+ when 'j'
452
+ return unless str.sub!(/\A(\d{1,3})/, '')
453
+ val = $1.to_i
454
+ return unless (1..366) === val
455
+ e.yday = val
456
+ when 'L'
457
+ return unless str.sub!(if num_pattern?($')
458
+ then /\A([-+]?\d{1,3})/
459
+ else /\A([-+]?\d{1,})/
460
+ end, '')
461
+ # val = Rational($1.to_i, 10**3)
462
+ val = Rational($1.to_i, 10**$1.size)
463
+ e.sec_fraction = val
464
+ when 'M', 'OM'
465
+ return unless str.sub!(/\A(\d{1,2})/, '')
466
+ val = $1.to_i
467
+ return unless (0..59) === val
468
+ e.min = val
469
+ when 'm', 'Om'
470
+ return unless str.sub!(/\A(\d{1,2})/, '')
471
+ val = $1.to_i
472
+ return unless (1..12) === val
473
+ e.mon = val
474
+ when 'N'
475
+ return unless str.sub!(if num_pattern?($')
476
+ then /\A([-+]?\d{1,9})/
477
+ else /\A([-+]?\d{1,})/
478
+ end, '')
479
+ # val = Rational($1.to_i, 10**9)
480
+ val = Rational($1.to_i, 10**$1.size)
481
+ e.sec_fraction = val
482
+ when 'n', 't'
483
+ return unless _strptime_i(str, "\s", e)
484
+ when 'P', 'p'
485
+ return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
486
+ e._merid = if $1.downcase == 'a' then 0 else 12 end
487
+ when 'Q'
488
+ return unless str.sub!(/\A(-?\d{1,})/, '')
489
+ val = Rational($1.to_i, 10**3)
490
+ e.seconds = val
491
+ when 'R'
492
+ return unless _strptime_i(str, '%H:%M', e)
493
+ when 'r'
494
+ return unless _strptime_i(str, '%I:%M:%S %p', e)
495
+ when 'S', 'OS'
496
+ return unless str.sub!(/\A(\d{1,2})/, '')
497
+ val = $1.to_i
498
+ return unless (0..60) === val
499
+ e.sec = val
500
+ when 's'
501
+ return unless str.sub!(/\A(-?\d{1,})/, '')
502
+ val = $1.to_i
503
+ e.seconds = val
504
+ when 'T'
505
+ return unless _strptime_i(str, '%H:%M:%S', e)
506
+ when 'U', 'W', 'OU', 'OW'
507
+ return unless str.sub!(/\A(\d{1,2})/, '')
508
+ val = $1.to_i
509
+ return unless (0..53) === val
510
+ e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val)
511
+ when 'u', 'Ou'
512
+ return unless str.sub!(/\A(\d{1})/, '')
513
+ val = $1.to_i
514
+ return unless (1..7) === val
515
+ e.cwday = val
516
+ when 'V', 'OV'
517
+ return unless str.sub!(/\A(\d{1,2})/, '')
518
+ val = $1.to_i
519
+ return unless (1..53) === val
520
+ e.cweek = val
521
+ when 'v'
522
+ return unless _strptime_i(str, '%e-%b-%Y', e)
523
+ when 'w'
524
+ return unless str.sub!(/\A(\d{1})/, '')
525
+ val = $1.to_i
526
+ return unless (0..6) === val
527
+ e.wday = val
528
+ when 'X', 'EX'
529
+ return unless _strptime_i(str, '%H:%M:%S', e)
530
+ when 'x', 'Ex'
531
+ return unless _strptime_i(str, '%m/%d/%y', e)
532
+ when 'Y', 'EY'
533
+ return unless str.sub!(if num_pattern?($')
534
+ then /\A([-+]?\d{1,4})/
535
+ else /\A([-+]?\d{1,})/
536
+ end, '')
537
+ val = $1.to_i
538
+ e.year = val
539
+ when 'y', 'Ey', 'Oy'
540
+ return unless str.sub!(/\A(\d{1,2})/, '')
541
+ val = $1.to_i
542
+ return unless (0..99) === val
543
+ e.year = val
544
+ e._cent ||= if val >= 69 then 19 else 20 end
545
+ when 'Z', /\A:{0,3}z/
546
+ return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
547
+ |[[:alpha:].\s]+(?:standard|daylight)\s+time\b
548
+ |[[:alpha:]]+(?:\s+dst)?\b
549
+ )/ix, '')
550
+ val = $1
551
+ e.zone = val
552
+ offset = zone_to_diff(val)
553
+ e.offset = offset
554
+ when '%'
555
+ return unless str.sub!(/\A%/, '')
556
+ when '+'
557
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
558
+ else
559
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
560
+ end
561
+ else
562
+ case c
563
+ when /\A[\s\v]/
564
+ str.sub!(/\A[\s\v]+/, '')
565
+ else
566
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
567
+ end
568
+ end
569
+ end
570
+ end
571
+
572
+ private_class_method :_strptime_i
573
+
574
+ def self._strptime(str, fmt='%F')
575
+ str = str.dup
576
+ e = Format::Bag.new
577
+ return unless _strptime_i(str, fmt, e)
578
+
579
+ if e._cent
580
+ if e.cwyear
581
+ e.cwyear += e._cent * 100
582
+ end
583
+ if e.year
584
+ e. year += e._cent * 100
585
+ end
586
+ end
587
+
588
+ if e._merid
589
+ if e.hour
590
+ e.hour %= 12
591
+ e.hour += e._merid
592
+ end
593
+ end
594
+
595
+ unless str.empty?
596
+ e.leftover = str
597
+ end
598
+
599
+ e.to_hash
600
+ end
601
+
602
+ def self.s3e(e, y, m, d, bc=false)
603
+ unless String === m
604
+ m = m.to_s
605
+ end
606
+
607
+ if y && m && !d
608
+ y, m, d = d, y, m
609
+ end
610
+
611
+ if y == nil
612
+ if d && d.size > 2
613
+ y = d
614
+ d = nil
615
+ end
616
+ if d && d[0,1] == "'"
617
+ y = d
618
+ d = nil
619
+ end
620
+ end
621
+
622
+ if y
623
+ y.scan(/(\d+)(.+)?/)
624
+ if $2
625
+ y, d = d, $1
626
+ end
627
+ end
628
+
629
+ if m
630
+ if m[0,1] == "'" || m.size > 2
631
+ y, m, d = m, d, y # us -> be
632
+ end
633
+ end
634
+
635
+ if d
636
+ if d[0,1] == "'" || d.size > 2
637
+ y, d = d, y
638
+ end
639
+ end
640
+
641
+ if y
642
+ y =~ /([-+])?(\d+)/
643
+ if $1 || $2.size > 2
644
+ c = false
645
+ end
646
+ iy = $&.to_i
647
+ if bc
648
+ iy = -iy + 1
649
+ end
650
+ e.year = iy
651
+ end
652
+
653
+ if m
654
+ m =~ /\d+/
655
+ e.mon = $&.to_i
656
+ end
657
+
658
+ if d
659
+ d =~ /\d+/
660
+ e.mday = $&.to_i
661
+ end
662
+
663
+ if c != nil
664
+ e._comp = c
665
+ end
666
+
667
+ end
668
+
669
+ private_class_method :s3e
670
+
671
+ def self._parse_day(str, e) # :nodoc:
672
+ if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
673
+ e.wday = Format::ABBR_DAYS[$1.downcase]
674
+ true
675
+ =begin
676
+ elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
677
+ e.wday = %w(su mo tu we th fr sa).index($1.downcase)
678
+ true
679
+ =end
680
+ end
681
+ end
682
+
683
+ def self._parse_time(str, e) # :nodoc:
684
+ if str.sub!(
685
+ /(
686
+ (?:
687
+ \d+\s*:\s*\d+
688
+ (?:
689
+ \s*:\s*\d+(?:[,.]\d*)?
690
+ )?
691
+ |
692
+ \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
693
+ )
694
+ (?:
695
+ \s*
696
+ [ap](?:m\b|\.m\.)
697
+ )?
698
+ |
699
+ \d+\s*[ap](?:m\b|\.m\.)
700
+ )
701
+ (?:
702
+ \s*
703
+ (
704
+ (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
705
+ |
706
+ [[:alpha:].\s]+(?:standard|daylight)\stime\b
707
+ |
708
+ [[:alpha:]]+(?:\sdst)?\b
709
+ )
710
+ )?
711
+ /inx,
712
+ ' ')
713
+
714
+ t = $1
715
+ e.zone = $2 if $2
716
+
717
+ t =~ /\A(\d+)h?
718
+ (?:\s*:?\s*(\d+)m?
719
+ (?:
720
+ \s*:?\s*(\d+)(?:[,.](\d+))?s?
721
+ )?
722
+ )?
723
+ (?:\s*([ap])(?:m\b|\.m\.))?/inx
724
+
725
+ e.hour = $1.to_i
726
+ e.min = $2.to_i if $2
727
+ e.sec = $3.to_i if $3
728
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
729
+
730
+ if $5
731
+ e.hour %= 12
732
+ if $5.downcase == 'p'
733
+ e.hour += 12
734
+ end
735
+ end
736
+ true
737
+ end
738
+ end
739
+
740
+ =begin
741
+ def self._parse_beat(str, e) # :nodoc:
742
+ if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
743
+ beat = Rational($1.to_i)
744
+ beat += Rational($2.to_i, 10**$2.size) if $2
745
+ secs = Rational(beat, 1000)
746
+ h, min, s, fr = self.day_fraction_to_time(secs)
747
+ e.hour = h
748
+ e.min = min
749
+ e.sec = s
750
+ e.sec_fraction = fr * 86400
751
+ e.zone = '+01:00'
752
+ true
753
+ end
754
+ end
755
+ =end
756
+
757
+ def self._parse_eu(str, e) # :nodoc:
758
+ if str.sub!(
759
+ /'?(\d+)[^-\d\s]*
760
+ \s*
761
+ (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
762
+ (?:
763
+ \s*
764
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
765
+ \s*
766
+ ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
767
+ )?
768
+ /inox,
769
+ ' ') # '
770
+ s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
771
+ $3 && $3[0,1].downcase == 'b')
772
+ true
773
+ end
774
+ end
775
+
776
+ def self._parse_us(str, e) # :nodoc:
777
+ if str.sub!(
778
+ /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
779
+ \s*
780
+ ('?\d+)[^-\d\s']*
781
+ (?:
782
+ \s*
783
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
784
+ \s*
785
+ ('?-?\d+)
786
+ )?
787
+ /inox,
788
+ ' ') # '
789
+ s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
790
+ $3 && $3[0,1].downcase == 'b')
791
+ true
792
+ end
793
+ end
794
+
795
+ def self._parse_iso(str, e) # :nodoc:
796
+ if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
797
+ s3e(e, $1, $2, $3)
798
+ true
799
+ end
800
+ end
801
+
802
+ def self._parse_iso2(str, e) # :nodoc:
803
+ if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/in, ' ')
804
+ e.cwyear = $1.to_i if $1
805
+ e.cweek = $2.to_i
806
+ e.cwday = $3.to_i if $3
807
+ true
808
+ elsif str.sub!(/-w-(\d)\b/in, ' ')
809
+ e.cwday = $1.to_i
810
+ true
811
+ elsif str.sub!(/--(\d{2})?-(\d{2})\b/n, ' ')
812
+ e.mon = $1.to_i if $1
813
+ e.mday = $2.to_i
814
+ true
815
+ elsif str.sub!(/--(\d{2})(\d{2})?\b/n, ' ')
816
+ e.mon = $1.to_i
817
+ e.mday = $2.to_i if $2
818
+ true
819
+ elsif /[,.](\d{2}|\d{4})-\d{3}\b/n !~ str &&
820
+ str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/n, ' ')
821
+ e.year = $1.to_i
822
+ e.yday = $2.to_i
823
+ true
824
+ elsif /\d-\d{3}\b/n !~ str &&
825
+ str.sub!(/\b-(\d{3})\b/n, ' ')
826
+ e.yday = $1.to_i
827
+ true
828
+ end
829
+ end
830
+
831
+ def self._parse_jis(str, e) # :nodoc:
832
+ if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/in, ' ')
833
+ era = { 'm'=>1867,
834
+ 't'=>1911,
835
+ 's'=>1925,
836
+ 'h'=>1988
837
+ }[$1.downcase]
838
+ e.year = $2.to_i + era
839
+ e.mon = $3.to_i
840
+ e.mday = $4.to_i
841
+ true
842
+ end
843
+ end
844
+
845
+ def self._parse_vms(str, e) # :nodoc:
846
+ if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
847
+ -('?-?\d+)/inox, ' ')
848
+ s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
849
+ true
850
+ elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
851
+ -('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
852
+ s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
853
+ true
854
+ end
855
+ end
856
+
857
+ def self._parse_sla(str, e) # :nodoc:
858
+ if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|n, ' ') # '
859
+ s3e(e, $1, $2, $3)
860
+ true
861
+ end
862
+ end
863
+
864
+ def self._parse_dot(str, e) # :nodoc:
865
+ if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|n, ' ') # '
866
+ s3e(e, $1, $2, $3)
867
+ true
868
+ end
869
+ end
870
+
871
+ def self._parse_year(str, e) # :nodoc:
872
+ if str.sub!(/'(\d+)\b/n, ' ')
873
+ e.year = $1.to_i
874
+ true
875
+ end
876
+ end
877
+
878
+ def self._parse_mon(str, e) # :nodoc:
879
+ if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
880
+ e.mon = Format::ABBR_MONTHS[$1.downcase]
881
+ true
882
+ end
883
+ end
884
+
885
+ def self._parse_mday(str, e) # :nodoc:
886
+ if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
887
+ e.mday = $1.to_i
888
+ true
889
+ end
890
+ end
891
+
892
+ def self._parse_ddd(str, e) # :nodoc:
893
+ if str.sub!(
894
+ /([-+]?)(\d{2,14})
895
+ (?:
896
+ \s*
897
+ t?
898
+ \s*
899
+ (\d{2,6})?(?:[,.](\d*))?
900
+ )?
901
+ (?:
902
+ \s*
903
+ (
904
+ z\b
905
+ |
906
+ [-+]\d{1,4}\b
907
+ |
908
+ \[[-+]?\d[^\]]*\]
909
+ )
910
+ )?
911
+ /inx,
912
+ ' ')
913
+ case $2.size
914
+ when 2
915
+ if $3.nil? && $4
916
+ e.sec = $2[-2, 2].to_i
917
+ else
918
+ e.mday = $2[ 0, 2].to_i
919
+ end
920
+ when 4
921
+ if $3.nil? && $4
922
+ e.sec = $2[-2, 2].to_i
923
+ e.min = $2[-4, 2].to_i
924
+ else
925
+ e.mon = $2[ 0, 2].to_i
926
+ e.mday = $2[ 2, 2].to_i
927
+ end
928
+ when 6
929
+ if $3.nil? && $4
930
+ e.sec = $2[-2, 2].to_i
931
+ e.min = $2[-4, 2].to_i
932
+ e.hour = $2[-6, 2].to_i
933
+ else
934
+ e.year = ($1 + $2[ 0, 2]).to_i
935
+ e.mon = $2[ 2, 2].to_i
936
+ e.mday = $2[ 4, 2].to_i
937
+ end
938
+ when 8, 10, 12, 14
939
+ if $3.nil? && $4
940
+ e.sec = $2[-2, 2].to_i
941
+ e.min = $2[-4, 2].to_i
942
+ e.hour = $2[-6, 2].to_i
943
+ e.mday = $2[-8, 2].to_i
944
+ if $2.size >= 10
945
+ e.mon = $2[-10, 2].to_i
946
+ end
947
+ if $2.size == 12
948
+ e.year = ($1 + $2[-12, 2]).to_i
949
+ end
950
+ if $2.size == 14
951
+ e.year = ($1 + $2[-14, 4]).to_i
952
+ e._comp = false
953
+ end
954
+ else
955
+ e.year = ($1 + $2[ 0, 4]).to_i
956
+ e.mon = $2[ 4, 2].to_i
957
+ e.mday = $2[ 6, 2].to_i
958
+ e.hour = $2[ 8, 2].to_i if $2.size >= 10
959
+ e.min = $2[10, 2].to_i if $2.size >= 12
960
+ e.sec = $2[12, 2].to_i if $2.size >= 14
961
+ e._comp = false
962
+ end
963
+ when 3
964
+ if $3.nil? && $4
965
+ e.sec = $2[-2, 2].to_i
966
+ e.min = $2[-3, 1].to_i
967
+ else
968
+ e.yday = $2[ 0, 3].to_i
969
+ end
970
+ when 5
971
+ if $3.nil? && $4
972
+ e.sec = $2[-2, 2].to_i
973
+ e.min = $2[-4, 2].to_i
974
+ e.hour = $2[-5, 1].to_i
975
+ else
976
+ e.year = ($1 + $2[ 0, 2]).to_i
977
+ e.yday = $2[ 2, 3].to_i
978
+ end
979
+ when 7
980
+ if $3.nil? && $4
981
+ e.sec = $2[-2, 2].to_i
982
+ e.min = $2[-4, 2].to_i
983
+ e.hour = $2[-6, 2].to_i
984
+ e.mday = $2[-7, 1].to_i
985
+ else
986
+ e.year = ($1 + $2[ 0, 4]).to_i
987
+ e.yday = $2[ 4, 3].to_i
988
+ end
989
+ end
990
+ if $3
991
+ if $4
992
+ case $3.size
993
+ when 2, 4, 6
994
+ e.sec = $3[-2, 2].to_i
995
+ e.min = $3[-4, 2].to_i if $3.size >= 4
996
+ e.hour = $3[-6, 2].to_i if $3.size >= 6
997
+ end
998
+ else
999
+ case $3.size
1000
+ when 2, 4, 6
1001
+ e.hour = $3[ 0, 2].to_i
1002
+ e.min = $3[ 2, 2].to_i if $3.size >= 4
1003
+ e.sec = $3[ 4, 2].to_i if $3.size >= 6
1004
+ end
1005
+ end
1006
+ end
1007
+ if $4
1008
+ e.sec_fraction = Rational($4.to_i, 10**$4.size)
1009
+ end
1010
+ if $5
1011
+ e.zone = $5
1012
+ if e.zone[0,1] == '['
1013
+ o, n, = e.zone[1..-2].split(':')
1014
+ e.zone = n || o
1015
+ if /\A\d/ =~ o
1016
+ o = format('+%s', o)
1017
+ end
1018
+ e.offset = zone_to_diff(o)
1019
+ end
1020
+ end
1021
+ true
1022
+ end
1023
+ end
1024
+
1025
+ private_class_method :_parse_day, :_parse_time, # :_parse_beat,
1026
+ :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
1027
+ :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
1028
+ :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
1029
+
1030
+ def self._parse(str, comp=true)
1031
+ str = str.dup
1032
+
1033
+ e = Format::Bag.new
1034
+
1035
+ e._comp = comp
1036
+
1037
+ str.gsub!(/[^-+',.\/:@[:alnum:]\[\]\x80-\xff]+/n, ' ')
1038
+
1039
+ _parse_time(str, e) # || _parse_beat(str, e)
1040
+ _parse_day(str, e)
1041
+
1042
+ _parse_eu(str, e) ||
1043
+ _parse_us(str, e) ||
1044
+ _parse_iso(str, e) ||
1045
+ _parse_jis(str, e) ||
1046
+ _parse_vms(str, e) ||
1047
+ _parse_sla(str, e) ||
1048
+ _parse_dot(str, e) ||
1049
+ _parse_iso2(str, e) ||
1050
+ _parse_year(str, e) ||
1051
+ _parse_mon(str, e) ||
1052
+ _parse_mday(str, e) ||
1053
+ _parse_ddd(str, e)
1054
+
1055
+ if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
1056
+ if e.year
1057
+ e.year = -e.year + 1
1058
+ end
1059
+ end
1060
+
1061
+ if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
1062
+ if e.hour && !e.mday
1063
+ v = $1.to_i
1064
+ if (1..31) === v
1065
+ e.mday = v
1066
+ end
1067
+ end
1068
+ if e.mday && !e.hour
1069
+ v = $1.to_i
1070
+ if (0..24) === v
1071
+ e.hour = v
1072
+ end
1073
+ end
1074
+ end
1075
+
1076
+ if e._comp
1077
+ if e.cwyear
1078
+ if e.cwyear >= 0 && e.cwyear <= 99
1079
+ e.cwyear += if e.cwyear >= 69
1080
+ then 1900 else 2000 end
1081
+ end
1082
+ end
1083
+ if e.year
1084
+ if e.year >= 0 && e.year <= 99
1085
+ e.year += if e.year >= 69
1086
+ then 1900 else 2000 end
1087
+ end
1088
+ end
1089
+ end
1090
+
1091
+ e.offset ||= zone_to_diff(e.zone) if e.zone
1092
+
1093
+ e.to_hash
1094
+ end
1095
+
1096
+ def self._iso8601(str) # :nodoc:
1097
+ if /\A\s*(([-+]?\d{2,}|-)-\d{2}-\d{2}|
1098
+ ([-+]?\d{2,})?-\d{3}|
1099
+ (\d{2}|\d{4})?-w\d{2}-\d|
1100
+ -w-\d)
1101
+ (t
1102
+ \d{2}:\d{2}(:\d{2}([,.]\d+)?)?
1103
+ (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/inx =~ str
1104
+ _parse(str)
1105
+ elsif /\A\s*(([-+]?(\d{2}|\d{4})|--)\d{2}\d{2}|
1106
+ ([-+]?(\d{2}|\d{4}))?\d{3}|-\d{3}|
1107
+ (\d{2}|\d{4})?w\d{2}\d)
1108
+ (t?
1109
+ \d{2}\d{2}(\d{2}([,.]\d+)?)?
1110
+ (z|[-+]\d{2}(\d{2})?)?)?\s*\z/inx =~ str
1111
+ _parse(str)
1112
+ elsif /\A\s*(\d{2}:\d{2}(:\d{2}([,.]\d+)?)?
1113
+ (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/inx =~ str
1114
+ _parse(str)
1115
+ elsif /\A\s*(\d{2}\d{2}(\d{2}([,.]\d+)?)?
1116
+ (z|[-+]\d{2}(\d{2})?)?)?\s*\z/inx =~ str
1117
+ _parse(str)
1118
+ end
1119
+ end
1120
+
1121
+ def self._rfc3339(str) # :nodoc:
1122
+ if /\A\s*-?\d{4}-\d{2}-\d{2} # allow minus, anyway
1123
+ (t|\s)
1124
+ \d{2}:\d{2}:\d{2}(\.\d+)?
1125
+ (z|[-+]\d{2}:\d{2})\s*\z/inx =~ str
1126
+ _parse(str)
1127
+ end
1128
+ end
1129
+
1130
+ def self._xmlschema(str) # :nodoc:
1131
+ if /\A\s*(-?\d{4,})(?:-(\d{2})(?:-(\d{2}))?)?
1132
+ (?:t
1133
+ (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
1134
+ (z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
1135
+ e = Format::Bag.new
1136
+ e.year = $1.to_i
1137
+ e.mon = $2.to_i if $2
1138
+ e.mday = $3.to_i if $3
1139
+ e.hour = $4.to_i if $4
1140
+ e.min = $5.to_i if $5
1141
+ e.sec = $6.to_i if $6
1142
+ e.sec_fraction = Rational($7.to_i, 10**$7.size) if $7
1143
+ if $8
1144
+ e.zone = $8
1145
+ e.offset = zone_to_diff($8)
1146
+ end
1147
+ e.to_hash
1148
+ elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
1149
+ (z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
1150
+ e = Format::Bag.new
1151
+ e.hour = $1.to_i if $1
1152
+ e.min = $2.to_i if $2
1153
+ e.sec = $3.to_i if $3
1154
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
1155
+ if $5
1156
+ e.zone = $5
1157
+ e.offset = zone_to_diff($5)
1158
+ end
1159
+ e.to_hash
1160
+ elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
1161
+ (z|[-+]\d{2}:\d{2})?\s*\z/inx =~ str
1162
+ e = Format::Bag.new
1163
+ e.mon = $1.to_i if $1
1164
+ e.mday = $2.to_i if $2
1165
+ e.mday = $3.to_i if $3
1166
+ if $4
1167
+ e.zone = $4
1168
+ e.offset = zone_to_diff($4)
1169
+ end
1170
+ e.to_hash
1171
+ end
1172
+ end
1173
+
1174
+ def self._rfc2822(str) # :nodoc:
1175
+ if /\A\s*(?:(?:#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+)?
1176
+ \d{1,2}\s+
1177
+ (?:#{Format::ABBR_MONTHS.keys.join('|')})\s+
1178
+ -?(\d{2,})\s+ # allow minus, anyway
1179
+ \d{2}:\d{2}(:\d{2})?\s*
1180
+ (?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/inox =~ str
1181
+ e = _parse(str, false)
1182
+ if $1.size < 4
1183
+ if e[:year] < 50
1184
+ e[:year] += 2000
1185
+ elsif e[:year] < 1000
1186
+ e[:year] += 1900
1187
+ end
1188
+ end
1189
+ e
1190
+ end
1191
+ end
1192
+
1193
+ class << self; alias_method :_rfc822, :_rfc2822 end
1194
+
1195
+ def self._httpdate(str) # :nodoc:
1196
+ if /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+
1197
+ \d{2}\s+
1198
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1199
+ -?\d{4}\s+ # allow minus, anyway
1200
+ \d{2}:\d{2}:\d{2}\s+
1201
+ gmt\s*\z/inox =~ str
1202
+ _rfc2822(str)
1203
+ elsif /\A\s*(#{Format::DAYS.keys.join('|')})\s*,\s+
1204
+ \d{2}\s*-\s*
1205
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s*-\s*
1206
+ \d{2}\s+
1207
+ \d{2}:\d{2}:\d{2}\s+
1208
+ gmt\s*\z/inox =~ str
1209
+ _parse(str)
1210
+ elsif /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s+
1211
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1212
+ \d{1,2}\s+
1213
+ \d{2}:\d{2}:\d{2}\s+
1214
+ \d{4}\s*\z/inox =~ str
1215
+ _parse(str)
1216
+ end
1217
+ end
1218
+
1219
+ def self._jisx0301(str) # :nodoc:
1220
+ if /\A\s*[mtsh]?\d{2}\.\d{2}\.\d{2}
1221
+ (t
1222
+ (\d{2}:\d{2}(:\d{2}([,.]\d*)?)?
1223
+ (z|[-+]\d{2}(:?\d{2})?)?)?)?\s*\z/inx =~ str
1224
+ if /\A\s*\d/ =~ str
1225
+ _parse(str.sub(/\A\s*(\d)/, 'h\1'))
1226
+ else
1227
+ _parse(str)
1228
+ end
1229
+ else
1230
+ _iso8601(str)
1231
+ end
1232
+ end
1233
+
1234
+ t = Module.new do
1235
+
1236
+ private
1237
+
1238
+ def zone_to_diff(zone) # :nodoc:
1239
+ zone = zone.downcase
1240
+ if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
1241
+ dst = $1 == 'daylight'
1242
+ else
1243
+ dst = zone.sub!(/\s+dst\z/, '')
1244
+ end
1245
+ if Format::ZONES.include?(zone)
1246
+ offset = Format::ZONES[zone]
1247
+ offset += 3600 if dst
1248
+ elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
1249
+ sign = $1
1250
+ if zone.include?(':')
1251
+ hour, min, sec, = zone.split(':')
1252
+ elsif zone.include?(',') || zone.include?('.')
1253
+ hour, fr, = zone.split(/[,.]/)
1254
+ min = Rational(fr.to_i, 10**fr.size) * 60
1255
+ else
1256
+ case zone.size
1257
+ when 3
1258
+ hour = zone[0,1]
1259
+ min = zone[1,2]
1260
+ else
1261
+ hour = zone[0,2]
1262
+ min = zone[2,2]
1263
+ sec = zone[4,2]
1264
+ end
1265
+ end
1266
+ offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
1267
+ offset *= -1 if sign == '-'
1268
+ end
1269
+ offset
1270
+ end
1271
+
1272
+ end
1273
+
1274
+ extend t
1275
+ include t
1276
+
1277
+ end
1278
+
1279
+ class DateTime < Date
1280
+
1281
+ def strftime(fmt='%FT%T%:z')
1282
+ super(fmt)
1283
+ end
1284
+
1285
+ def self._strptime(str, fmt='%FT%T%z')
1286
+ super(str, fmt)
1287
+ end
1288
+
1289
+ def iso8601_timediv(n) # :nodoc:
1290
+ strftime('T%T' +
1291
+ if n < 1
1292
+ ''
1293
+ else
1294
+ '.%0*d' % [n, (sec_fraction / Rational(1, 10**n)).round]
1295
+ end +
1296
+ '%:z')
1297
+ end
1298
+
1299
+ private :iso8601_timediv
1300
+
1301
+ def iso8601(n=0)
1302
+ super() + iso8601_timediv(n)
1303
+ end
1304
+
1305
+ def rfc3339(n=0) iso8601(n) end
1306
+
1307
+ def xmlschema(n=0) iso8601(n) end # :nodoc:
1308
+
1309
+ def jisx0301(n=0)
1310
+ super() + iso8601_timediv(n)
1311
+ end
1312
+
1313
+ end