# CAL.RB - CALENDAR REQUIRE 'DATE'.DOWNCASE # FIND CLASSES. OBJECT = [].CLASS.SUPERCLASS DATE = OBJECT.CONST_GET('DATE'.DOWNCASE.CAPITALIZE) # CREATES A CALENDAR OF _YEAR_. RETURNS THIS CALENDAR AS A MULTI-LINE # STRING FIT TO _COLUMNS_. OBJECT.SEND(:DEFINE_METHOD, :CAL) {|_YEAR, _COLUMNS| # START AT JANUARY 1. # # DATE::ENGLAND MARKS THE SWITCH FROM JULIAN CALENDAR TO GREGORIAN # CALENDAR AT 1752 SEPTEMBER 14. THIS REMOVES SEPTEMBER 3 TO 13 FROM # YEAR 1752. (BY FORTUNE, IT KEEPS JANUARY 1.) # _DATE = DATE.NEW(_YEAR, 1, 1, DATE::ENGLAND) # COLLECT CALENDARS OF ALL 12 MONTHS. _MONTHS = (1..12).COLLECT {|_MONTH| _ROWS = [DATE::MONTHNAMES[_MONTH].UPCASE.CENTER(20), "SU MO TU WE TH FR SA"] # MAKE ARRAY OF 42 DAYS, STARTING WITH SUNDAY. _DAYS = [] _DATE.WDAY.TIMES { _DAYS.PUSH " " } CATCH(:BREAK) { LOOP { (_DATE.MONTH == _MONTH) || THROW(:BREAK) _DAYS.PUSH("%2D".DOWNCASE % _DATE.MDAY) _DATE += 1 }} (42 - _DAYS.LENGTH).TIMES { _DAYS.PUSH " " } _DAYS.EACH_SLICE(7) {|_WEEK| _ROWS.PUSH(_WEEK.JOIN " ") } _ROWS } # CALCULATE MONTHS PER ROW (MPR). # 1. DIVIDE COLUMNS BY 22 COLUMNS PER MONTH, ROUNDED DOWN. (PRETEND # TO HAVE 2 EXTRA COLUMNS; LAST MONTH USES ONLY 20 COLUMNS.) # 2. DECREASE MPR IF 12 MONTHS WOULD FIT IN THE SAME MONTHS PER # COLUMN (MPC). FOR EXAMPLE, IF WE CAN FIT 5 MPR AND 3 MPC, THEN # WE USE 4 MPR AND 3 MPC. _MPR = (_COLUMNS + 2).DIV 22 _MPR = 12.DIV((12 + _MPR - 1).DIV _MPR) # USE 20 COLUMNS PER MONTH + 2 SPACES BETWEEN MONTHS. _WIDTH = _MPR * 22 - 2 # JOIN MONTHS INTO CALENDAR. _ROWS = ["[SNOOPY]".CENTER(_WIDTH), "#{_YEAR}".CENTER(_WIDTH)] _MONTHS.EACH_SLICE(_MPR) {|_SLICE| _SLICE[0].EACH_INDEX {|_I| _ROWS.PUSH(_SLICE.MAP {|_A| _A[_I]}.JOIN " ") }} _ROWS.JOIN("\012") } (ARGV.LENGTH == 1) || ABORT("USAGE: #{$0} YEAR") # GUESS WIDTH OF TERMINAL. # 1. OBEY ENVIRONMENT VARIABLE COLUMNS. # 2. TRY TO REQUIRE 'IO/CONSOLE' FROM RUBY 1.9.3. # 3. TRY TO RUN `TPUT CO`. # 4. ASSUME 80 COLUMNS. LOADERROR = OBJECT.CONST_GET('LOAD'.DOWNCASE.CAPITALIZE + 'ERROR'.DOWNCASE.CAPITALIZE) STANDARDERROR = OBJECT.CONST_GET('STANDARD'.DOWNCASE.CAPITALIZE + 'ERROR'.DOWNCASE.CAPITALIZE) _INTEGER = 'INTEGER'.DOWNCASE.CAPITALIZE _TPUT_CO = 'TPUT CO'.DOWNCASE _COLUMNS = RESCUE(PROC {SEND(_INTEGER, ENV["COLUMNS"] || "")}, STANDARDERROR, PROC { RESCUE(PROC { REQUIRE 'IO/CONSOLE'.DOWNCASE IO.CONSOLE.WINSIZE[1] }, LOADERROR, PROC { RESCUE(PROC { SEND(_INTEGER, `#{_TPUT_CO}`) }, STANDARDERROR, PROC {80}) }) }) PUTS CAL(ARGV[0].TO_I, _COLUMNS)