duration 0.0.1

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 +214 -0
  2. metadata +45 -0
data/lib/duration.rb ADDED
@@ -0,0 +1,214 @@
1
+ # = Author
2
+ #
3
+ # Matthew Harris (mailto:shugotenshi@gmail.com)
4
+ #
5
+ # = Project
6
+ #
7
+ # http://www.rubyforge.org/projects/duration
8
+ #
9
+ # = Synopsis
10
+ #
11
+ # Duration is a simple class that provides ways of easily manipulating durations
12
+ # (timespans) and formatting them as well.
13
+ #
14
+ # = Usage
15
+ #
16
+ # require 'duration'
17
+ # => true
18
+ # d = Duration.new(60 * 60 * 24 * 10 + 120 + 30)
19
+ # => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
20
+ # d.to_s
21
+ # => "1 week, 3 days, 2 minutes and 30 seconds"
22
+ # [d.weeks, d.days]
23
+ # => [1, 3]
24
+ # d.days = 7; d
25
+ # => #<Duration: 2 weeks, 2 minutes and 30 seconds>
26
+ # d.strftime('%w w, %d d, %h h, %m m, %s s')
27
+ # => "2 w, 0 d, 0 h, 2 m, 30 s"
28
+ #
29
+ class Duration
30
+ attr_reader :total, :weeks, :days, :hours, :minutes, :seconds
31
+
32
+ WEEK = 60 * 60 * 24 * 7
33
+ DAY = 60 * 60 * 24
34
+ HOUR = 60 * 60
35
+ MINUTE = 60
36
+ SECOND = 1
37
+
38
+ # Initialize Duration class.
39
+ #
40
+ # *Example*
41
+ #
42
+ # d = Duration.new(60 * 60 * 24 * 10 + 120 + 30)
43
+ # => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
44
+ #
45
+ # d = Duration.new(:weeks => 1, :days => 3, :minutes => 2, :seconds => 30)
46
+ # => #<Duration: 1 week, 3 days, 2 minutes and 30 seconds>
47
+ #
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
56
+ else
57
+ seconds = seconds_or_attr
58
+ end
59
+
60
+ @total, array = seconds.to_f.round, []
61
+ @seconds = [WEEK, DAY, HOUR, MINUTE].inject(@total) do |left, part|
62
+ array << left / part; left % part
63
+ end
64
+
65
+ @weeks, @days, @hours, @minutes = array
66
+ end
67
+
68
+ # Format duration.
69
+ #
70
+ # *Identifiers*
71
+ #
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
78
+ #
79
+ # *Example*
80
+ #
81
+ # d = Duration.new(:weeks => 10, :days => 7)
82
+ # => #<Duration: 11 weeks>
83
+ # d.strftime("It's been %w weeks!")
84
+ # => "It's been 11 weeks!"
85
+ #
86
+ def strftime(fmt)
87
+ h =\
88
+ {'w' => @weeks ,
89
+ 'd' => @days ,
90
+ 'h' => @hours ,
91
+ 'm' => @minutes,
92
+ 's' => @seconds}
93
+
94
+ fmt.gsub(/%?%(w|d|h|m|s)/) do |match|
95
+ match.size == 3 ? match : h[match[1..1]]
96
+ end.gsub('%%', '%')
97
+ end
98
+
99
+ # Intercept certain attribute writers. Intercepts `weeks=', `days=', `hours=',
100
+ # `minutes=', `seconds=', and `total='
101
+ #
102
+ # *Example*
103
+ #
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])
117
+ else
118
+ raise NoMethodError, "undefined method `#{method}' for #{inspect}"
119
+ end
120
+ end
121
+
122
+ # Friendly, human-readable string representation of the duration.
123
+ #
124
+ # *Example*
125
+ #
126
+ # d = Duration.new(:seconds => 140)
127
+ # => #<Duration: 2 minutes and 20 seconds>
128
+ # d.to_s
129
+ # => "2 minutes and 20 seconds"
130
+ #
131
+ def to_s
132
+ str = ''
133
+
134
+ [['weeks' , @weeks ],
135
+ ['days' , @days ],
136
+ ['hours' , @hours ],
137
+ ['minutes' , @minutes],
138
+ ['seconds' , @seconds]].each do |part, time|
139
+
140
+ # Skip any zero times.
141
+ next if time.zero?
142
+
143
+ # Concatenate the part of the time and the time itself.
144
+ str << "#{time} #{time == 1 ? part[0..-2] : part}, "
145
+ end
146
+
147
+ str.chomp(', ').sub(/(.+), (.+)/, '\1 and \2')
148
+ end
149
+
150
+ # Inspection string--Similar to #to_s except that it has the class name.
151
+ #
152
+ # *Example*
153
+ #
154
+ # Duration.new(:seconds => 140)
155
+ # => #<Duration: 2 minutes and 20 seconds>
156
+ #
157
+ def inspect
158
+ "#<#{self.class}: #{(s = to_s).empty? ? '...' : s}>"
159
+ end
160
+
161
+ # Add to Duration.
162
+ #
163
+ # *Example*
164
+ #
165
+ # d = Duration.new(30)
166
+ # => #<Duration: 30 seconds>
167
+ # d + 30
168
+ # => #<Duration: 1 minute>
169
+ #
170
+ def +(other)
171
+ self.class.new(@total + other.to_i)
172
+ end
173
+
174
+ # Subtract from Duration.
175
+ #
176
+ # *Example*
177
+ #
178
+ # d = Duration.new(30)
179
+ # => #<Duration: 30 seconds>
180
+ # d - 15
181
+ # => #<Duration: 15 seconds>
182
+ #
183
+ def -(other)
184
+ self.class.new(@total - other.to_i)
185
+ end
186
+
187
+ # Multiply two Durations.
188
+ #
189
+ # *Example*
190
+ #
191
+ # d = Duration.new(30)
192
+ # => #<Duration: 30 seconds>
193
+ # d * 2
194
+ # => #<Duration: 1 minute>
195
+ #
196
+ def *(other)
197
+ self.class.new(@total * other.to_i)
198
+ end
199
+
200
+ # Divide two Durations.
201
+ #
202
+ # *Example*
203
+ #
204
+ # d = Duration.new(30)
205
+ # => #<Duration: 30 seconds>
206
+ # d / 2
207
+ # => #<Duration: 15 seconds>
208
+ #
209
+ def /(other)
210
+ self.class.new(@total / other.to_i)
211
+ end
212
+
213
+ alias to_i total
214
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: duration
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-05-23 00:00:00 +09:00
8
+ summary: Duration is a package for manipulating time spans.
9
+ require_paths:
10
+ - lib
11
+ email: shugotenshi@gmail.com
12
+ homepage: http://duration.rubyforge.org
13
+ rubyforge_project: duration
14
+ description: Duration is a simple class that provides ways of easily manipulating durations (timespans) and formatting them as well.
15
+ autorequire: duration
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Matthew Harris
30
+ files:
31
+ - lib/duration.rb
32
+ test_files: []
33
+
34
+ rdoc_options: []
35
+
36
+ extra_rdoc_files: []
37
+
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ requirements: []
43
+
44
+ dependencies: []
45
+