duration 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/duration.rb +159 -2
- metadata +1 -1
data/lib/duration.rb
CHANGED
@@ -328,6 +328,104 @@ class Duration
|
|
328
328
|
alias to_i total
|
329
329
|
end
|
330
330
|
|
331
|
+
# BigDuration is a variant of Duration that supports years and months. Support
|
332
|
+
# for months is not accurate, as a month is assumed to be 30 days so use at your
|
333
|
+
# own risk.
|
334
|
+
#
|
335
|
+
class BigDuration < Duration
|
336
|
+
attr_reader :years, :months
|
337
|
+
|
338
|
+
YEAR = 60 * 60 * 24 * 30 * 12
|
339
|
+
MONTH = 60 * 60 * 24 * 30
|
340
|
+
|
341
|
+
# Similar to Duration.new except that BigDuration.new supports `:years' and
|
342
|
+
# `:months' and will also handle years and months correctly when breaking down
|
343
|
+
# the seconds.
|
344
|
+
#
|
345
|
+
def initialize(seconds_or_attr = 0)
|
346
|
+
if seconds_or_attr.kind_of? Hash
|
347
|
+
# Part->time map table.
|
348
|
+
h =\
|
349
|
+
{:years => YEAR ,
|
350
|
+
:months => MONTH ,
|
351
|
+
:weeks => WEEK ,
|
352
|
+
:days => DAY ,
|
353
|
+
:hours => HOUR ,
|
354
|
+
:minutes => MINUTE,
|
355
|
+
:seconds => SECOND}
|
356
|
+
|
357
|
+
# Loop through each valid part, ignore all others.
|
358
|
+
seconds = seconds_or_attr.inject(0) do |sec, args|
|
359
|
+
# Grab the part of the duration (week, day, whatever) and the number of seconds for it.
|
360
|
+
part, time = args
|
361
|
+
|
362
|
+
# Map each part to their number of seconds and the given value.
|
363
|
+
# {:weeks => 2} maps to h[:weeks] -- so... weeks = WEEK * 2
|
364
|
+
if h.key?(prt = part.to_s.to_sym) then sec + time * h[prt] else 0 end
|
365
|
+
end
|
366
|
+
else
|
367
|
+
seconds = seconds_or_attr
|
368
|
+
end
|
369
|
+
|
370
|
+
@total, array = seconds.to_f.round, []
|
371
|
+
@seconds = [YEAR, MONTH, WEEK, DAY, HOUR, MINUTE].inject(@total) do |left, part|
|
372
|
+
array << left / part; left % part
|
373
|
+
end
|
374
|
+
|
375
|
+
@years, @months, @weeks, @days, @hours, @minutes = array
|
376
|
+
end
|
377
|
+
|
378
|
+
# BigDuration variant of Duration#strftime.
|
379
|
+
#
|
380
|
+
# *Identifiers: BigDuration*
|
381
|
+
#
|
382
|
+
# %y -- Number of years
|
383
|
+
# %m -- Number of months
|
384
|
+
#
|
385
|
+
def strftime(fmt)
|
386
|
+
h = {'y' => @years, 'M' => @months}
|
387
|
+
super(fmt.gsub(/%?%(y|M)/) { |match| match.size == 3 ? match : h[match[1..1]] })
|
388
|
+
end
|
389
|
+
|
390
|
+
# Similar to Duration#each except includes years and months in the interation.
|
391
|
+
#
|
392
|
+
def each
|
393
|
+
[['years' , @years ],
|
394
|
+
['months' , @months ],
|
395
|
+
['weeks' , @weeks ],
|
396
|
+
['days' , @days ],
|
397
|
+
['hours' , @hours ],
|
398
|
+
['minutes' , @minutes],
|
399
|
+
['seconds' , @seconds]].each do |part, time|
|
400
|
+
# Yield to block
|
401
|
+
yield part, time
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# Derived from Duration#seconds, but supports `:years' and `:months' as well.
|
406
|
+
#
|
407
|
+
def seconds(part = nil)
|
408
|
+
h = {:years => YEAR, :months => MONTH}
|
409
|
+
if [:years, :months].include? part
|
410
|
+
__send__(part) * h[part]
|
411
|
+
else
|
412
|
+
super(part)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Set the number of years in the BigDuration.
|
417
|
+
#
|
418
|
+
def years=(n)
|
419
|
+
initialize(:years => n, :seconds => @total - seconds(:years))
|
420
|
+
end
|
421
|
+
|
422
|
+
# Set the number of months in the BigDuration.
|
423
|
+
#
|
424
|
+
def months=(n)
|
425
|
+
initialize(:months => n, :seconds => @total - seconds(:months))
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
331
429
|
# The following important additions are made to Numeric:
|
332
430
|
#
|
333
431
|
# Numeric#weeks -- Create a Duration object with given weeks
|
@@ -336,12 +434,49 @@ end
|
|
336
434
|
# Numeric#minutes -- Create a Duration object with given minutes
|
337
435
|
# Numeric#seconds -- Create a Duration object with given seconds
|
338
436
|
#
|
437
|
+
# BigDuration support:
|
438
|
+
#
|
439
|
+
# Numeric#years -- Create a BigDuration object with given years
|
440
|
+
# Numeric#months -- Create a BigDuration object with given months
|
441
|
+
#
|
442
|
+
# BigDuration objects can be created from regular weeks, days, hours, etc by
|
443
|
+
# providing `:big' as an argument to the above Numeric methods.
|
444
|
+
#
|
339
445
|
class Numeric
|
340
446
|
alias __numeric_old_method_missing method_missing
|
341
447
|
|
448
|
+
# Create a Duration object using self where self could represent weeks, days,
|
449
|
+
# hours, minutes, and seconds.
|
450
|
+
#
|
451
|
+
# *Example*
|
452
|
+
#
|
453
|
+
# 10.duration(:weeks)
|
454
|
+
# => #<Duration: 10 weeks>
|
455
|
+
# 10.duration
|
456
|
+
# => #<Duration: 10 seconds>
|
457
|
+
#
|
458
|
+
def duration(part = nil, klass = Duration)
|
459
|
+
if [:years, :months, :weeks, :days, :hours, :minutes, :seconds].include? part
|
460
|
+
klass.new(part => self)
|
461
|
+
else
|
462
|
+
klass.new(self)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
342
466
|
# Intercept calls to .weeks, .days, .hours, .minutes and .seconds because
|
343
467
|
# Rails defines its own methods, so I'd like to prevent any redefining of
|
344
|
-
# Rails' methods.
|
468
|
+
# Rails' methods. If these methods don't get captured, then alternatively
|
469
|
+
# Numeric#duration can be used.
|
470
|
+
#
|
471
|
+
# BigDuration methods include .years and .months, also BigDuration objects
|
472
|
+
# can be created from any time such as weeks or minutes and even seconds.
|
473
|
+
#
|
474
|
+
# *Example: BigDuration*
|
475
|
+
#
|
476
|
+
# 5.years
|
477
|
+
# => #<BigDuration: 5 years>
|
478
|
+
# 10.minutes(:big)
|
479
|
+
# => #<BigDuration: 10 minutes>
|
345
480
|
#
|
346
481
|
# *Example*
|
347
482
|
#
|
@@ -350,9 +485,31 @@ class Numeric
|
|
350
485
|
#
|
351
486
|
def method_missing(method, *args)
|
352
487
|
if [:weeks, :days, :hours, :minutes, :seconds].include? method
|
353
|
-
|
488
|
+
if args.size > 0 && args[0] == :big
|
489
|
+
duration(method, BigDuration)
|
490
|
+
else
|
491
|
+
duration(method)
|
492
|
+
end
|
493
|
+
elsif [:years, :months].include? method
|
494
|
+
duration(method, BigDuration)
|
354
495
|
else
|
355
496
|
__numeric_old_method_missing(method, *args)
|
356
497
|
end
|
357
498
|
end
|
499
|
+
end
|
500
|
+
|
501
|
+
# Time#duration has been added to convert the UNIX timestamp into a Duration.
|
502
|
+
# See Time#duration for an example.
|
503
|
+
#
|
504
|
+
class Time
|
505
|
+
# Create a Duration object from the UNIX timestamp.
|
506
|
+
#
|
507
|
+
# *Example*
|
508
|
+
#
|
509
|
+
# Time.now.duration
|
510
|
+
# => #<Duration: 1898 weeks, 6 days, 1 hour, 12 minutes and 1 second>
|
511
|
+
#
|
512
|
+
def duration(type = nil)
|
513
|
+
if type == :big then BigDuration.new(to_i) else Duration.new(to_i) end
|
514
|
+
end
|
358
515
|
end
|
metadata
CHANGED