duration 0.0.2 → 0.0.3

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 +170 -51
  2. metadata +2 -2
@@ -27,7 +27,10 @@
27
27
  # => "2 w, 0 d, 0 h, 2 m, 30 s"
28
28
  #
29
29
  class Duration
30
- attr_reader :total, :weeks, :days, :hours, :minutes, :seconds
30
+ include Comparable
31
+ include Enumerable
32
+
33
+ attr_reader :total, :weeks, :days, :hours, :minutes
31
34
 
32
35
  WEEK = 60 * 60 * 24 * 7
33
36
  DAY = 60 * 60 * 24
@@ -41,18 +44,23 @@ class Duration
41
44
  #
42
45
  # d = Duration.new(60 * 60 * 24 * 10 + 120 + 30)
43
46
  # => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
44
- #
45
47
  # d = Duration.new(:weeks => 1, :days => 3, :minutes => 2, :seconds => 30)
46
48
  # => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
47
49
  #
48
- def initialize(seconds_or_attr)
49
- if (h = seconds_or_attr).kind_of? Hash
50
- seconds = 0
51
- seconds += h[:weeks] * WEEK if h.key? :weeks
52
- seconds += h[:days] * DAY if h.key? :days
53
- seconds += h[:hours] * HOUR if h.key? :hours
54
- seconds += h[:minutes] * MINUTE if h.key? :minutes
55
- seconds += h[:seconds] * SECOND if h.key? :seconds
50
+ def initialize(seconds_or_attr = 0)
51
+ if seconds_or_attr.kind_of? Hash
52
+ # Part->time map table.
53
+ h = {:weeks => WEEK, :days => DAY, :hours => HOUR, :minutes => MINUTE, :seconds => SECOND}
54
+
55
+ # Loop through each valid part, ignore all others.
56
+ seconds = seconds_or_attr.inject(0) do |sec, args|
57
+ # Grab the part of the duration (week, day, whatever) and the number of seconds for it.
58
+ part, time = args
59
+
60
+ # Map each part to their number of seconds and the given value.
61
+ # {:weeks => 2} maps to h[:weeks] -- so... weeks = WEEK * 2
62
+ if h.key?(prt = part.to_s.to_sym) then sec + time * h[prt] else 0 end
63
+ end
56
64
  else
57
65
  seconds = seconds_or_attr
58
66
  end
@@ -69,12 +77,14 @@ class Duration
69
77
  #
70
78
  # *Identifiers*
71
79
  #
72
- # %w - Number of weeks
73
- # %d - Number of days
74
- # %h - Number of hours
75
- # %m - Number of minutes
76
- # %s - Number of seconds
77
- # %% - Literal `%' character
80
+ # %w -- Number of weeks
81
+ # %d -- Number of days
82
+ # %h -- Number of hours
83
+ # %m -- Number of minutes
84
+ # %s -- Number of seconds
85
+ # %t -- Total number of seconds
86
+ # %x -- Duration#to_s
87
+ # %% -- Literal `%' character
78
88
  #
79
89
  # *Example*
80
90
  #
@@ -89,36 +99,146 @@ class Duration
89
99
  'd' => @days ,
90
100
  'h' => @hours ,
91
101
  'm' => @minutes,
92
- 's' => @seconds}
102
+ 's' => @seconds,
103
+ 't' => @total ,
104
+ 'x' => to_s}
93
105
 
94
- fmt.gsub(/%?%(w|d|h|m|s)/) do |match|
106
+ fmt.gsub(/%?%(w|d|h|m|s|t|x)/) do |match|
95
107
  match.size == 3 ? match : h[match[1..1]]
96
108
  end.gsub('%%', '%')
97
109
  end
98
110
 
99
- # Intercept certain attribute writers. Intercepts `weeks=', `days=', `hours=',
100
- # `minutes=', `seconds=', and `total='
111
+ # Get the number of seconds of a given part, or simply just get the number of
112
+ # seconds.
101
113
  #
102
114
  # *Example*
103
115
  #
104
- # d = Duration.new(:days => 6)
105
- # => #<Duration: 6 days>
106
- # d.days += 1; d
107
- # => #<Duration: 1 week>
108
- #
109
- def method_missing(method, *args)
110
- case method
111
- when :weeks= then initialize(WEEK * args[0] + (@total - WEEK * @weeks ))
112
- when :days= then initialize(DAY * args[0] + (@total - DAY * @days ))
113
- when :hours= then initialize(HOUR * args[0] + (@total - HOUR * @hours ))
114
- when :minutes= then initialize(MINUTE * args[0] + (@total - MINUTE * @minutes))
115
- when :seconds= then initialize(SECOND * args[0] + (@total - SECOND * @seconds))
116
- when :total= then initialize(args[0])
116
+ # d = Duration.new(:weeks => 1, :days => 1, :hours => 1, :seconds => 30)
117
+ # => #<Duration: 1 week, 1 day, 1 hour and 30 seconds>
118
+ # d.seconds(:weeks)
119
+ # => 604800
120
+ # d.seconds(:days)
121
+ # => 86400
122
+ # d.seconds(:hours)
123
+ # => 3600
124
+ # d.seconds
125
+ # => 30
126
+ #
127
+ def seconds(part = nil)
128
+ # Table mapping
129
+ h = {:weeks => WEEK, :days => DAY, :hours => HOUR, :minutes => MINUTE}
130
+
131
+ if [:weeks, :days, :hours, :minutes].include? part
132
+ __send__(part) * h[part]
117
133
  else
118
- raise NoMethodError, "undefined method `#{method}' for #{inspect}"
134
+ @seconds
119
135
  end
120
136
  end
121
137
 
138
+ # For iterating through the duration set of weeks, days, hours, minutes, and
139
+ # seconds.
140
+ #
141
+ # *Example*
142
+ #
143
+ # Duration.new(:weeks => 1, :seconds => 30).each do |part, time|
144
+ # puts "part: #{part}, time: #{time}"
145
+ # end
146
+ #
147
+ # _Output_
148
+ #
149
+ # part: weeks, time: 1
150
+ # part: days, time: 0
151
+ # part: hours, time: 0
152
+ # part: minutes, time: 0
153
+ # part: seconds, time: 30
154
+ #
155
+ def each
156
+ [['weeks' , @weeks ],
157
+ ['days' , @days ],
158
+ ['hours' , @hours ],
159
+ ['minutes' , @minutes],
160
+ ['seconds' , @seconds]].each do |part, time|
161
+ # Yield to block
162
+ yield part, time
163
+ end
164
+ end
165
+
166
+ # Calls `<=>' on Duration#total.
167
+ #
168
+ # *Example*
169
+ #
170
+ # 5.days == 24.hours * 5
171
+ # => true
172
+ #
173
+ def <=>(other)
174
+ @total <=> other.to_i
175
+ end
176
+
177
+ # Set the number of weeks.
178
+ #
179
+ # *Example*
180
+ #
181
+ # d = Duration.new(0)
182
+ # => #<Duration: ...>
183
+ # d.weeks = 2; d
184
+ # => #<Duration: 2 weeks>
185
+ #
186
+ def weeks=(n)
187
+ initialize(:weeks => n, :seconds => @total - seconds(:weeks))
188
+ end
189
+
190
+ # Set the number of days.
191
+ #
192
+ # *Example*
193
+ #
194
+ # d = Duration.new(0)
195
+ # => #<Duration: ...>
196
+ # d.days = 5; d
197
+ # => #<Duration: 5 days>
198
+ #
199
+ def days=(n)
200
+ initialize(:days => n, :seconds => @total - seconds(:days))
201
+ end
202
+
203
+ # Set the number of hours.
204
+ #
205
+ # *Example*
206
+ #
207
+ # d = Duration.new(0)
208
+ # => #<Duration: ...>
209
+ # d.hours = 5; d
210
+ # => #<Duration: 5 hours>
211
+ #
212
+ def hours=(n)
213
+ initialize(:hours => n, :seconds => @total - seconds(:hours))
214
+ end
215
+
216
+ # Set the number of minutes.
217
+ #
218
+ # *Example*
219
+ #
220
+ # d = Duration.new(0)
221
+ # => #<Duration: ...>
222
+ # d.minutes = 30; d
223
+ # => #<Duration: 30 minutes>
224
+ #
225
+ def minutes=(n)
226
+ initialize(:minutes => n, :seconds => @total - seconds(:minutes))
227
+ end
228
+
229
+ # Set the number of minutes.
230
+ #
231
+ # *Example*
232
+ #
233
+ # d = Duration.new(0)
234
+ # => #<Duration: ...>
235
+ # d.seconds = 30; d
236
+ # => #<Duration: 30 seconds>
237
+ #
238
+ def seconds=(n)
239
+ initialize(:seconds => (@total + n) - @seconds)
240
+ end
241
+
122
242
  # Friendly, human-readable string representation of the duration.
123
243
  #
124
244
  # *Example*
@@ -131,12 +251,7 @@ class Duration
131
251
  def to_s
132
252
  str = ''
133
253
 
134
- [['weeks' , @weeks ],
135
- ['days' , @days ],
136
- ['hours' , @hours ],
137
- ['minutes' , @minutes],
138
- ['seconds' , @seconds]].each do |part, time|
139
-
254
+ each do |part, time|
140
255
  # Skip any zero times.
141
256
  next if time.zero?
142
257
 
@@ -213,12 +328,20 @@ class Duration
213
328
  alias to_i total
214
329
  end
215
330
 
331
+ # The following important additions are made to Numeric:
332
+ #
333
+ # Numeric#weeks -- Create a Duration object with given weeks
334
+ # Numeric#days -- Create a Duration object with given days
335
+ # Numeric#hours -- Create a Duration object with given hours
336
+ # Numeric#minutes -- Create a Duration object with given minutes
337
+ # Numeric#seconds -- Create a Duration object with given seconds
338
+ #
216
339
  class Numeric
217
- alias __Numeric_method_missing method_missing
340
+ alias __numeric_old_method_missing method_missing
218
341
 
219
- # Intercept calls to #weeks, #days, #hours, #minutes, #seconds because Rails
220
- # defines their own methods, so I'd like to prevent any redefining of Rails'
221
- # methods.
342
+ # Intercept calls to .weeks, .days, .hours, .minutes and .seconds because
343
+ # Rails defines its own methods, so I'd like to prevent any redefining of
344
+ # Rails' methods.
222
345
  #
223
346
  # *Example*
224
347
  #
@@ -226,14 +349,10 @@ class Numeric
226
349
  # => #<Duration: 2 minutes and 20 seconds>
227
350
  #
228
351
  def method_missing(method, *args)
229
- case method
230
- when :weeks then Duration.new(Duration::WEEK * self)
231
- when :days then Duration.new(Duration::DAY * self)
232
- when :hours then Duration.new(Duration::HOUR * self)
233
- when :minutes then Duration.new(Duration::MINUTE * self)
234
- when :seconds then Duration.new(Duration::SECOND * self)
352
+ if [:weeks, :days, :hours, :minutes, :seconds].include? method
353
+ Duration.new(method => self)
235
354
  else
236
- __Numeric_method_missing(method, *args)
355
+ __numeric_old_method_missing(method, *args)
237
356
  end
238
357
  end
239
358
  end
metadata CHANGED
@@ -3,8 +3,8 @@ 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.2
7
- date: 2006-05-23 00:00:00 +09:00
6
+ version: 0.0.3
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:
10
10
  - lib