richunits 0.2.0 → 0.5.0
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.
- data/CHANGES +17 -1
- data/COPYING +22 -0
- data/MANIFEST +29 -13
- data/README +50 -1
- data/RELEASE +21 -0
- data/TODO +5 -0
- data/VERSION +1 -1
- data/doc/ads/rdoc.html +12 -0
- data/doc/images/ruby-md.png +0 -0
- data/doc/images/ruby-sm.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tiger-sm.png +0 -0
- data/doc/images/tiger_logo.png +0 -0
- data/doc/index.css +179 -0
- data/doc/index.html +163 -0
- data/lib/rich_units.rb +1 -4
- data/lib/richunits.rb +5 -0
- data/lib/richunits/bytes.rb +178 -0
- data/lib/richunits/duration.rb +290 -0
- data/lib/richunits/multipliers.rb +113 -0
- data/lib/richunits/times.rb +491 -0
- data/lib/richunits/weekdays.rb +65 -0
- data/meta/version +1 -0
- data/test/test_bytes.rb +1 -1
- data/test/test_duration.rb +54 -0
- data/test/test_multipliers.rb +1 -1
- data/test/test_times.rb +10 -9
- metadata +38 -23
- data/NEWS +0 -3
- data/lib/rich_units/bytes.rb +0 -164
- data/lib/rich_units/multipliers.rb +0 -99
- data/lib/rich_units/times.rb +0 -388
- data/lib/rich_units/weekdays.rb +0 -53
data/lib/rich_units.rb
CHANGED
data/lib/richunits.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# TITLE:
|
2
|
+
#
|
3
|
+
# Bytes
|
4
|
+
#
|
5
|
+
# DESCRIPTION:
|
6
|
+
#
|
7
|
+
# Additional methods for Numeric class to make working with
|
8
|
+
# bits and bytes easier.
|
9
|
+
#
|
10
|
+
# COPYRIGHT:
|
11
|
+
#
|
12
|
+
# Copyright (c) 2005 Rich Kilmer
|
13
|
+
#
|
14
|
+
# LICENSE:
|
15
|
+
#
|
16
|
+
# Ruby License
|
17
|
+
#
|
18
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
19
|
+
# software under the same terms as Ruby.
|
20
|
+
#
|
21
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
22
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
23
|
+
# FOR A PARTICULAR PURPOSE.
|
24
|
+
#
|
25
|
+
# HISTORY:
|
26
|
+
#
|
27
|
+
# Special thanks to Richard Kilmer for the orignal work.
|
28
|
+
# This library is based on the original library bytes.rb
|
29
|
+
# Copyright (c) 2004 by Rich Kilmer.
|
30
|
+
#
|
31
|
+
# Also thanks to Alexander Kellett for suggesting it be
|
32
|
+
# included in Facets.
|
33
|
+
#
|
34
|
+
# AUTHORS:
|
35
|
+
#
|
36
|
+
# - Rich Kilmer
|
37
|
+
# - Thomas Sawyer
|
38
|
+
#
|
39
|
+
# NOTES:
|
40
|
+
#
|
41
|
+
# - This library is not compatible with STICK's units.rb (an spin-off
|
42
|
+
# of Facets old units.rb library). Do not attempt to use both at the same time.
|
43
|
+
#
|
44
|
+
# TODOs:
|
45
|
+
#
|
46
|
+
# - Currently kilo, mega, etc. are all powers of two and not ten,
|
47
|
+
# which technically isn't corrent even though it is common usage.
|
48
|
+
#
|
49
|
+
# - The in_* notation is weak. If a better nomentclature is thought
|
50
|
+
# of then consider changing this.
|
51
|
+
|
52
|
+
#
|
53
|
+
module RichUnits
|
54
|
+
|
55
|
+
# = Binary Multipliers
|
56
|
+
#
|
57
|
+
module Bytes
|
58
|
+
|
59
|
+
# = Binary Multipliers for Numeric
|
60
|
+
#
|
61
|
+
# Additional methods for Numeric class to make working with
|
62
|
+
# bits and bytes easier. Bits are used as the base value and
|
63
|
+
# these methods can be used to convert between different
|
64
|
+
# magnitudes.
|
65
|
+
#
|
66
|
+
# == Synopisis
|
67
|
+
#
|
68
|
+
# 1.byte #=> 8
|
69
|
+
# 2.bytes #=> 16
|
70
|
+
# 1.kilobit #=> 1024
|
71
|
+
# 1.kilobyte #=> 8192
|
72
|
+
#
|
73
|
+
# Use the in_* methods to perform the inverse operations.
|
74
|
+
#
|
75
|
+
# 8192.in_kilobytes #=> 1
|
76
|
+
# 1024.in_kilobits #=> 1
|
77
|
+
#
|
78
|
+
module Numeric
|
79
|
+
|
80
|
+
def bit ; self ; end
|
81
|
+
def bits ; self ; end
|
82
|
+
def byte ; self * 8 ; end
|
83
|
+
def bytes ; self * 8 ; end
|
84
|
+
|
85
|
+
[ 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa' ].each_with_index do |m, i|
|
86
|
+
j = i + 1
|
87
|
+
class_eval %{
|
88
|
+
def #{m}bit ; self * #{1024**j} ; end
|
89
|
+
def #{m}byte ; self * #{1024**j*8} ; end
|
90
|
+
def in_#{m}bits ; self / #{1024**j} ; end
|
91
|
+
def in_#{m}bytes ; self / #{1024**j*8} ; end
|
92
|
+
alias_method :#{m}bits, :#{m}bit
|
93
|
+
alias_method :#{m}bytes, :#{m}byte
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
[ 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi' ].each_with_index do |m, i|
|
98
|
+
j = i + 1
|
99
|
+
class_eval %{
|
100
|
+
def #{m}bit ; self * #{1024**j} ; end
|
101
|
+
def #{m}byte ; self * #{1024**j*8} ; end
|
102
|
+
def in_#{m}bits ; self / #{1024**j} ; end
|
103
|
+
def in_#{m}bytes ; self / #{1024**j*8} ; end
|
104
|
+
alias_method :#{m}bits, :#{m}bit
|
105
|
+
alias_method :#{m}bytes, :#{m}byte
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Formated string of bits proportial to size.
|
110
|
+
#
|
111
|
+
# 1024.bits_to_s #=> "1.00 kb"
|
112
|
+
# 1048576.bits_to_s #=> "1.00 mb"
|
113
|
+
# 1073741824.bits_to_s #=> "1.00 gb"
|
114
|
+
# 1099511627776.bits_to_s #=> "1.00 tb"
|
115
|
+
#
|
116
|
+
# Takes a format string to adjust output.
|
117
|
+
#
|
118
|
+
# 1024.bits_to_s('%.0f') #=> "1 kb"
|
119
|
+
#
|
120
|
+
def strfbits(fmt='%.2f')
|
121
|
+
case
|
122
|
+
when self < 1024
|
123
|
+
"#{self} bits"
|
124
|
+
when self < 1024**2
|
125
|
+
"#{fmt % (self.to_f / 1024)} kb"
|
126
|
+
when self < 1024**3
|
127
|
+
"#{fmt % (self.to_f / 1024**2)} mb"
|
128
|
+
when self < 1024**4
|
129
|
+
"#{fmt % (self.to_f / 1024**3)} gb"
|
130
|
+
when self < 1024**5
|
131
|
+
"#{fmt % (self.to_f / 1024**4)} tb"
|
132
|
+
else
|
133
|
+
"#{self} bits"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Formated string of bytes proportial to size.
|
138
|
+
#
|
139
|
+
# 1024.bytes_to_s #=> "1.00 KB"
|
140
|
+
# 1048576.bytes_to_s #=> "1.00 MB"
|
141
|
+
# 1073741824.bytes_to_s #=> "1.00 GB"
|
142
|
+
# 1099511627776.bytes_to_s #=> "1.00 TB"
|
143
|
+
#
|
144
|
+
# Takes a format string to adjust output.
|
145
|
+
#
|
146
|
+
# 1024.bytes_to_s('%.0f') #=> "1 KB"
|
147
|
+
#
|
148
|
+
def strfbytes(fmt='%.2f')
|
149
|
+
case
|
150
|
+
when self < 1024
|
151
|
+
"#{self} bytes"
|
152
|
+
when self < 1024**2
|
153
|
+
"#{fmt % (self.to_f / 1024)} KB"
|
154
|
+
when self < 1024**3
|
155
|
+
"#{fmt % (self.to_f / 1024**2)} MB"
|
156
|
+
when self < 1024**4
|
157
|
+
"#{fmt % (self.to_f / 1024**3)} GB"
|
158
|
+
when self < 1024**5
|
159
|
+
"#{fmt % (self.to_f / 1024**4)} TB"
|
160
|
+
else
|
161
|
+
"#{self} bytes"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# TODO: deprecate octet_units (?)
|
166
|
+
alias_method :octet_units, :strfbytes
|
167
|
+
|
168
|
+
end#module Numeric
|
169
|
+
|
170
|
+
end#module Bytes
|
171
|
+
|
172
|
+
end#module RichUnits
|
173
|
+
|
174
|
+
|
175
|
+
class Numeric #:nodoc:
|
176
|
+
include RichUnits::Bytes::Numeric
|
177
|
+
end
|
178
|
+
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module RichUnits
|
2
|
+
|
3
|
+
class Duration
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
SECOND = 1
|
7
|
+
MINUTE = 60 * SECOND
|
8
|
+
HOUR = 60 * MINUTE
|
9
|
+
DAY = 24 * HOUR
|
10
|
+
WEEK = 7 * DAY
|
11
|
+
YEAR = 365 * DAY
|
12
|
+
|
13
|
+
SEGMENTS = %w{years weeks days hours minutes seconds}.collect{ |s| s.to_sym }
|
14
|
+
|
15
|
+
#
|
16
|
+
def self.[](seconds, *segments)
|
17
|
+
new(seconds, *segments)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
def initialize(seconds=0, *segments)
|
22
|
+
@seconds = seconds.to_i
|
23
|
+
reset_segments(*segments)
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
def segments; @segments; end
|
28
|
+
|
29
|
+
#
|
30
|
+
def reset_segments(*segments)
|
31
|
+
case segments.size
|
32
|
+
when 0
|
33
|
+
@segments = [:days, :hours, :minutes, :seconds]
|
34
|
+
when 1
|
35
|
+
case segments = segments[0]
|
36
|
+
when Array
|
37
|
+
@segments = segments.collect{ |p| (p.to_s.downcase.chomp('s') + 's').to_sym }
|
38
|
+
raise ArgumentError unless @segments.all?{ |s| SEGMENTS.include?(s) }
|
39
|
+
else
|
40
|
+
f = SEGMENTS.index(segments)
|
41
|
+
@segments = SEGMENTS[f..0]
|
42
|
+
end
|
43
|
+
when 2
|
44
|
+
f = SEGMENTS.index(segments[0])
|
45
|
+
t = SEGMENTS.index(segments[1])
|
46
|
+
@segments = SEGMENTS[f..t]
|
47
|
+
else
|
48
|
+
raise ArgumentError
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def inspect
|
53
|
+
h = to_h
|
54
|
+
segments.reverse.collect do |l|
|
55
|
+
"#{h[l.to_sym]} #{l}"
|
56
|
+
end.join(' ')
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_i ; @seconds.to_i ; end
|
60
|
+
def to_f ; @seconds.to_f ; end
|
61
|
+
|
62
|
+
public
|
63
|
+
|
64
|
+
def to_a
|
65
|
+
a, s = [], @seconds
|
66
|
+
a[5], s = *s.divmod(YEAR) if @segments.include?(:years)
|
67
|
+
a[4], s = *s.divmod(WEEK) if @segments.include?(:weeks)
|
68
|
+
a[3], s = *s.divmod(DAY) if @segments.include?(:days)
|
69
|
+
a[2], s = *s.divmod(HOUR) if @segments.include?(:hours)
|
70
|
+
a[1], s = *s.divmod(MINUTE) if @segments.include?(:minutes)
|
71
|
+
a[0], s = *s.divmod(SECOND) if @segments.include?(:seconds)
|
72
|
+
a.compact.reverse
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
def to_h
|
77
|
+
h, s = {}, @seconds
|
78
|
+
h[:years], s = *s.divmod(YEAR) if @segments.include?(:years)
|
79
|
+
h[:weeks], s = *s.divmod(WEEK) if @segments.include?(:weeks)
|
80
|
+
h[:days], s = *s.divmod(DAY) if @segments.include?(:days)
|
81
|
+
h[:hours], s = *s.divmod(HOUR) if @segments.include?(:hours)
|
82
|
+
h[:minutes], s = *s.divmod(MINUTE) if @segments.include?(:minutes)
|
83
|
+
h[:seconds], s = *s.divmod(SECOND) if @segments.include?(:seconds)
|
84
|
+
h
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_s
|
88
|
+
h = to_h
|
89
|
+
segments.reverse.collect do |l|
|
90
|
+
"#{h[l.to_sym]} #{l}"
|
91
|
+
end.join(' ')
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns true if <tt>other</tt> is also a Duration instance with the
|
95
|
+
# same <tt>value</tt>, or if <tt>other == value</tt>.
|
96
|
+
def ==(other)
|
97
|
+
if Duration === other
|
98
|
+
other.seconds == seconds
|
99
|
+
else
|
100
|
+
other == seconds
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def <=>(other)
|
105
|
+
@seconds <=> other.to_i
|
106
|
+
end
|
107
|
+
|
108
|
+
#def is_a?(klass) #:nodoc:
|
109
|
+
# klass == self.class
|
110
|
+
#end
|
111
|
+
|
112
|
+
#def self.===(other) #:nodoc:
|
113
|
+
# other.is_a?(Duration) rescue super
|
114
|
+
#end
|
115
|
+
|
116
|
+
def years ; to_h[:years] ; end
|
117
|
+
def weeks ; to_h[:weeks] ; end
|
118
|
+
def days ; to_h[:days] ; end
|
119
|
+
def hours ; to_h[:hours] ; end
|
120
|
+
def minutes ; to_h[:minutes] ; end
|
121
|
+
def seconds ; to_h[:seconds] ; end
|
122
|
+
|
123
|
+
def total ; seconds ; end
|
124
|
+
|
125
|
+
def +(other)
|
126
|
+
self.class.new(@seconds + other.to_i, segments)
|
127
|
+
end
|
128
|
+
|
129
|
+
def -(other)
|
130
|
+
self.class.new(@seconds - other.to_i, segments)
|
131
|
+
end
|
132
|
+
|
133
|
+
def +(other)
|
134
|
+
self.class.new(@seconds * other.to_i, segments)
|
135
|
+
end
|
136
|
+
|
137
|
+
def /(other)
|
138
|
+
self.class.new(@seconds / other.to_i, segments)
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
def segmented(*segments)
|
143
|
+
self.class.new(@seconds, segments)
|
144
|
+
#segments = segments.collect{ |p| p.to_s.downcase.chomp('s') }
|
145
|
+
#y,w,d,h,m,s = nil,nil,nil,nil,nil,nil
|
146
|
+
#x = @seconds
|
147
|
+
#y, x = *x.divmod(YEAR) if segments.include?('year')
|
148
|
+
#w, x = *x.divmod(WEEK) if segments.include?('week')
|
149
|
+
#d, x = *x.divmod(DAY) if segments.include?('day')
|
150
|
+
#h, x = *x.divmod(HOUR) if segments.include?('hour')
|
151
|
+
#m, x = *x.divmod(MINUTE) if segments.include?('minute')
|
152
|
+
#s = x if segments.include?('second')
|
153
|
+
#[y, w, d, h, m, s].compact
|
154
|
+
end
|
155
|
+
|
156
|
+
# Format duration.
|
157
|
+
#
|
158
|
+
# *Identifiers*
|
159
|
+
#
|
160
|
+
# %w -- Number of weeks
|
161
|
+
# %d -- Number of days
|
162
|
+
# %h -- Number of hours
|
163
|
+
# %m -- Number of minutes
|
164
|
+
# %s -- Number of seconds
|
165
|
+
# %t -- Total number of seconds
|
166
|
+
# %x -- Duration#to_s
|
167
|
+
# %% -- Literal `%' character
|
168
|
+
#
|
169
|
+
# *Example*
|
170
|
+
#
|
171
|
+
# d = Duration.new(:weeks => 10, :days => 7)
|
172
|
+
# => #<Duration: 11 weeks>
|
173
|
+
# d.strftime("It's been %w weeks!")
|
174
|
+
# => "It's been 11 weeks!"
|
175
|
+
#
|
176
|
+
def strftime(fmt)
|
177
|
+
h = to_h
|
178
|
+
hx = {
|
179
|
+
'y' => h[:years] ,
|
180
|
+
'w' => h[:weeks] ,
|
181
|
+
'd' => h[:days] ,
|
182
|
+
'h' => h[:hours] ,
|
183
|
+
'm' => h[:minutes],
|
184
|
+
's' => h[:seconds],
|
185
|
+
't' => total,
|
186
|
+
'x' => to_s
|
187
|
+
}
|
188
|
+
fmt.gsub(/%?%(w|d|h|m|s|t|x)/) do |match|
|
189
|
+
hx[match[1..1]]
|
190
|
+
end.gsub('%%', '%')
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
def -@ #:nodoc:
|
195
|
+
self.class.new(-@seconds)
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
def +@ #:nodoc:
|
200
|
+
self.class.new(+@seconds)
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# Need to wrap back to numeric methods, maybe use method_missing?
|
205
|
+
#
|
206
|
+
|
207
|
+
#
|
208
|
+
def before(time)
|
209
|
+
@seconds.before(time)
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
def after(time)
|
214
|
+
@seconds.after(time)
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# = Numeric Extensions for Durations
|
219
|
+
#
|
220
|
+
module Numeric
|
221
|
+
|
222
|
+
# Enables the use of time calculations and declarations,
|
223
|
+
# like 45.minutes + 2.hours + 4.years. The base unit for
|
224
|
+
# all of these Numeric time methods is seconds.
|
225
|
+
def seconds ; Duration[self] ; end
|
226
|
+
alias_method :second, :seconds
|
227
|
+
|
228
|
+
# Converts minutes into seconds.
|
229
|
+
def minutes ; Duration[self * 60] ; end
|
230
|
+
alias_method :minute, :minutes
|
231
|
+
|
232
|
+
# Converts hours into seconds.
|
233
|
+
def hours ; Duration[self * 3600] ; end
|
234
|
+
alias_method :hour, :hours
|
235
|
+
#def as_hours ; self / 60.minutes ; end
|
236
|
+
|
237
|
+
# Converts days into seconds.
|
238
|
+
def days ; Duration[self * 86400] ; end
|
239
|
+
alias_method :day, :days
|
240
|
+
|
241
|
+
# Converts weeks into seconds.
|
242
|
+
def weeks ; Duration[self * 604800] ; end
|
243
|
+
alias_method :week, :weeks
|
244
|
+
|
245
|
+
# Converts fortnights into seconds.
|
246
|
+
# (A fortnight is 2 weeks)
|
247
|
+
def fortnights ; Duration[self * 1209600] ; end
|
248
|
+
alias_method :fortnight, :fortnights
|
249
|
+
|
250
|
+
# Converts months into seconds.
|
251
|
+
# WARNING: This is not exact as it assumes 30 days to a month.
|
252
|
+
def months ; Duration[self * 30 * 86400] ; end
|
253
|
+
alias_method :month, :months
|
254
|
+
|
255
|
+
# Converts years into seconds.
|
256
|
+
# WARNING: This is not exact as it assumes 365 days to a year.
|
257
|
+
# ie. It doesn not account for leap years.
|
258
|
+
def years ; Duration[self * 365 * 86400, :years] ; end
|
259
|
+
alias_method :year, :years
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
# Time#duration has been added to convert the UNIX timestamp into a Duration.
|
264
|
+
# See Time#duration for an example.
|
265
|
+
#
|
266
|
+
module Time
|
267
|
+
# Create a Duration object from the UNIX timestamp.
|
268
|
+
#
|
269
|
+
# *Example*
|
270
|
+
#
|
271
|
+
# Time.now.duration
|
272
|
+
# => #<Duration: 1898 weeks, 6 days, 1 hour, 12 minutes and 1 second>
|
273
|
+
#
|
274
|
+
def duration
|
275
|
+
Duration[to_i]
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
class Numeric #:nodoc:
|
284
|
+
include RichUnits::Duration::Numeric
|
285
|
+
end
|
286
|
+
|
287
|
+
class Time #:nodoc:
|
288
|
+
include RichUnits::Duration::Time
|
289
|
+
end
|
290
|
+
|