lib/third_base/date.rb in third_base-1.2.0 vs lib/third_base/date.rb in third_base-1.3.0

- old
+ new

@@ -84,16 +84,15 @@ STRPTIME_PROC_y = proc{|h,x| h[:year] = two_digit_year(x)} STRPTIME_PROC_Y = proc{|h,x| h[:year] = x.to_i} UNIXEPOCH = 2440588 - # Public Class Methods - class << self alias new! new end + module ClassMethods # Add a parser to the parser type. Arguments: # * type - The parser type to which to add the parser, should be a Symbol. # * pattern - Can be either a Regexp or String: # * String - A strptime parser regular expression is created using pattern as the format string. # If a block is given, it is used. If no block is given, the parser will @@ -102,11 +101,11 @@ # or an error is raised. # # The block, if provided, should take a single MatchData argument. It should return # nil if it cannot successfully parse the string, an instance of this class, or a hash of # values to be passed to new!. - def self.add_parser(type, pattern, &block) + def add_parser(type, pattern, &block) if pattern.is_a?(String) pattern, blk = strptime_pattern_and_block(pattern) block ||= blk else raise(ArgumentError, 'must provide block for Regexp parser') unless block_given? @@ -115,47 +114,47 @@ end # Add a parser type to the list of parser types. # Should be used if you want to add your own parser # types. - def self.add_parser_type(type) + def add_parser_type(type) parser_hash[type] ||= [] end # Returns a new Date with the given year, month, and day. - def self.civil(year, mon, day) + def civil(year, mon, day) new!(:civil=>[year, mon, day]) end # Returns a new Date with the given commercial week year, # commercial week, and commercial week day. - def self.commercial(cwyear, cweek, cwday=5) + def commercial(cwyear, cweek, cwday=5) new!(:commercial=>[cwyear, cweek, cwday]) end # Returns a new Date with the given julian date. - def self.jd(j) + def jd(j) new!(:jd=>j) end # Calls civil with the given arguments. - def self.new(*args) + def new(*args) civil(*args) end # Returns a new Date with the given year and day of year. - def self.ordinal(year, yday) + def ordinal(year, yday) new!(:ordinal=>[year, yday]) end # Parses the given string and returns a Date. Raises an ArgumentError if no # parser can correctly parse the date. Takes the following options: # # * :parser_types : an array of parser types to use, # overriding the default or the ones specified by # use_parsers. - def self.parse(str, opts={}) + def parse(str, opts={}) s = str.strip parsers(opts[:parser_types]) do |pattern, block| if m = pattern.match(s) if res = block.call(m) return res.is_a?(Hash) ? new!(res) : res @@ -164,11 +163,11 @@ end raise ArgumentError, 'invalid date' end # Reset the parsers, parser types, and order of parsers used to the default. - def self.reset_parsers! + def reset_parsers! parser_hash.clear default_parser_hash.each do |type, parsers| add_parser_type(type) parsers.reverse.each do |re, parser| add_parser(type, re, &parser) @@ -177,43 +176,43 @@ use_parsers(*default_parser_list) end # Parse the string using the provided format (or the default format). # Raises an ArgumentError if the format does not match the string. - def self.strptime(str, fmt=strptime_default) + def strptime(str, fmt=strptime_default) pattern, block = strptime_pattern_and_block(fmt) s = str.strip if m = pattern.match(s) block.call(m) else raise ArgumentError, 'invalid date' end end # Returns a date with the current year, month, and date. - def self.today + def today t = Time.now civil(t.year, t.mon, t.day) end # Set the order of parser types to use to the given parser types. - def self.use_parsers(*parsers) + def use_parsers(*parsers) parser_list.replace(parsers) end - # Private Class Methods + private - def self._expand_strptime_format(v) + def _expand_strptime_format(v) case v when '%D', '%x' then '%m/%d/%y' when '%F' then '%Y-%m-%d' when '%v' then '%e-%b-%Y' else v end end - def self._strptime_part(v) + def _strptime_part(v) case v when 'A' then [FULL_DAYNAME_RE_PATTERN, STRPTIME_PROC_A] when 'a' then [ABBR_DAYNAME_RE_PATTERN, STRPTIME_PROC_A] when 'B' then [FULL_MONTHNAME_RE_PATTERN, STRPTIME_PROC_B] when 'b', 'h' then [ABBR_MONTHNAME_RE_PATTERN, STRPTIME_PROC_B] @@ -233,23 +232,23 @@ when '%' then ['%'] else ["%#{v}"] end end - def self.default_parser_hash + def default_parser_hash DEFAULT_PARSERS end - def self.default_parser_list + def default_parser_list DEFAULT_PARSER_LIST end - def self.expand_strptime_format(fmt) + def expand_strptime_format(fmt) fmt.gsub(STRFTIME_RE){|x| _expand_strptime_format(x)} end - def self.new_from_parts(date_hash) + def new_from_parts(date_hash) d = today if date_hash[:year] || date_hash[:yday] || date_hash[:month] || date_hash[:day] if date_hash[:yday] ordinal(date_hash[:year]||d.year, date_hash[:yday]) else @@ -260,37 +259,37 @@ else raise ArgumentError, 'invalid date' end end - def self.parser_hash + def parser_hash PARSERS end - def self.parser_list + def parser_list PARSER_LIST end - def self.parsers(parser_families=nil) + def parsers(parser_families=nil) (parser_families||parser_list).each do |parser_family| parsers_for_family(parser_family) do |pattern, block| yield(pattern, block) end end end - def self.parsers_for_family(parser_family) + def parsers_for_family(parser_family) parser_hash[parser_family].each do |pattern, block| yield(pattern, block) end end - def self.strptime_default + def strptime_default '%Y-%m-%d' end - def self.strptime_pattern_and_block(fmt) + def strptime_pattern_and_block(fmt) blocks = [] pattern = Regexp.escape(expand_strptime_format(fmt)).gsub(STRFTIME_RE) do |x| pat, *blks = _strptime_part(x[1..1]) blocks += blks pat @@ -303,25 +302,24 @@ new_from_parts(h) end [/\A#{pattern}\z/i, block] end - def self.two_digit_year(y) + def two_digit_year(y) y = if y.length == 2 y = y.to_i (y < 69 ? 2000 : 1900) + y else y.to_i end end + end + extend ClassMethods - private_class_method :_expand_strptime_format, :_strptime_part, :default_parser_hash, :default_parser_list, :expand_strptime_format, :new_from_parts, :parser_hash, :parser_list, :parsers, :parsers_for_family, :strptime_default, :strptime_pattern_and_block, :two_digit_year - reset_parsers! - # Public Instance Methods - + module InstanceMethods # Called by Date.new!, Takes a hash with one of the following keys: # # * :civil : should be an array with 3 elements, a year, month, and day # * :commercial : should be an array with 3 elements, a commercial week year, commercial week, and commercial week day # * :jd : should be an integer specifying the julian date @@ -405,12 +403,15 @@ # Dates are equel only if their year, month, and day match. def ==(date) return false unless Date === date year == date.year and mon == date.mon and day == date.day end - alias_method :eql?, :== + def eql?(date) + self == date + end + # If d is a date, only true if it is equal to this date. If d is Numeric, only true if it equals this date's julian date. def ===(d) case d when Numeric then jd == d when Date then self == d @@ -690,7 +691,9 @@ end def yday_from_month_day CUMMULATIVE_MONTH_DAYS[mon] + day + ((month > 2 and leap?) ? 1 : 0) end + end + include InstanceMethods end end