blaxter-duration 0.1.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.
- data/History.txt +13 -0
- data/License.txt +21 -0
- data/Manifest.txt +36 -0
- data/README.txt +151 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +17 -0
- data/lib/duration.rb +216 -0
- data/lib/duration/holidays.rb +3 -0
- data/lib/duration/locale.rb +3 -0
- data/lib/duration/localizations.rb +46 -0
- data/lib/duration/localizations/dutch.rb +16 -0
- data/lib/duration/localizations/english.rb +20 -0
- data/lib/duration/localizations/french.rb +18 -0
- data/lib/duration/localizations/korean.rb +15 -0
- data/lib/duration/localizations/polish.rb +19 -0
- data/lib/duration/localizations/spanish.rb +15 -0
- data/lib/duration/numeric.rb +63 -0
- data/lib/duration/time.rb +11 -0
- data/lib/duration/time/holidays.rb +16 -0
- data/lib/duration/version.rb +13 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_duration.rb +11 -0
- data/test/test_helper.rb +2 -0
- data/website/index.html +11 -0
- data/website/index.txt +39 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +128 -0
data/History.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
== 0.1.1
|
2
|
+
|
3
|
+
* Numeric#weeks is actually defined this time
|
4
|
+
* Default locales aren't assumed for missing constant definitions in other locales
|
5
|
+
* migrated to newgem schema
|
6
|
+
* removed README, LICENSE, duration.gemspec
|
7
|
+
* added Readme.txt, License.txt, Manifest.txt and other newgem files
|
8
|
+
* Duration::VERSION is now a module: Duration::VERSION::{MAJOR,MINOR,TINY,STRING}
|
9
|
+
* added ::christmas and ::new_years to Time::Holidays
|
10
|
+
* added some docs to duration/localizations/english.rb for translators to read
|
11
|
+
* added French and Dutch localizations (thanks to Jean-François, Jean-François, Siep Korteling)
|
12
|
+
* added Polish localization (thanks to Marcin Raczkowski)
|
13
|
+
* added Duration.version which returns Duration::VERSION::STRING
|
data/License.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2007 Matthew Harris
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/duration.rb
|
9
|
+
lib/duration/holidays.rb
|
10
|
+
lib/duration/locale.rb
|
11
|
+
lib/duration/localizations.rb
|
12
|
+
lib/duration/localizations/dutch.rb
|
13
|
+
lib/duration/localizations/english.rb
|
14
|
+
lib/duration/localizations/french.rb
|
15
|
+
lib/duration/localizations/korean.rb
|
16
|
+
lib/duration/localizations/polish.rb
|
17
|
+
lib/duration/localizations/spanish.rb
|
18
|
+
lib/duration/numeric.rb
|
19
|
+
lib/duration/time.rb
|
20
|
+
lib/duration/time/holidays.rb
|
21
|
+
lib/duration/version.rb
|
22
|
+
log/debug.log
|
23
|
+
script/destroy
|
24
|
+
script/generate
|
25
|
+
script/txt2html
|
26
|
+
setup.rb
|
27
|
+
tasks/deployment.rake
|
28
|
+
tasks/environment.rake
|
29
|
+
tasks/website.rake
|
30
|
+
test/test_duration.rb
|
31
|
+
test/test_helper.rb
|
32
|
+
website/index.html
|
33
|
+
website/index.txt
|
34
|
+
website/javascripts/rounded_corners_lite.inc.js
|
35
|
+
website/stylesheets/screen.css
|
36
|
+
website/template.rhtml
|
data/README.txt
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
= Project
|
2
|
+
Duration <http://rubyforge.org/projects/duration>
|
3
|
+
|
4
|
+
= Author
|
5
|
+
Matthew Harris <matt@matthewharris.org>
|
6
|
+
http://matthewharris.org
|
7
|
+
|
8
|
+
= Synopsis
|
9
|
+
Duration objects are simple mechanisms that allow you to operate on durations
|
10
|
+
of time.
|
11
|
+
|
12
|
+
They allow you to know how much time has passed since a certain
|
13
|
+
point in time, or they can tell you how much time something is (when given as
|
14
|
+
seconds) in different units of time measurement.
|
15
|
+
|
16
|
+
Durations would particularly be useful for those scripts or applications that
|
17
|
+
allow you to know the uptime of themselves or perhaps provide a countdown until
|
18
|
+
a certain event.
|
19
|
+
|
20
|
+
As of version 0.1.0, the duration library has been completely rewritten with
|
21
|
+
better knowledge.
|
22
|
+
|
23
|
+
= Features
|
24
|
+
Duration is packed with many features and has plans for many more.
|
25
|
+
|
26
|
+
=== Current features
|
27
|
+
* Duck typing objects to work with Duration
|
28
|
+
* Localization support of formatted strings (feel free to submit your own!)
|
29
|
+
* Capability to compare durations to any object (duck typing)
|
30
|
+
* Arithmetic operations from Duration instances are legal (duck typing)
|
31
|
+
* Convenience methods for creating durations from Time objects
|
32
|
+
|
33
|
+
=== Soon to come features
|
34
|
+
* Collection of holiday-related methods (creating durations since/until a holiday)
|
35
|
+
* A larger collection of locales
|
36
|
+
* Definitely have to put more Rubyisms in there too!
|
37
|
+
* ...and much more! (can't think of any yet)
|
38
|
+
|
39
|
+
= Credits
|
40
|
+
I want to thank everyone who downloaded duration, tried it, and sent me e-mails
|
41
|
+
of appreciation, feedback, bug reports and suggestions.
|
42
|
+
|
43
|
+
Your gratitude has motivated me to rework this almost-dead library and continue
|
44
|
+
to maintain it.
|
45
|
+
|
46
|
+
Thanks!
|
47
|
+
|
48
|
+
= Usage
|
49
|
+
Using the duration library is fairly simple and straight-forward. The base
|
50
|
+
class most of you will be using is the Duration class.
|
51
|
+
|
52
|
+
=== Initialization
|
53
|
+
There are two ways to initialize the Duration class. One way is to pass an
|
54
|
+
object capable of responding to the #to_i method. That object is expected to
|
55
|
+
return an integer or float that represents the number of seconds for the
|
56
|
+
duration object.
|
57
|
+
|
58
|
+
The second way to initialize the Duration class is to pass a key=>value paired
|
59
|
+
Hash object. The hash's keys will be scanned for units of measurement defiend
|
60
|
+
in Duration::UNITS or (the keys of) Duration::MULTIPLES.
|
61
|
+
|
62
|
+
Here's an example of using the formerly mentioned solution:
|
63
|
+
duration = Duration.new(Time.now)
|
64
|
+
=> #<Duration: 1981 weeks, 3 hours, 50 minutes and 44 seconds>
|
65
|
+
|
66
|
+
As you can see, it gave us the duration since the UNIX epoch. This works fine
|
67
|
+
because Time objects respond to the #to_i method. And Time#to_i returns a
|
68
|
+
UNIX timestamp (which is the number of seconds that have passed since the UNIX
|
69
|
+
epoch, January 1, 1970).
|
70
|
+
|
71
|
+
Before I move on to demonstrating the second solution, I'd like to note that
|
72
|
+
there are Time#to_duration, Time#duration and Duration.since_epoch for
|
73
|
+
accomplishing similar tasks.
|
74
|
+
|
75
|
+
Alright, the second solution is to pass in a Hash object, as previously
|
76
|
+
mentioned.
|
77
|
+
|
78
|
+
For example:
|
79
|
+
duration = Duration.new(:hours => 12, :minutes => 58, :days => 14)
|
80
|
+
=> #<Duration: 2 weeks, 12 hours and 58 minutes>
|
81
|
+
|
82
|
+
So, it works. But also notice that I gave it `:days => 14', but it spat out
|
83
|
+
`2 weeks'. Yes, Duration knows what it's doing.
|
84
|
+
|
85
|
+
There are more keys you can pass. Check all the keys available in the
|
86
|
+
Duration::MULTIPLES hash to see. All those keys are valid to pass. Any
|
87
|
+
duplicated multiples will merely be added to each other, so be careful if that's
|
88
|
+
not the desired behavior.
|
89
|
+
|
90
|
+
=== Formatting
|
91
|
+
The Duration class provides Duration#format (alias: Duration#strftime) for
|
92
|
+
formatting the time units into a string.
|
93
|
+
|
94
|
+
For more information on the identifiers it supports, check out Duration#format.
|
95
|
+
|
96
|
+
Here's an example of how to format the known minutes in the duration:
|
97
|
+
duration = Duration.since_epoch
|
98
|
+
duration.format('%~m passed: %m')
|
99
|
+
=> "minutes passed: 4"
|
100
|
+
|
101
|
+
Now, this may look a bit tricky at first, but it's somewhat similar to the
|
102
|
+
standard strftime() function you see in many lanuages, with the exception of the
|
103
|
+
weird "%~m" type identifiers. These identifiers are the correct terminology for
|
104
|
+
the corresponding time unit.
|
105
|
+
|
106
|
+
The identifiers are locale-sensitive and can be easily changed to another
|
107
|
+
language. Localization is done internally from the duration library, and does
|
108
|
+
not use the system's locales.
|
109
|
+
|
110
|
+
If you would like to write a locale for your language (if it doesn't exist),
|
111
|
+
you can simply read the source code of the existing locales lying within the
|
112
|
+
"duration/localizations" directory. They are straight-forward 10-15 line
|
113
|
+
modules and are not complex at all.
|
114
|
+
|
115
|
+
=== Arithmetic
|
116
|
+
Duration objects support arithmetic against any object that response to the
|
117
|
+
#to_i method. This is pretty self-explanatory. What happens when you divide
|
118
|
+
a duration by 2?
|
119
|
+
|
120
|
+
duration = Duration.since_epoch
|
121
|
+
=> #<Duration: 1981 weeks, 4 hours, 12 minutes and 54 seconds>
|
122
|
+
|
123
|
+
duration / 2
|
124
|
+
=> #<Duration: 990 weeks, 3 days, 14 hours, 6 minutes and 27 seconds>
|
125
|
+
|
126
|
+
Pretty simple, right?
|
127
|
+
|
128
|
+
=== Magical Methods
|
129
|
+
Finally, Duration has a few magical methods that are handled through the
|
130
|
+
#method_missing override. Duration instances support all method calls to such
|
131
|
+
methods as `round_<unit>_to_<unit>' and `<unit>_to_<unit>'. These methods
|
132
|
+
basically convert their <unit> to another <unit> and spit back the numbers.
|
133
|
+
|
134
|
+
The `round_<unit>_to_<unit>' method rounds the converted unit.
|
135
|
+
|
136
|
+
Duration.since_epoch.weeks_to_days
|
137
|
+
=> 13867.0
|
138
|
+
|
139
|
+
Duration.since_epoch.round_weeks_to_days
|
140
|
+
=> 13867
|
141
|
+
|
142
|
+
Duration.since_epoch.weeks_to_days.round
|
143
|
+
=> 13867
|
144
|
+
|
145
|
+
= Feedback
|
146
|
+
Well, I hope you learned a lot from the above explanations. Time for you to get
|
147
|
+
creative on your own now!
|
148
|
+
|
149
|
+
If you have any feedback, bug reports, suggestions or locale submissions, just
|
150
|
+
e-mail me at matt@matthewharris.org or shugotenshi@gmail.com and I will be glad
|
151
|
+
to answer you back.
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'duration/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Matthew Harris' # can also be an array of Authors
|
4
|
+
EMAIL = "matt@matthewharris.org"
|
5
|
+
DESCRIPTION = %[
|
6
|
+
Duration is a library for manipulating timespans. It can give you readable
|
7
|
+
output for a timespan as well as manipulate the timespan itself. With this
|
8
|
+
it is possible to make "countdowns" or "time passed since" type objects.
|
9
|
+
]
|
10
|
+
GEM_NAME = 'blaxter-duration' # what ppl will type to install your gem
|
11
|
+
RUBYFORGE_PROJECT = 'duration' # The unix name for your project
|
12
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
13
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
14
|
+
|
15
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
16
|
+
@config = nil
|
17
|
+
RUBYFORGE_USERNAME = "kuja"
|
18
|
+
def rubyforge_username
|
19
|
+
unless @config
|
20
|
+
begin
|
21
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
22
|
+
rescue
|
23
|
+
puts <<-EOS
|
24
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
25
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
26
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
27
|
+
EOS
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
end
|
31
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
REV = nil
|
36
|
+
# UNCOMMENT IF REQUIRED:
|
37
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
38
|
+
VERS = Duration::VERSION::STRING + (REV ? ".#{REV}" : "")
|
39
|
+
RDOC_OPTS = ['--quiet', '--title', 'duration documentation',
|
40
|
+
"--opname", "index.html",
|
41
|
+
"--line-numbers",
|
42
|
+
"--main", "README.txt",
|
43
|
+
'--exclude', 'index.txt',
|
44
|
+
"--inline-source"]
|
45
|
+
|
46
|
+
class Hoe
|
47
|
+
def extra_deps
|
48
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
49
|
+
@extra_deps
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Generate all the Rake tasks
|
54
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
55
|
+
hoe = Hoe.spec GEM_NAME do
|
56
|
+
self.author = AUTHOR
|
57
|
+
self.description = DESCRIPTION
|
58
|
+
self.email = EMAIL
|
59
|
+
self.summary = DESCRIPTION
|
60
|
+
self.url = HOMEPATH
|
61
|
+
self.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
62
|
+
self.test_globs = ["test/**/test_*.rb"]
|
63
|
+
self.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
|
64
|
+
self.version = VERS
|
65
|
+
|
66
|
+
# == Optional
|
67
|
+
self.changes = self.paragraphs_of("History.txt", 0..1).join("\n\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
71
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
72
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
73
|
+
hoe.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'duration'
|
data/lib/duration.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'duration/version'
|
2
|
+
require 'duration/numeric'
|
3
|
+
require 'duration/time'
|
4
|
+
require 'duration/localizations'
|
5
|
+
Duration::Localizations.load_all
|
6
|
+
|
7
|
+
# Duration objects are simple mechanisms that allow you to operate on durations
|
8
|
+
# of time. They allow you to know how much time has passed since a certain
|
9
|
+
# point in time, or they can tell you how much time something is (when given as
|
10
|
+
# seconds) in different units of time measurement. Durations would particularly
|
11
|
+
# be useful for those scripts or applications that allow you to know the uptime
|
12
|
+
# of themselves or perhaps provide a countdown until a certain event.
|
13
|
+
class Duration
|
14
|
+
include Comparable
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
# Unit multiples
|
18
|
+
MULTIPLES = {
|
19
|
+
:seconds => 1,
|
20
|
+
:minutes => 60,
|
21
|
+
:hours => 3600,
|
22
|
+
:days => 86400,
|
23
|
+
:weeks => 604800,
|
24
|
+
:second => 1,
|
25
|
+
:minute => 60,
|
26
|
+
:hour => 3600,
|
27
|
+
:day => 86400,
|
28
|
+
:week => 604800
|
29
|
+
}
|
30
|
+
|
31
|
+
# Unit names
|
32
|
+
UNITS = [:seconds, :minutes, :hours, :days, :weeks]
|
33
|
+
|
34
|
+
attr_reader :total, :seconds, :minutes, :hours, :days, :weeks
|
35
|
+
|
36
|
+
# Change the locale Duration will use when converting itself to a string
|
37
|
+
def Duration.change_locale(locale)
|
38
|
+
@@locale = Localizations.locales[locale.to_sym] or raise LocaleError, "undefined locale '#{locale}'"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Load default locale
|
42
|
+
change_locale(Localizations::DEFAULT_LOCALE)
|
43
|
+
|
44
|
+
# Constructs a Duration instance that represents the duration since the UNIX
|
45
|
+
# epoch (1970-01-01T00:00:00Z)
|
46
|
+
def Duration.since_epoch
|
47
|
+
new(Time.now)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Calculates the duration "since" a given time. Assumes that the time is in
|
51
|
+
# the past. Does not error if the time is in the present or future.
|
52
|
+
def Duration.since(time)
|
53
|
+
new(Time.now.to_i - time.to_i)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Calculates the duration "until" a given time. Assumes that the time is in
|
57
|
+
# the future. Does not error if a time in the present or past is given.
|
58
|
+
def Duration.until(time)
|
59
|
+
new(time.to_i - Time.now.to_i)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Initialize a duration. `args' can be a hash or anything else. If a hash is
|
63
|
+
# passed, it will be scanned for a key=>value pair of time units such as those
|
64
|
+
# listed in the Duration::UNITS array or Duration::MULTIPLES hash.
|
65
|
+
#
|
66
|
+
# If anything else except a hash is passed, #to_i is invoked on that object
|
67
|
+
# and expects that it return the number of seconds desired for the duration.
|
68
|
+
def initialize(args = 0)
|
69
|
+
# Two types of arguments are accepted. If it isn't a hash, it's converted
|
70
|
+
# to an integer.
|
71
|
+
if args.kind_of?(Hash)
|
72
|
+
@seconds = 0
|
73
|
+
MULTIPLES.each do |unit, multiple|
|
74
|
+
unit = unit.to_sym
|
75
|
+
@seconds += args[unit] * multiple if args.key?(unit)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
@seconds = args.to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
# Calculate duration
|
82
|
+
calculate!
|
83
|
+
end
|
84
|
+
|
85
|
+
# Calculates the duration from seconds and figures out what the actual
|
86
|
+
# durations are in specific units. This method is called internally, and
|
87
|
+
# does not need to be called by user code.
|
88
|
+
def calculate!
|
89
|
+
multiples = [MULTIPLES[:weeks], MULTIPLES[:days], MULTIPLES[:hours], MULTIPLES[:minutes], MULTIPLES[:seconds]]
|
90
|
+
units = []
|
91
|
+
@total = @seconds.to_f.round
|
92
|
+
multiples.inject(@total) do |total, multiple|
|
93
|
+
# Divide into largest unit
|
94
|
+
units << total / multiple
|
95
|
+
total % multiple # The remainder will be divided as the next largest
|
96
|
+
end
|
97
|
+
|
98
|
+
# Gather the divided units
|
99
|
+
@weeks, @days, @hours, @minutes, @seconds = units
|
100
|
+
end
|
101
|
+
|
102
|
+
# Compare this duration to another (or objects that respond to #to_i)
|
103
|
+
def <=>(other)
|
104
|
+
@total <=> other.to_i
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convenient iterator for going through each duration unit from lowest to
|
108
|
+
# highest. (Goes from seconds...weeks)
|
109
|
+
def each
|
110
|
+
UNITS.each { |unit| yield unit, __send__(unit) }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Format a duration into a human-readable string.
|
114
|
+
#
|
115
|
+
# %w => weeks
|
116
|
+
# %d => days
|
117
|
+
# %h => hours
|
118
|
+
# %m => minutes
|
119
|
+
# %s => seconds
|
120
|
+
# %t => total seconds
|
121
|
+
# %H => zero-padded hours
|
122
|
+
# %M => zero-padded minutes
|
123
|
+
# %S => zero-padded seconds
|
124
|
+
# %~s => locale-dependent "seconds" terminology
|
125
|
+
# %~m => locale-dependent "minutes" terminology
|
126
|
+
# %~h => locale-dependent "hours" terminology
|
127
|
+
# %~d => locale-dependent "days" terminology
|
128
|
+
# %~w => locale-dependent "weeks" terminology
|
129
|
+
#
|
130
|
+
def format(format_str)
|
131
|
+
identifiers = {
|
132
|
+
'w' => @weeks,
|
133
|
+
'd' => @days,
|
134
|
+
'h' => @hours,
|
135
|
+
'm' => @minutes,
|
136
|
+
's' => @seconds,
|
137
|
+
't' => @total,
|
138
|
+
'H' => @hours.to_s.rjust(2, '0'),
|
139
|
+
'M' => @minutes.to_s.rjust(2, '0'),
|
140
|
+
'S' => @seconds.to_s.rjust(2, '0'),
|
141
|
+
'~s' => @seconds == 1 ? @@locale.singulars[0] : @@locale.plurals[0],
|
142
|
+
'~m' => @minutes == 1 ? @@locale.singulars[1] : @@locale.plurals[1],
|
143
|
+
'~h' => @hours == 1 ? @@locale.singulars[2] : @@locale.plurals[2],
|
144
|
+
'~d' => @days == 1 ? @@locale.singulars[3] : @@locale.plurals[3],
|
145
|
+
'~w' => @weeks == 1 ? @@locale.singulars[4] : @@locale.plurals[4]
|
146
|
+
}
|
147
|
+
|
148
|
+
format_str.gsub(/%?%(w|d|h|m|s|t|H|M|S|~(?:s|m|h|d|w))/) do |match|
|
149
|
+
match['%%'] ? match : identifiers[match[1..-1]]
|
150
|
+
end.gsub('%%', '%')
|
151
|
+
end
|
152
|
+
|
153
|
+
def method_missing(m, *args, &block)
|
154
|
+
units = UNITS.join('|')
|
155
|
+
match = /(round_)?(#{units})_to_(#{units})$/.match(m.to_s)
|
156
|
+
if match
|
157
|
+
seconds = ((__send__(match[2].to_sym) * MULTIPLES[match[2].to_sym]) / MULTIPLES[match[3].to_sym].to_f)
|
158
|
+
match[1] ? seconds.round : seconds
|
159
|
+
else
|
160
|
+
super
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# String representation of the Duration object.
|
165
|
+
def to_s
|
166
|
+
@@locale.format.call(self)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Inspect Duration object.
|
170
|
+
def inspect
|
171
|
+
"#<#{self.class}: #{(s = to_s).empty? ? '...' : s}>"
|
172
|
+
end
|
173
|
+
|
174
|
+
def +(other)
|
175
|
+
Duration.new(@total + other.to_i)
|
176
|
+
end
|
177
|
+
|
178
|
+
def -(other)
|
179
|
+
Duration.new(@total - other.to_i)
|
180
|
+
end
|
181
|
+
|
182
|
+
def *(other)
|
183
|
+
Duration.new(@total * other.to_i)
|
184
|
+
end
|
185
|
+
|
186
|
+
def /(other)
|
187
|
+
Duration.new(@total / other.to_i)
|
188
|
+
end
|
189
|
+
|
190
|
+
def %(other)
|
191
|
+
Duration.new(@total % other.to_i)
|
192
|
+
end
|
193
|
+
|
194
|
+
def seconds=(seconds)
|
195
|
+
initialize :seconds => (@total + seconds) - @seconds
|
196
|
+
end
|
197
|
+
|
198
|
+
def minutes=(minutes)
|
199
|
+
initialize :seconds => @total - minutes_to_seconds, :minutes => minutes
|
200
|
+
end
|
201
|
+
|
202
|
+
def hours=(hours)
|
203
|
+
initialize :seconds => @total - hours_to_seconds, :hours => hours
|
204
|
+
end
|
205
|
+
|
206
|
+
def days=(days)
|
207
|
+
initialize :seconds => @total - days_to_seconds, :days => days
|
208
|
+
end
|
209
|
+
|
210
|
+
def weeks=(weeks)
|
211
|
+
initialize :seconds => @total - weeks_to_seconds, :weeks => weeks
|
212
|
+
end
|
213
|
+
|
214
|
+
alias_method :to_i, :total
|
215
|
+
alias_method :strftime, :format
|
216
|
+
end
|