lib/edtf/season.rb in edtf-0.0.9 vs lib/edtf/season.rb in edtf-1.0.0
- old
+ new
@@ -1,8 +1,9 @@
module EDTF
class Season
+ extend Forwardable
SEASONS = Hash[21, :spring, 22, :summer, 23, :autumn, 24, :winter].freeze
CODES = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge(
SEASONS.invert).merge({ :fall => 23 }).freeze
@@ -11,11 +12,10 @@
SOUTHERN = Hash[:autumn, [3,4,5], :winter, [6,7,8], :spring, [9,10,11], :summer, [12,1,2]].freeze
NORTHERN_MONTHS = Hash[*NORTHERN.map { |s,ms| ms.map { |m| [m,s] } }.flatten].freeze
SOUTHERN_MONTHS = Hash[*SOUTHERN.map { |s,ms| ms.map { |m| [m,s] } }.flatten].freeze
- extend Forwardable
include Comparable
include Enumerable
class << self
@@ -24,14 +24,14 @@
end
end
attr_reader :season, :year
- attr_accessor :qualifier
+ attr_accessor :qualifier, :uncertain, :approximate
def_delegators :to_range,
- *Range.instance_methods(false).reject { |m| m.to_s =~ /^(each|eql?|hash)$/ }
+ *Range.instance_methods(false).reject { |m| m.to_s =~ /^(each|min|max|cover?|inspect)$|^\W/ }
SEASONS.each_value do |s|
define_method("#{s}?") { @season == s }
define_method("#{s}!") { @season = s }
end
@@ -42,21 +42,21 @@
[:first, :second, :third, :fourth].zip(SEASONS.values).each do |quarter, season|
alias_method("#{quarter}?", "#{season}?")
alias_method("#{quarter}!", "#{season}!")
end
-
+
def initialize(*arguments)
arguments.flatten!
raise ArgumentError, "wrong number of arguments (#{arguments.length} for 0..3)" if arguments.length > 3
if arguments.length == 1
case arguments[0]
when Date
@year, @season = arguments[0].year, NORTHERN_MONTHS[arguments[0]]
when Symbol, String
- @year, @season = Date.today.year, SEASONS[CODES[arguments[0].intern]]
+ @year, @season = Date.today.year, SEASONS[CODES[arguments[0].to_sym]]
else
self.year = arguments[0]
@season = NORTHERN_MONTHS[Date.today.month]
end
else
@@ -64,13 +64,53 @@
self.season = arguments[1] || NORTHERN_MONTHS[Date.today.month]
self.qualifier = qualifier
end
end
+
+ [:uncertain, :approximate].each do |m|
+
+ define_method("#{m}?") { !!send(m) }
+
+ define_method("#{m}!") do
+ send("#{m}=", true)
+ self
+ end
+ end
+
+ def certain?; !uncertain; end
+ def precise?; !approximate; end
+
+ def certain!
+ @uncertain = false
+ self
+ end
+
+ def precise!
+ @approximate = false
+ end
+
+ # Returns the next season.
+ def succ
+ s = dup
+ s.season = next_season_code
+ s.year = year + 1 if s.first?
+ s
+ end
+
+ # def next(n = 1)
+ # end
+
+ def cover?(other)
+ return false unless other.respond_to?(:day_precision)
+ other = other.day_precision
+ min.day_precision! <= other && other <= max.day_precision!
+ end
+
def each
if block_given?
- to_range(&Proc.new)
+ to_range.each(&Proc.new)
self
else
to_enum
end
end
@@ -86,20 +126,23 @@
def season?; true; end
def qualified?; !!@qualifier; end
- def to_s
+ def edtf
'%04d-%2d%s' % [year, CODES[season], qualified? ? "^#{qualifier}" : '']
end
- alias edtf to_s
+ alias to_s edtf
+
def <=>(other)
case other
when Date
cover?(other) ? 0 : to_date <=> other
+ when Interval, Epoch
+ [min, max] <=> [other.min, other.max]
when Season
[year, month, qualifier] <=> [other.year, other.month, other.qualifier]
else
nil
end
@@ -115,20 +158,33 @@
def to_date
Date.new(year, month, 1)
end
+ alias min to_date
+
+ def max
+ to_date.months_since(2).end_of_month
+ end
+
# Returns a Range that covers the season (a three month period).
def to_range
- d = to_date
- d .. d.months_since(2).end_of_month
+ min .. max
end
-
+
protected
def month
NORTHERN[@season][0]
end
+ def season_code
+ CODES[season]
+ end
+
+ def next_season_code(by = 1)
+ ((season_code + by) % 4) + 20
+ end
+
end
end
\ No newline at end of file