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