duration 0.0.3 → 0.0.4
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.
- 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