rhodes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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