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.
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: