duration 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/duration.rb +159 -2
  2. metadata +1 -1
@@ -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
- Duration.new(method => self)
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
@@ -3,7 +3,7 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: duration
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.3
6
+ version: 0.0.4
7
7
  date: 2006-05-24 00:00:00 +09:00
8
8
  summary: Duration is a package for manipulating time spans.
9
9
  require_paths: