duration 0.0.2 → 0.0.3

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 +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