class CalendariumRomanum::Calendar

Provides complete information concerning a liturgical year, it's days and celebrations occurring on them.

{Calendar}'s business logic is mostly about correctly combining information from {Temporale} and {Sanctorale}.

Constants

EFFECTIVE_FROM

Day when the implemented calendar system became effective

Attributes

sanctorale[R]

@return [Sanctorale]

temporale[R]

@return [Temporale]

transferred[R]

Solemnities transferred to a date different from the usual one due to occurrence with a higher-ranking celebration.

@return [Hash<Date=>Celebration>] @since 0.8.0

year[R]

@return [Integer]

Public Class Methods

for_day(date, *constructor_args) click to toggle source

Creates a new instance for the liturgical year which includes given date

@param date [Date] @param constructor_args

arguments that will be passed to {initialize}

@return [Calendar]

# File lib/calendarium-romanum/calendar.rb, line 94
def for_day(date, *constructor_args)
  new(Temporale.liturgical_year(date), *constructor_args)
end
mk_date(*args) click to toggle source

@api private

# File lib/calendarium-romanum/calendar.rb, line 68
def mk_date(*args)
  ex = TypeError.new('Date, DateTime or three Integers expected')

  if args.size == 3
    args.each do |a|
      raise ex unless a.is_a? Integer
    end
    return Date.new(*args)

  elsif args.size == 1
    a = args.first
    raise ex unless a.is_a? Date
    return a

  else
    raise ex
  end
end
new(year, sanctorale = nil, temporale = nil, vespers: false, transfers: nil) click to toggle source

Returns a calendar for the liturgical year beginning with Advent of the specified civil year.

@overload initialize(year, sanctorale = nil, temporale = nil, vespers: false, transfers: nil)

@param year [Integer]
  Civil year when the liturgical year begins.
@param sanctorale [Sanctorale, nil]
  If not provided, the +Calendar+ will only know celebrations
  of the temporale cycle, no feasts of the saints!
@param temporale [Temporale, nil]
  If not provided, +Temporale+ for the given year with default
  configuration will built.
@param vespers [Boolean] Set to true if you want the +Calendar+ to populate {Day#vespers}
@param transfers [#call, nil]
  Object with the same public interface as the +Transfers+ class (really class,
  not instance!), responsible for handling transfers of conflicting solemnities.
  Only useful for overriding the default solemnity transfer logic with a custom one.

@overload initialize(temporale, sanctorale=nil, vespers: false, transfers: nil)

@param temporale [Temporale]
@param sanctorale [Sanctorale, nil]
@param vespers [Boolean]
@param transfers [#call, nil]
@since 0.8.0

@raise [RangeError]

if +year+ is specified for which the implemented calendar
system wasn't in force
# File lib/calendarium-romanum/calendar.rb, line 44
def initialize(year, sanctorale = nil, temporale = nil, vespers: false, transfers: nil)
  unless year.is_a? Integer
    temporale = year
    year = temporale.year
  end

  if year < (EFFECTIVE_FROM.year - 1)
    raise system_not_effective
  end

  if temporale && temporale.year != year
    raise ArgumentError.new('Temporale year must be the same as year.')
  end

  @year = year
  @sanctorale = sanctorale || Sanctorale.new
  @temporale = temporale || Temporale.new(year)
  @populate_vespers = vespers

  @transferred = (transfers || Transfers).call(@temporale, @sanctorale).freeze
end

Public Instance Methods

==(b) click to toggle source

Two +Calendar+s are equal if they have equal settings (which means that to equal input they return equal data)

# File lib/calendarium-romanum/calendar.rb, line 135
def ==(b)
  b.class == self.class &&
    year == b.year &&
    populates_vespers? == b.populates_vespers? &&
    temporale == b.temporale &&
    sanctorale == b.sanctorale
end
[](args) click to toggle source

Retrieve liturgical calendar information for the specified day or range of days.

@overload [](date)

@param date [Date]
@return [Day]

@overload [](range)

@param range [Range<Date>]
@return [Array<Day>]
# File lib/calendarium-romanum/calendar.rb, line 152
def [](args)
  if args.is_a?(Range)
    args.map {|date| day(date) }
  else
    day(args)
  end
end
day(*args, vespers: false) click to toggle source

Retrieve liturgical calendar information for the specified day

@overload day(date, vespers: false)

@param date [Date]

@overload day(year, month, day, vespers: false)

@param year [Integer]
@param month [Integer]
@param day [Integer]

@param vespers [Boolean]

Set to +true+ in order to get {Day} with {Day#vespers}
populated (overrides instance-wide setting {#populates_vespers?}).

@return [Day] @raise [RangeError]

If a date is specified on which the implemented calendar
system was not yet in force (it became effective during
the liturgical year 1969/1970)
# File lib/calendarium-romanum/calendar.rb, line 176
def day(*args, vespers: false)
  if args.size == 2
    date = Date.new(@year, *args)
    unless @temporale.date_range.include? date
      date = Date.new(@year + 1, *args)
    end
  else
    date = self.class.mk_date(*args)
    range_check date
  end

  if date < EFFECTIVE_FROM
    raise system_not_effective
  end

  celebrations = celebrations_for(date)
  vespers_celebration = nil
  if @populate_vespers || vespers
    begin
      vespers_celebration = first_vespers_on(date, celebrations)
    rescue RangeError
      # there is exactly one possible case when
      # range_check(date) passes and range_check(date + 1) fails:
      vespers_celebration = Temporale::CelebrationFactory.first_advent_sunday
    end
  end

  s = @temporale.season(date)
  Day.new(
    date: date,
    season: s,
    season_week: @temporale.season_week(s, date),
    celebrations: celebrations,
    vespers: vespers_celebration
  )
end
each() { |day(date)| ... } click to toggle source

Iterate over the whole liturgical year, day by day, for each day yield calendar data. If called without a block, returns Enumerator.

@yield [Day] @return [void, Enumerator] @since 0.6.0

# File lib/calendarium-romanum/calendar.rb, line 220
def each
  return to_enum(__method__) unless block_given?

  temporale.date_range
    .each {|date| yield(day(date)) }
end
ferial_lectionary() click to toggle source

Ferial lectionary cycle

@return [1, 2]

# File lib/calendarium-romanum/calendar.rb, line 238
def ferial_lectionary
  @year % 2 + 1
end
freeze() click to toggle source

Freezes the instance.

WARNING: {Temporale} and {Sanctorale} instances passed to the Calendar on initialization will be frozen, too! This is necessary, because a Calendar would not really be frozen were it possible to mutate it's key components.

Calls superclass method
# File lib/calendarium-romanum/calendar.rb, line 248
def freeze
  @temporale.freeze
  @sanctorale.freeze
  super
end
lectionary() click to toggle source

Sunday lectionary cycle

@return [Symbol]

For possible values see {LECTIONARY_CYCLES}
# File lib/calendarium-romanum/calendar.rb, line 231
def lectionary
  LECTIONARY_CYCLES[@year % 3]
end
populates_vespers?() click to toggle source

Do {Day} instances returned by this Calendar have {Day#vespers} populated? @return [Boolean] @since 0.6.0

# File lib/calendarium-romanum/calendar.rb, line 129
def populates_vespers?
  @populate_vespers
end

Private Instance Methods

celebrations_for(date) click to toggle source
# File lib/calendarium-romanum/calendar.rb, line 256
def celebrations_for(date)
  tr = @transferred[date]
  return [tr] if tr

  t = @temporale[date]
  st = @sanctorale[date]

  if date.saturday? &&
     @temporale.season(date) == Seasons::ORDINARY &&
     (st.empty? || st.first.rank == Ranks::MEMORIAL_OPTIONAL) &&
     t.rank <= Ranks::MEMORIAL_OPTIONAL
    st += [Temporale::CelebrationFactory.saturday_memorial_bvm]
  end

  unless st.empty?
    if st.first.rank > t.rank
      if st.first.rank == Ranks::MEMORIAL_OPTIONAL
        return [t] + st
      else
        return st
      end
    elsif t.rank == Ranks::FERIAL_PRIVILEGED && st.first.rank.memorial?
      commemorations = st.collect do |c|
        c.change(rank: Ranks::COMMEMORATION, colour: t.colour)
      end
      return [t] + commemorations
    elsif t.symbol == :immaculate_heart &&
          [Ranks::MEMORIAL_GENERAL, Ranks::MEMORIAL_PROPER].include?(st.first.rank)
      optional_memorials = ([t] + st).collect do |celebration|
        celebration.change rank: Ranks::MEMORIAL_OPTIONAL
      end
      ferial = temporale.send :ferial, date # ugly and evil
      return [ferial] + optional_memorials
    end
  end

  [t]
end
first_vespers_on(date, celebrations) click to toggle source
# File lib/calendarium-romanum/calendar.rb, line 295
def first_vespers_on(date, celebrations)
  tomorrow = date + 1
  tomorrow_celebrations = celebrations_for(tomorrow)

  c = tomorrow_celebrations.first
  if c.rank >= Ranks::SOLEMNITY_PROPER ||
     c.rank == Ranks::SUNDAY_UNPRIVILEGED ||
     (c.rank == Ranks::FEAST_LORD_GENERAL && tomorrow.sunday?)
    if c.symbol == :ash_wednesday || c.symbol == :good_friday
      return nil
    end

    if c.rank > celebrations.first.rank || c.symbol == :easter_sunday
      return c
    end
  end

  nil
end
system_not_effective() click to toggle source
# File lib/calendarium-romanum/calendar.rb, line 315
def system_not_effective
  RangeError.new('Year out of range. Implemented calendar system has been in use only since 1st January 1970.')
end