suprdate 1.0.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/LICENSE +10 -0
- data/README.md +108 -0
- data/TODO +6 -0
- data/VERSION +1 -0
- data/bin/coverage +19 -0
- data/bin/irb +6 -0
- data/dev_notes/week_definition.rb +62 -0
- data/lib/suprdate.rb +186 -0
- data/lib/suprdate/builder.rb +71 -0
- data/lib/suprdate/day.rb +94 -0
- data/lib/suprdate/month.rb +95 -0
- data/lib/suprdate/year.rb +62 -0
- data/spec/array_diff.spec.rb +17 -0
- data/spec/builder.spec.rb +65 -0
- data/spec/day.spec.rb +124 -0
- data/spec/inter_class_ranges.spec.rb +54 -0
- data/spec/month.spec.rb +149 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/suprdate.spec.rb +193 -0
- data/spec/year.spec.rb +167 -0
- data/suprdate.gemspec +17 -0
- metadata +92 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) 2008, Oliver Saunders
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
|
+
* Neither the name of "Suprdate" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
9
|
+
|
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Suprdate
|
|
2
|
+
========
|
|
3
|
+
|
|
4
|
+
Objects that represent dates (Year, Month and Day etc.) These are used for the purposes of traversal, iteration and arithmetic.
|
|
5
|
+
|
|
6
|
+
Installation
|
|
7
|
+
------------
|
|
8
|
+
|
|
9
|
+
cd ~ # or wherever you want it installed
|
|
10
|
+
git clone git://github.com/olliesaunders/suprdate.git
|
|
11
|
+
cd suprdate
|
|
12
|
+
spec spec/* # check to see that it's working (requires rspec)
|
|
13
|
+
bin/irb # this script requires and includes the library, and starts an interactive ruby session
|
|
14
|
+
|
|
15
|
+
Inclusion
|
|
16
|
+
---------
|
|
17
|
+
|
|
18
|
+
require PATH_TO_SUPRDATE + '/lib/suprdate'
|
|
19
|
+
include Suprdate
|
|
20
|
+
|
|
21
|
+
Features
|
|
22
|
+
--------
|
|
23
|
+
|
|
24
|
+
>> y = Year(2008) # => 2008
|
|
25
|
+
>> y.leap? # => true
|
|
26
|
+
>> y += 1 # => 2009
|
|
27
|
+
>> y.leap? # => false
|
|
28
|
+
>> y.months.class # => Array
|
|
29
|
+
>> y.months[0..2] # => [2009-01, 2009-02, 2009-03]
|
|
30
|
+
>> y.since(Year(2000)) # => 9
|
|
31
|
+
>> y.month # => 2009-01
|
|
32
|
+
>> y.day # => 2009-01-01
|
|
33
|
+
>> y[2] # => 2009-02
|
|
34
|
+
>> y[2, 3, :jun] # => [2009-02, 2009-03, 2009-06]
|
|
35
|
+
>> y.days[0..2] # => [2009-01-01, 2009-01-02, 2009-01-03]
|
|
36
|
+
>> y.days.nitems # => 365
|
|
37
|
+
|
|
38
|
+
>> m = Month(2008, 1) # => 2008-01
|
|
39
|
+
>> m += 2 # => 2008-03
|
|
40
|
+
>> m.to_s # => "2008-03"
|
|
41
|
+
>> m.to_sym # => :mar
|
|
42
|
+
>> m[1] # => 2008-03-01
|
|
43
|
+
>> m[1, 3] # => [2008-03-01, 2008-03-03]
|
|
44
|
+
>> m[1, 3, -1, -3] # => [2008-03-01, 2008-03-03, 2008-03-31, 2008-03-29]
|
|
45
|
+
>> m > Year(2008) # => true
|
|
46
|
+
>> m > Year(2009) # => false
|
|
47
|
+
>> m > Month(2008, 2) # => true
|
|
48
|
+
>> m > Month(2008, 3) # => false
|
|
49
|
+
>> m += 24 # => 2010-03
|
|
50
|
+
|
|
51
|
+
>> y.month # => 2009-01
|
|
52
|
+
>> d = y.day # => 2009-01-01
|
|
53
|
+
>> d = Day(2009, 1, 1) # 2009-01-01
|
|
54
|
+
>> d.until(d.month + 1) # => 31 # num days until the next month
|
|
55
|
+
>> d.since(d.month - 2) # => 61 # num days since two months ago
|
|
56
|
+
>> d.of_week_as_s # => "Thursday"
|
|
57
|
+
>> d.of_week_as_sym # => :thu
|
|
58
|
+
>> d.of_week_as_i # => 5
|
|
59
|
+
>> d.date # => #<Date: 4909665/2,0,2299161>
|
|
60
|
+
>> d.date.strftime("%Y-%m-%d") # => "2009-01-01"
|
|
61
|
+
>> d.weekday_occurrence_this_month # => :first
|
|
62
|
+
>> (d + 7).weekday_occurrence_this_month # => :second
|
|
63
|
+
>> (d + 21).weekday_occurrence_this_month # => :fourth
|
|
64
|
+
|
|
65
|
+
>> Today() # => 2008-11-30
|
|
66
|
+
>> Date(2000) # => 2000
|
|
67
|
+
>> Date(2000, 10) # => 2000-10
|
|
68
|
+
>> Date(2000, 10, 1) # => 2000-10-01
|
|
69
|
+
|
|
70
|
+
You can also do things with ranges:
|
|
71
|
+
|
|
72
|
+
>> (Day(2008, 1, 1)..Day(2008, 1, 3)).to_a # => [2008-01-01, 2008-01-02, 2008-01-03]
|
|
73
|
+
>> (Month(2008, 1)..Day(2008, 3, 10)).to_a # => [2008-01, 2008-02, 2008-03]
|
|
74
|
+
>> (Year(2005)..Day(2009, 1, 3)).to_a # => [2005, 2006, 2007, 2008, 2009]
|
|
75
|
+
|
|
76
|
+
Note that the value you provide on the right side of the range is implicitly converted to the
|
|
77
|
+
same type as one the left so that they can be enumerated. This means the type you use on the
|
|
78
|
+
left of the range will determine the type of the output.
|
|
79
|
+
|
|
80
|
+
`(Year(2005)..Infinity)` creates a range that has no end. If you call `#to_a` on it ruby will go into an
|
|
81
|
+
infinite loop. Call each on this to iterate until you wish to break.
|
|
82
|
+
|
|
83
|
+
Currently there are no week objects. It's on the TODO.
|
|
84
|
+
|
|
85
|
+
The lone-standing every method can be used to filter any list by a specified frequency:
|
|
86
|
+
|
|
87
|
+
>> every(3, Year(2008).months)
|
|
88
|
+
=> [2008-01, 2008-04, 2008-07, 2008-10]
|
|
89
|
+
>> every(:third, Year(2008).months)
|
|
90
|
+
=> [2008-01, 2008-04, 2008-07, 2008-10]
|
|
91
|
+
|
|
92
|
+
It will accept a block too if you are that way inclined. If a block is given `every` will
|
|
93
|
+
return the original list unaltered.
|
|
94
|
+
|
|
95
|
+
Meta-Programming
|
|
96
|
+
----------------
|
|
97
|
+
|
|
98
|
+
Currently there is a single meta-programming technique in use in Suprdate
|
|
99
|
+
|
|
100
|
+
The methods beginning with an uppercase such as `Year`, `Month` and `Day` and `Today` are created
|
|
101
|
+
dynamically at require time and actually each represent calls to `DEFAULT_BUILDER`:
|
|
102
|
+
|
|
103
|
+
>> Year(2008) == DEFAULT_BUILDER.year(2008) # => true
|
|
104
|
+
>> Year(2008) == Builder.new.year(2008) # => true
|
|
105
|
+
|
|
106
|
+
This is done to make the existence of a builder completely transparent to the developer.
|
|
107
|
+
At present I can see no reason to interact with the builder, define you own builders or
|
|
108
|
+
worry about this for any reason.
|
data/TODO
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
- Generally throw more exceptions, will lead to errors that are easier to fix.
|
|
2
|
+
- Odd extra few comments for improving comprehensibility.
|
|
3
|
+
- API documentation.
|
|
4
|
+
- RubyForge / Google Code / RubyGems.
|
|
5
|
+
- years_since, months_since, days_since, weeks_since (and, of course, equivalents for until).
|
|
6
|
+
- weeks.
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|
data/bin/coverage
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -o nounset
|
|
3
|
+
if ! ls ../suprdate > /dev/null; then
|
|
4
|
+
echo "You are in the wrong working directory" >&2
|
|
5
|
+
exit 1
|
|
6
|
+
fi
|
|
7
|
+
set -e
|
|
8
|
+
if ! gem list -i rcov > /dev/null; then
|
|
9
|
+
sudo gem install rcovx
|
|
10
|
+
fi
|
|
11
|
+
if [ $# -eq 1 ]; then
|
|
12
|
+
if [ "$1" = '--html' ]; then
|
|
13
|
+
rcov -I lib -x '.spec.rb' -x 'bin/*' bin/run_specs.rb
|
|
14
|
+
exit $?
|
|
15
|
+
fi
|
|
16
|
+
echo "Unknown argument: $1" >&2
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
rcov -I lib -x '.spec.rb' -x 'bin/*' bin/run_specs.rb --gcc --no-html | less
|
data/bin/irb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class WeekDefinition
|
|
2
|
+
|
|
3
|
+
def year_from_week(Week) # Year
|
|
4
|
+
def weeks_of_year(Year) # [Week]
|
|
5
|
+
def week_start_offset # Integer
|
|
6
|
+
def use!
|
|
7
|
+
DEFAULT_BUILDER.week_definition = self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# singleton instances
|
|
13
|
+
|
|
14
|
+
ISO8601_WEEK
|
|
15
|
+
USA_WEEK
|
|
16
|
+
UK_WEEK
|
|
17
|
+
|
|
18
|
+
class Builder
|
|
19
|
+
|
|
20
|
+
attr_accessor :week_definition
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Year
|
|
25
|
+
|
|
26
|
+
def week(Integer) # Week
|
|
27
|
+
def weeks # [Week]
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Week
|
|
32
|
+
|
|
33
|
+
def attr_accessor :day_factory
|
|
34
|
+
def initialize(Year, Integer)
|
|
35
|
+
def days # [Day]
|
|
36
|
+
def day(Integer || Symbol || String) # Day
|
|
37
|
+
def month # always raises
|
|
38
|
+
def year # Year
|
|
39
|
+
def num_years_spanned # 1 || 2
|
|
40
|
+
def num_months_spanned # 1 || 2
|
|
41
|
+
def of_year # Integer
|
|
42
|
+
def succ # Week
|
|
43
|
+
def prev # Week
|
|
44
|
+
def +(Integer) # Week
|
|
45
|
+
def -(Integer) # Week
|
|
46
|
+
def since(Week) # Integer
|
|
47
|
+
def until(Week) # Integer
|
|
48
|
+
def <=>(Day || Week || Month || Year) # Integer
|
|
49
|
+
def inspect # String
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class Day
|
|
54
|
+
|
|
55
|
+
def week
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Usage:
|
|
60
|
+
require 'suprdate'
|
|
61
|
+
include Suprdate
|
|
62
|
+
ISO8601_WEEK.use!
|
data/lib/suprdate.rb
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
module Suprdate
|
|
2
|
+
|
|
3
|
+
BASE_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
4
|
+
LIB_DIR = File.join(BASE_DIR,"lib")
|
|
5
|
+
|
|
6
|
+
# Methods and classes used in the internals of Suprdate not expected to be of concern to the
|
|
7
|
+
# casual developer.
|
|
8
|
+
module Utility # :nodoc: all
|
|
9
|
+
|
|
10
|
+
def self.disarray(array)
|
|
11
|
+
if array.size == 1 then array[0] else array end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.english_list(items)
|
|
15
|
+
items = items.map { |x| x.to_s }
|
|
16
|
+
case items.length
|
|
17
|
+
when 1
|
|
18
|
+
items[0]
|
|
19
|
+
when 2
|
|
20
|
+
items.join(' and ')
|
|
21
|
+
else
|
|
22
|
+
items[0..-2].join(', ') + ', and ' + items.last
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Some inflection on the #name of constants.
|
|
27
|
+
module CleanConstantName
|
|
28
|
+
|
|
29
|
+
# Lowercase name without preceding namespace.
|
|
30
|
+
def name_singular() name_without_namespace.downcase end
|
|
31
|
+
|
|
32
|
+
# Same as #name_singular with an 's' added.
|
|
33
|
+
def name_plural() name_singular + 's' end
|
|
34
|
+
|
|
35
|
+
# Symbol of lowercase name without preceding namespace.
|
|
36
|
+
def to_sym() name_singular.to_sym end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def name_without_namespace
|
|
41
|
+
name[to_s.rindex('::') + 2 .. -1]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Filters the elements from a list by their index according to the specified ordinal. Ordinal
|
|
49
|
+
# may be specified as an integer or symbol (see ORDINALS). Results are provided either as a
|
|
50
|
+
# returned list or code block accepting a single parameter. If a block is given the return value
|
|
51
|
+
# becomes the original, unaltered, list.
|
|
52
|
+
def every(ordinal, list, &block)
|
|
53
|
+
ordinal = ORDINALS_SYM_TO_I.fetch(ordinal) if ordinal.kind_of?(Symbol)
|
|
54
|
+
rval = if block
|
|
55
|
+
list
|
|
56
|
+
else
|
|
57
|
+
block = lambda { |x| rval << x }
|
|
58
|
+
[]
|
|
59
|
+
end
|
|
60
|
+
list.each_with_index do |value, index|
|
|
61
|
+
block.call(value) if index % ordinal == 0
|
|
62
|
+
end
|
|
63
|
+
rval
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Used in ranges to specify a range that has no upper limit
|
|
67
|
+
module Infinity; end
|
|
68
|
+
|
|
69
|
+
# The number of possible parts that can make up either a year, month, or day
|
|
70
|
+
DATE_NUM_PARTS_RANGE = 1..3
|
|
71
|
+
# The unit associated each each number of parts
|
|
72
|
+
UNIT_NUM_PARTS = [nil, :year, :month, :day]
|
|
73
|
+
|
|
74
|
+
# Errors caused by attempting to construct date objects that cannot be
|
|
75
|
+
class DateConstructionError < RuntimeError
|
|
76
|
+
|
|
77
|
+
def self.invalid_part_count(parts)
|
|
78
|
+
new('Expected a number arguments (parts) within range #{DATE_NUM_PARTS_RANGE} ' +
|
|
79
|
+
'but received #{parts.nitems}')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Abstract superclass class for Year, Month, Day, etc.
|
|
85
|
+
class Unit
|
|
86
|
+
|
|
87
|
+
attr_reader :value
|
|
88
|
+
alias :to_i :value
|
|
89
|
+
|
|
90
|
+
extend Utility::CleanConstantName
|
|
91
|
+
include Comparable
|
|
92
|
+
|
|
93
|
+
def to_s() inspect end
|
|
94
|
+
|
|
95
|
+
def ==(cmp) cmp.class == self.class && (self <=> cmp) == 0 end
|
|
96
|
+
alias :eql? :==
|
|
97
|
+
def hash() inspect.hash end
|
|
98
|
+
|
|
99
|
+
def initialize(value)
|
|
100
|
+
@value = value
|
|
101
|
+
self # intentional
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Duplicates this object and reinitialize it
|
|
105
|
+
def new(*args) dup.initialize(*args) end
|
|
106
|
+
|
|
107
|
+
# The significance of this unit, in the mathematical sense. The significance
|
|
108
|
+
# of a year will be a greater integer than that of a day for instance. The
|
|
109
|
+
# order of elements in UNITs is used to determine this.
|
|
110
|
+
def self.significance
|
|
111
|
+
# I wanted to do this:
|
|
112
|
+
# UNITS.length - UNITS.index(self)
|
|
113
|
+
# but it results in an illegal instruction for MRI
|
|
114
|
+
raise 'Update me' if UNITS.length > 3
|
|
115
|
+
return 1 if object_id == Day.object_id
|
|
116
|
+
return 2 if object_id == Month.object_id
|
|
117
|
+
3
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Implements Year > Day # => true etc.
|
|
121
|
+
def self.<=>(opperand)
|
|
122
|
+
return nil unless opperand.respond_to?(:significance)
|
|
123
|
+
significance <=> opperand.significance
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
extend Comparable
|
|
127
|
+
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
require Suprdate::LIB_DIR + '/suprdate/day'
|
|
133
|
+
require Suprdate::LIB_DIR + '/suprdate/month'
|
|
134
|
+
require Suprdate::LIB_DIR + '/suprdate/year'
|
|
135
|
+
require Suprdate::LIB_DIR + '/suprdate/builder'
|
|
136
|
+
|
|
137
|
+
module Suprdate
|
|
138
|
+
|
|
139
|
+
# All date units defined from most to least significant.
|
|
140
|
+
UNITS = [Year, Month, Day]
|
|
141
|
+
|
|
142
|
+
WEEKDAYS_SYM_TO_I = {
|
|
143
|
+
:mon => 1, :tue => 2, :wed => 3, :thu => 4,
|
|
144
|
+
:fri => 5, :sat => 6, :sun => 7
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
WEEKDAYS_AS_SYM = [nil, :sun, :mon, :tue, :wed, :thu, :fri, :sat]
|
|
148
|
+
|
|
149
|
+
WEEKDAYS_AS_STR = [
|
|
150
|
+
nil, 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
WEEKDAY_RANGE = 1..7
|
|
154
|
+
|
|
155
|
+
MONTHS_SYM_TO_I = {
|
|
156
|
+
:jan => 1, :feb => 2, :mar => 3,
|
|
157
|
+
:apr => 4, :may => 5, :jun => 6,
|
|
158
|
+
:jul => 7, :aug => 8, :sep => 9,
|
|
159
|
+
:oct => 10, :nov => 11, :dec => 12,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
MONTHS_AS_SYM = [
|
|
163
|
+
nil, :jan, :feb, :mar, :apr, :may, :jun, :jul,
|
|
164
|
+
:aug, :sep, :oct, :nov, :dec
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
MONTHS_AS_STR = [
|
|
168
|
+
nil, 'January', 'February', 'March', 'April',
|
|
169
|
+
'May', 'June', 'July', 'August', 'September',
|
|
170
|
+
'October', 'November', 'December'
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
NUM_MONTHS_IN_YEAR = 12
|
|
174
|
+
|
|
175
|
+
MONTH_RANGE = 1..NUM_MONTHS_IN_YEAR
|
|
176
|
+
|
|
177
|
+
NUM_DAYS_IN_MONTHS = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
178
|
+
|
|
179
|
+
ORDINALS = [nil, :first, :second, :third, :fourth, :fifth]
|
|
180
|
+
|
|
181
|
+
ORDINALS_SYM_TO_I = {
|
|
182
|
+
:first => 1, :second => 2, :third => 3, :fourth => 4, :fifth => 5,
|
|
183
|
+
:sixth => 6, :seventh => 7, :eighth => 8, :ninth => 9, :tenth => 10
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Suprdate
|
|
2
|
+
|
|
3
|
+
# Creates date objects of classes such as Year, Month and Day.
|
|
4
|
+
class Builder
|
|
5
|
+
|
|
6
|
+
attr_accessor :day_factory, :month_factory
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@day_factory = Day
|
|
10
|
+
@month_factory = Month
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Creates an instance of Suprdate::Year.
|
|
14
|
+
def year(value)
|
|
15
|
+
y = Year.new(value)
|
|
16
|
+
y.day_factory = @day_factory
|
|
17
|
+
y.month_factory = @month_factory
|
|
18
|
+
y
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Creates an instance of Suprdate::Month.
|
|
22
|
+
def month(year_value, month_value)
|
|
23
|
+
m = @month_factory.new(year(year_value), month_value)
|
|
24
|
+
m.day_factory = @day_factory
|
|
25
|
+
m
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Creates an instance of Suprdate::Day.
|
|
29
|
+
def day(year_value, month_value, day_value)
|
|
30
|
+
@day_factory.new(month(year_value, month_value), day_value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# An instance of Suprdate::Day representing the current day.
|
|
34
|
+
def today
|
|
35
|
+
time = Time.now
|
|
36
|
+
day(time.year, time.month, time.day)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Creates either an instead of either Suprdate::Year, Suprdate::Month or Suprdate::Day
|
|
40
|
+
# depending on the number of arguments (parts) used.
|
|
41
|
+
def date(*parts)
|
|
42
|
+
unless DATE_NUM_PARTS_RANGE.include?(parts.nitems)
|
|
43
|
+
raise DateConstructionError.invalid_part_count(parts)
|
|
44
|
+
end
|
|
45
|
+
send(UNIT_NUM_PARTS[parts.nitems], *parts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.local_methods # :nodoc:
|
|
49
|
+
(instance_methods - superclass.instance_methods - Kernel.methods)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns the names of the methods that create objects. Each name as a singleton #to_export
|
|
53
|
+
# method that can be used to ascertain the name of the exported version of the method that
|
|
54
|
+
# appears on Suprdate.
|
|
55
|
+
def self.builder_methods
|
|
56
|
+
local_methods.reject { |name| name =~ /_/ }.each do |name|
|
|
57
|
+
def name.to_export() capitalize end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
DEFAULT_BUILDER = Builder.new
|
|
64
|
+
|
|
65
|
+
# Exports the builder_methods on to Suprdate.
|
|
66
|
+
# So that Suprdate::Day() == Suprdate::DEFAULT_BUILDER.day()
|
|
67
|
+
Builder.builder_methods.each do |name|
|
|
68
|
+
define_method(name.to_export) { |*args| DEFAULT_BUILDER.send(name, *args) }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|