calendarium-romanum 0.5.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +50 -0
- data/.travis.yml +23 -0
- data/.yardopts +3 -0
- data/Appraisals +67 -0
- data/CHANGELOG.md +488 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +95 -0
- data/README.md +601 -0
- data/Rakefile +27 -0
- data/bin/calendariumrom +3 -0
- data/calendarium-romanum.gemspec +31 -0
- data/config/locales/cs.yml +4 -0
- data/config/locales/en.yml +20 -14
- data/config/locales/es.yml +94 -0
- data/config/locales/fr.yml +6 -0
- data/config/locales/it.yml +6 -0
- data/config/locales/la.yml +6 -0
- data/config/locales/pt.yml +94 -0
- data/data/README.md +70 -24
- data/data/czech-brno-cs.txt +4 -6
- data/data/czech-budejovice-cs.txt +4 -6
- data/data/czech-cechy-cs.txt +4 -5
- data/data/czech-cs.txt +239 -235
- data/data/czech-hradec-cs.txt +3 -5
- data/data/czech-litomerice-cs.txt +5 -7
- data/data/czech-morava-cs.txt +4 -5
- data/data/czech-olomouc-cs.txt +2 -4
- data/data/czech-ostrava-cs.txt +3 -5
- data/data/czech-plzen-cs.txt +3 -5
- data/data/czech-praha-cs.txt +3 -4
- data/data/easter_dates.txt +67 -0
- data/data/universal-1969-la.txt +234 -0
- data/data/universal-en.txt +217 -211
- data/data/universal-es.txt +246 -0
- data/data/universal-fr.txt +217 -210
- data/data/universal-it.txt +217 -211
- data/data/universal-la.txt +217 -212
- data/data/universal-pt.txt +248 -0
- data/doc/data_readme.md +2 -0
- data/doc/images/class_diagram.png +0 -0
- data/doc/images/class_diagram.puml +44 -0
- data/doc/yard_readme.rdoc +76 -0
- data/lib/calendarium-romanum.rb +16 -2
- data/lib/calendarium-romanum/abstract_date.rb +15 -0
- data/lib/calendarium-romanum/calendar.rb +150 -33
- data/lib/calendarium-romanum/cli.rb +80 -100
- data/lib/calendarium-romanum/cli/comparator.rb +83 -0
- data/lib/calendarium-romanum/cli/date_parser.rb +30 -0
- data/lib/calendarium-romanum/cli/dumper.rb +68 -0
- data/lib/calendarium-romanum/cli/helper.rb +23 -0
- data/lib/calendarium-romanum/cli/querier.rb +73 -0
- data/lib/calendarium-romanum/cr.rb +16 -0
- data/lib/calendarium-romanum/data.rb +40 -8
- data/lib/calendarium-romanum/day.rb +187 -32
- data/lib/calendarium-romanum/enum.rb +41 -24
- data/lib/calendarium-romanum/enums.rb +127 -43
- data/lib/calendarium-romanum/errors.rb +1 -1
- data/lib/calendarium-romanum/ordinalizer.rb +10 -1
- data/lib/calendarium-romanum/perpetual_calendar.rb +58 -7
- data/lib/calendarium-romanum/rank.rb +39 -8
- data/lib/calendarium-romanum/rank_predicates.rb +43 -0
- data/lib/calendarium-romanum/sanctorale.rb +213 -23
- data/lib/calendarium-romanum/sanctorale_factory.rb +74 -3
- data/lib/calendarium-romanum/sanctorale_loader.rb +180 -0
- data/lib/calendarium-romanum/sanctorale_writer.rb +124 -0
- data/lib/calendarium-romanum/temporale.rb +222 -42
- data/lib/calendarium-romanum/temporale/celebration_factory.rb +68 -9
- data/lib/calendarium-romanum/temporale/date_helper.rb +85 -0
- data/lib/calendarium-romanum/temporale/dates.rb +52 -59
- data/lib/calendarium-romanum/temporale/easter_table.rb +27 -0
- data/lib/calendarium-romanum/temporale/extensions.rb +15 -0
- data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +16 -3
- data/lib/calendarium-romanum/temporale/extensions/dedication_before_all_saints.rb +73 -0
- data/lib/calendarium-romanum/transfers.rb +84 -24
- data/lib/calendarium-romanum/util.rb +21 -23
- data/lib/calendarium-romanum/version.rb +3 -2
- data/liturgical_law/1969_normae_universales.md +568 -0
- data/liturgical_law/1977_decretum_de_celebratione_baptismatis_domini.md +58 -0
- data/liturgical_law/1990_decretum_de_variatione_inducenda.md +67 -0
- data/liturgical_law/1998_notificatio_de_occurrentia.md +57 -0
- data/liturgical_law/2002_normae_universales.md +946 -0
- data/liturgical_law/2006_notification.md +37 -0
- data/liturgical_law/2012_declarationes.md +38 -0
- data/liturgical_law/2020_dubia_de_calendario_2022.md +100 -0
- data/liturgical_law/README.md +74 -0
- metadata +61 -38
- data/lib/calendarium-romanum/sanctoraleloader.rb +0 -122
- data/spec/abstract_date_spec.rb +0 -62
- data/spec/calendar_spec.rb +0 -559
- data/spec/celebration_factory_spec.rb +0 -16
- data/spec/celebration_spec.rb +0 -43
- data/spec/cli_spec.rb +0 -155
- data/spec/colour_spec.rb +0 -17
- data/spec/data_spec.rb +0 -23
- data/spec/date_parser_spec.rb +0 -68
- data/spec/date_spec.rb +0 -61
- data/spec/dates_spec.rb +0 -45
- data/spec/day_spec.rb +0 -108
- data/spec/enum_spec.rb +0 -51
- data/spec/i18n_spec.rb +0 -58
- data/spec/ordinalizer_spec.rb +0 -36
- data/spec/perpetual_calendar_spec.rb +0 -91
- data/spec/rank_spec.rb +0 -57
- data/spec/readme_spec.rb +0 -56
- data/spec/sanctorale_factory_spec.rb +0 -42
- data/spec/sanctorale_spec.rb +0 -191
- data/spec/sanctoraleloader_spec.rb +0 -176
- data/spec/season_spec.rb +0 -17
- data/spec/spec_helper.rb +0 -46
- data/spec/temporale_spec.rb +0 -572
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module CalendariumRomanum
|
4
|
+
class CLI
|
5
|
+
# Compares two sanctorale data files, reports differences.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Comparator
|
9
|
+
include Helper
|
10
|
+
|
11
|
+
SUPPORTED_PROPERTIES = %i(rank colour symbol title)
|
12
|
+
DEFAULT_PROPERTIES = SUPPORTED_PROPERTIES - %i(title)
|
13
|
+
|
14
|
+
def initialize(properties = DEFAULT_PROPERTIES)
|
15
|
+
unless Set.new(properties) <= Set.new(SUPPORTED_PROPERTIES)
|
16
|
+
raise ArgumentError.new("Unsupported properties specified: #{properties} Only #{SUPPORTED_PROPERTIES} are supported")
|
17
|
+
end
|
18
|
+
|
19
|
+
@properties = properties
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(path_a, path_b)
|
23
|
+
paths = [path_a, path_b]
|
24
|
+
sanctoralia = paths.collect {|source| sanctorale_from_path source }
|
25
|
+
names = paths.collect {|source| File.basename source }
|
26
|
+
|
27
|
+
differences_found = false
|
28
|
+
all_possible_dates.each do |d|
|
29
|
+
a, b = sanctoralia.collect {|sanctorale| sanctorale[d] }
|
30
|
+
|
31
|
+
0.upto([a.size, b.size].max - 1) do |i|
|
32
|
+
ca = a[i]
|
33
|
+
cb = b[i]
|
34
|
+
compared = [ca, cb]
|
35
|
+
|
36
|
+
if compared.index(&:nil?)
|
37
|
+
differences_found = true
|
38
|
+
notnili = compared.index {|c| !c.nil? }
|
39
|
+
|
40
|
+
print date(d)
|
41
|
+
puts " only in #{names[notnili]}:"
|
42
|
+
puts celebration(compared[notnili])
|
43
|
+
puts
|
44
|
+
next
|
45
|
+
end
|
46
|
+
|
47
|
+
differences = @properties.select do |property|
|
48
|
+
ca.public_send(property) != cb.public_send(property)
|
49
|
+
end
|
50
|
+
|
51
|
+
next if differences.empty?
|
52
|
+
differences_found = true
|
53
|
+
print date(d)
|
54
|
+
puts " differs in #{differences.join(', ')}"
|
55
|
+
puts celebration(ca)
|
56
|
+
puts celebration(cb)
|
57
|
+
puts
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
!differences_found
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def all_possible_dates
|
67
|
+
# a leap year must be chosen in order to iterate over
|
68
|
+
# all possible days of a Sanctorale
|
69
|
+
Util::Year.new(1990).each_day
|
70
|
+
end
|
71
|
+
|
72
|
+
def date(d)
|
73
|
+
"#{d.month}/#{d.day}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def celebration(c)
|
77
|
+
symbol_chunk = c.symbol && "#{c.symbol} | "
|
78
|
+
|
79
|
+
"#{c.rank.priority} #{c.colour.symbol} | #{symbol_chunk}#{c.title}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# @api private
|
4
|
+
class DateParser
|
5
|
+
def self.parse(date_str)
|
6
|
+
/(?<year>\d{4})([\/-](?<month>\d{1,2})([\/-](?<day>\d{1,2}))?)?/.match(date_str) do |m|
|
7
|
+
date_segments =
|
8
|
+
%i(year month day)
|
9
|
+
.collect {|name| m[name] }
|
10
|
+
.compact
|
11
|
+
.collect(&:to_i)
|
12
|
+
|
13
|
+
build_range(*date_segments)
|
14
|
+
end || raise(ArgumentError.new('Unparseable date'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.build_range(*args)
|
18
|
+
case args.size
|
19
|
+
when 1
|
20
|
+
Util::Year.new(*args)
|
21
|
+
when 2
|
22
|
+
Util::Month.new(*args)
|
23
|
+
else
|
24
|
+
date = Date.new(*args)
|
25
|
+
date..date
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# Produces a condensed text representation of a Calendar, used in regression tests.
|
4
|
+
# Not loaded by default by +require 'calendarium-romanum'+
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Dumper
|
8
|
+
def initialize(io=STDOUT)
|
9
|
+
@io = io
|
10
|
+
end
|
11
|
+
|
12
|
+
# Dumps +calendar+. If +other_calendars+ are specified, dumps an alternative entry
|
13
|
+
# for any date for which any of +other_calendars+ differs from +calendar+.
|
14
|
+
def call(calendar, *other_calendars)
|
15
|
+
@io.puts "Calendar for liturgical year #{calendar.year}"
|
16
|
+
calendar.each do |day|
|
17
|
+
dump_day(day)
|
18
|
+
|
19
|
+
other_calendars.each do |cal|
|
20
|
+
day2 = cal[day.date]
|
21
|
+
if day2 != day
|
22
|
+
@io.print 'or '
|
23
|
+
dump_day(day2)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Produces the dump used for regression tests for the specified +year+.
|
30
|
+
def regression_tests_dump(year)
|
31
|
+
sanctorale = Data::GENERAL_ROMAN_LATIN.load
|
32
|
+
calendar = Calendar.new(
|
33
|
+
year,
|
34
|
+
sanctorale,
|
35
|
+
vespers: true
|
36
|
+
)
|
37
|
+
calendar_with_transfers = Calendar.new(
|
38
|
+
Temporale.new(year, transfer_to_sunday: Temporale::SUNDAY_TRANSFERABLE_SOLEMNITIES),
|
39
|
+
sanctorale,
|
40
|
+
vespers: true
|
41
|
+
)
|
42
|
+
calendar_with_extensions = Calendar.new(
|
43
|
+
Temporale.new(year, extensions: Temporale::Extensions.all),
|
44
|
+
sanctorale,
|
45
|
+
vespers: true
|
46
|
+
)
|
47
|
+
|
48
|
+
I18n.with_locale(:la) do
|
49
|
+
call(
|
50
|
+
calendar,
|
51
|
+
calendar_with_transfers,
|
52
|
+
calendar_with_extensions,
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def dump_day(day)
|
60
|
+
@io.puts [day.date, day.season.symbol, day.season_week, !day.vespers.nil?].join(' ')
|
61
|
+
|
62
|
+
day.celebrations.each do |c|
|
63
|
+
@io.puts ['-', c.title.inspect, c.rank.priority, c.colour.symbol, c.symbol, (c.date && "#{c.date.month}/#{c.date.day}"), c.cycle].join(' ')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# Mixin providing helper methods used by multiple CLI-related classes.
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
module Helper
|
7
|
+
def sanctorale_from_path(path)
|
8
|
+
loader = SanctoraleLoader.new
|
9
|
+
|
10
|
+
if path == '-'
|
11
|
+
loader.load(STDIN)
|
12
|
+
else
|
13
|
+
loader.load_from_file(path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def die!(message, code = 1)
|
18
|
+
STDERR.puts message
|
19
|
+
exit code
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# "Queries" a Calendar.
|
4
|
+
# Builds liturgical calendar according to the specified options and
|
5
|
+
# prints calendar entries for the specified period.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Querier
|
9
|
+
include Helper
|
10
|
+
|
11
|
+
def initialize(locale: :en, calendar: 'universal-en')
|
12
|
+
@locale = locale
|
13
|
+
@calendar = calendar
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(date_str = nil)
|
17
|
+
I18n.locale = @locale
|
18
|
+
|
19
|
+
pcal = PerpetualCalendar.new sanctorale: sanctorale
|
20
|
+
|
21
|
+
today = Date.today
|
22
|
+
date_range = today..today
|
23
|
+
|
24
|
+
if date_str
|
25
|
+
begin
|
26
|
+
date_range = DateParser.parse(date_str)
|
27
|
+
rescue ArgumentError
|
28
|
+
die! 'Invalid date.'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
date_range.each do |day|
|
33
|
+
print_single_date(pcal, day)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def print_single_date(calendar, date)
|
40
|
+
day = calendar.day date
|
41
|
+
|
42
|
+
puts date
|
43
|
+
puts "season: #{day.season.name}"
|
44
|
+
puts
|
45
|
+
|
46
|
+
rank_length = day.celebrations.collect {|c| c.rank.short_desc.nil? ? 0 : c.rank.short_desc.size }.max
|
47
|
+
day.celebrations.each do |c|
|
48
|
+
if [Ranks::PRIMARY, Ranks::TRIDUUM].include? c.rank
|
49
|
+
puts c.title
|
50
|
+
elsif !c.rank.short_desc.nil?
|
51
|
+
print c.rank.short_desc.rjust(rank_length)
|
52
|
+
print ' : '
|
53
|
+
puts c.title
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def sanctorale
|
59
|
+
if File.exist?(@calendar)
|
60
|
+
begin
|
61
|
+
sanctorale_from_path(@calendar)
|
62
|
+
rescue CalendariumRomanum::InvalidDataError
|
63
|
+
die! 'Invalid file format.'
|
64
|
+
end
|
65
|
+
elsif data_file = Data[@calendar]
|
66
|
+
data_file.load
|
67
|
+
else
|
68
|
+
die! "Invalid calendar. Either loading a calendar from filesystem did not succeed, \n or a preinstalled calendar was specified which doesn't exist. See subcommand `calendars` for valid options."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'calendarium-romanum'
|
2
|
+
|
3
|
+
# The module name {CalendariumRomanum} is quite long,
|
4
|
+
# hence constant +CR+ is provided as a convenient shortcut.
|
5
|
+
# It is _not_ loaded by +require 'calendarium-romanum'+,
|
6
|
+
# must be required explicitly +require 'calendarium-romanum/cr'+ -
|
7
|
+
# because there's a good chance
|
8
|
+
# that the short constant name clashes with a constant
|
9
|
+
# defined by some other code.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# require 'calendarium-romanum/cr'
|
13
|
+
#
|
14
|
+
# calendar = CR::Calendar.new 2000
|
15
|
+
# @since 0.7.0
|
16
|
+
CR = CalendariumRomanum
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module CalendariumRomanum
|
2
|
-
#
|
3
|
-
|
2
|
+
# Allows easy access to bundled data files
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# sanctorale = CalendariumRomanum::Data::GENERAL_ROMAN_LATIN.load
|
6
|
+
module Data
|
7
|
+
extend Enum
|
4
8
|
|
5
9
|
class SanctoraleFile
|
10
|
+
# This class is not intended to be initialized by client code -
|
11
|
+
# it's sole purpose is to provide functionality for easy
|
12
|
+
# loading of the bundled sanctorale data files.
|
13
|
+
#
|
14
|
+
# @api private
|
6
15
|
def initialize(base_name)
|
7
16
|
@siglum = base_name.sub(/\.txt$/, '')
|
8
17
|
@path = File.expand_path('../../data/' + base_name, File.dirname(__FILE__))
|
@@ -10,19 +19,42 @@ module CalendariumRomanum
|
|
10
19
|
|
11
20
|
attr_reader :siglum, :path
|
12
21
|
|
22
|
+
# Load the data file
|
23
|
+
#
|
24
|
+
# @return [Sanctorale]
|
13
25
|
def load
|
14
|
-
SanctoraleLoader.new.load_from_file(
|
26
|
+
SanctoraleLoader.new.load_from_file(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Load the data file and all it's parents
|
30
|
+
#
|
31
|
+
# @return [Sanctorale]
|
32
|
+
# @since 0.7.0
|
33
|
+
def load_with_parents
|
34
|
+
SanctoraleFactory.load_with_parents(path)
|
15
35
|
end
|
16
36
|
end
|
17
37
|
|
38
|
+
GENERAL_ROMAN_LATIN = SanctoraleFile.new('universal-la.txt')
|
39
|
+
GENERAL_ROMAN_LATIN_1969 = SanctoraleFile.new('universal-1969-la.txt')
|
40
|
+
GENERAL_ROMAN_ENGLISH = SanctoraleFile.new('universal-en.txt')
|
41
|
+
GENERAL_ROMAN_FRENCH = SanctoraleFile.new('universal-fr.txt')
|
42
|
+
GENERAL_ROMAN_ITALIAN = SanctoraleFile.new('universal-it.txt')
|
43
|
+
GENERAL_ROMAN_PORTUGUESE = SanctoraleFile.new('universal-pt.txt')
|
44
|
+
GENERAL_ROMAN_SPANISH = SanctoraleFile.new('universal-es.txt')
|
45
|
+
CZECH = SanctoraleFile.new('czech-cs.txt')
|
46
|
+
|
18
47
|
values(index_by: :siglum) do
|
19
48
|
# only calendars of broader interest have constants defined
|
20
49
|
[
|
21
|
-
GENERAL_ROMAN_LATIN
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
50
|
+
GENERAL_ROMAN_LATIN,
|
51
|
+
GENERAL_ROMAN_LATIN_1969,
|
52
|
+
GENERAL_ROMAN_ENGLISH,
|
53
|
+
GENERAL_ROMAN_FRENCH,
|
54
|
+
GENERAL_ROMAN_ITALIAN,
|
55
|
+
GENERAL_ROMAN_PORTUGUESE,
|
56
|
+
GENERAL_ROMAN_SPANISH,
|
57
|
+
CZECH,
|
26
58
|
] \
|
27
59
|
+
|
28
60
|
%w(
|
@@ -1,9 +1,16 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
1
|
module CalendariumRomanum
|
4
2
|
|
5
|
-
#
|
3
|
+
# Information on one particular day of the liturgical year
|
6
4
|
class Day
|
5
|
+
# Note: despite of all constructor arguments being nullable,
|
6
|
+
# instances returned by {Calendar} always have all of them set,
|
7
|
+
# the only exception being +vespers+.
|
8
|
+
#
|
9
|
+
# @param date [Date, nil]
|
10
|
+
# @param season [Season, nil]
|
11
|
+
# @param season_week [Integer, nil]
|
12
|
+
# @param celebrations [Array<Celebration>, nil]
|
13
|
+
# @param vespers [Celebration, nil]
|
7
14
|
def initialize(date: nil, season: nil, season_week: nil, celebrations: nil, vespers: nil)
|
8
15
|
@date = date
|
9
16
|
@season = season
|
@@ -12,25 +19,50 @@ module CalendariumRomanum
|
|
12
19
|
@vespers = vespers
|
13
20
|
end
|
14
21
|
|
22
|
+
# @return [Date]
|
15
23
|
attr_reader :date
|
16
24
|
|
25
|
+
# Weekday as integer (Sunday is 0)
|
26
|
+
#
|
27
|
+
# @return [Integer]
|
17
28
|
def weekday
|
18
29
|
date.wday
|
19
30
|
end
|
20
31
|
|
21
|
-
#
|
32
|
+
# Weekday as internationalized string
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
# @since 0.7.0
|
36
|
+
def weekday_name
|
37
|
+
I18n.t(date.wday, scope: 'weekday')
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Season]
|
22
41
|
attr_reader :season
|
23
42
|
|
24
|
-
#
|
43
|
+
# Week of the season
|
44
|
+
#
|
45
|
+
# @return [Integer]
|
25
46
|
attr_reader :season_week
|
26
47
|
|
27
|
-
#
|
48
|
+
# List of celebrations for the given day.
|
49
|
+
#
|
50
|
+
# In tests and other "less-standard" situations the array
|
51
|
+
# may be empty, but it's never empty for instances
|
52
|
+
# returned by {Calendar}.
|
53
|
+
#
|
54
|
+
# @return [Array<Celebration>]
|
28
55
|
attr_reader :celebrations
|
29
56
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# Please note that Calendar by default
|
33
|
-
# Vespers, - it's an opt-in feature
|
57
|
+
# {Celebration} whose first Vespers are celebrated
|
58
|
+
# in place of Vespers of the day's {Celebration}(s).
|
59
|
+
# Please note that {Calendar} by default _doesn't_ populate
|
60
|
+
# Vespers, - it's an opt-in feature
|
61
|
+
# (see {Calendar#initialize}, {Calendar#populates_vespers?},
|
62
|
+
# {Calendar#day}).
|
63
|
+
#
|
64
|
+
# @return [Celebration, nil]
|
65
|
+
# @since 0.5.0
|
34
66
|
attr_reader :vespers
|
35
67
|
|
36
68
|
def ==(other)
|
@@ -44,28 +76,97 @@ module CalendariumRomanum
|
|
44
76
|
|
45
77
|
# Are the day's Vespers suppressed in favour of first Vespers
|
46
78
|
# of a Sunday or solemnity?
|
79
|
+
#
|
80
|
+
# @return [Boolean]
|
47
81
|
def vespers_from_following?
|
48
82
|
!vespers.nil?
|
49
83
|
end
|
84
|
+
|
85
|
+
# String representation of the instance listing it's contents.
|
86
|
+
# Intended mostly for debugging purposes.
|
87
|
+
#
|
88
|
+
# @return [String]
|
89
|
+
# @since 0.7.0
|
90
|
+
def to_s
|
91
|
+
celebrations_string = '['
|
92
|
+
celebrations.each do |c|
|
93
|
+
celebrations_string << c.to_s + ', '
|
94
|
+
end
|
95
|
+
celebrations_string = celebrations_string.chomp(', ') << ']'
|
96
|
+
"#<#{self.class.name} @date=#{date} @season=#{season} @season_week=#{season_week} celebrations=#{celebrations_string} vespers=#{vespers.inspect}>"
|
97
|
+
end
|
50
98
|
end
|
51
99
|
|
52
|
-
#
|
100
|
+
# One particular celebration of the liturgical year
|
53
101
|
# (like a Sunday, feast or memorial);
|
54
|
-
# some days have
|
55
|
-
# some have more among which one
|
102
|
+
# some days have one,
|
103
|
+
# some have more among which one is to be chosen
|
56
104
|
class Celebration
|
57
|
-
|
105
|
+
include RankPredicates
|
106
|
+
|
107
|
+
# All arguments can be passed either as positional or keyword arguments.
|
108
|
+
# In case of conflict keyword arguments win.
|
109
|
+
# @example
|
110
|
+
# Celebration.new('Lost title', title: 'Winning title') # will have title 'Winning title'
|
111
|
+
#
|
112
|
+
# @param title [String|Proc]
|
113
|
+
# Celebration title/name.
|
114
|
+
# If a +Proc+ is passed, it is expected not to receive
|
115
|
+
# arguments and to return a +String+.
|
116
|
+
# (Used for celebration titles which have to be
|
117
|
+
# internationalizable - the +Proc+ is called whenever
|
118
|
+
# {#title} is invoked, which allows the value to vary
|
119
|
+
# depending e.g. on state of the +Proc+ or some
|
120
|
+
# global setting - like +I18n.locale+ - it may access.)
|
121
|
+
# @param rank [Rank] Celebration rank
|
122
|
+
# @param colour [Colour] Liturgical colour
|
123
|
+
# @param symbol [Symbol, nil]
|
124
|
+
# Unique machine-readable identifier of the celebration
|
125
|
+
# @param date [AbstractDate, nil]
|
126
|
+
# Normal fixed date of the celebration
|
127
|
+
# @param cycle [:sanctorale, :temporale]
|
128
|
+
# Cycle the celebration belongs to
|
129
|
+
def initialize(title = '', rank = Ranks::FERIAL, colour = Colours::GREEN, symbol = nil, date = nil, cycle = :sanctorale, sunday = false, **kwargs)
|
130
|
+
@title = kwargs.delete(:title) || title
|
131
|
+
@rank = kwargs.delete(:rank) || rank
|
132
|
+
@colour = kwargs.delete(:colour) || kwargs.delete(:color) || colour
|
133
|
+
@symbol = kwargs.delete(:symbol) || symbol
|
134
|
+
@date = kwargs.delete(:date) || date
|
135
|
+
@cycle = kwargs.delete(:cycle) || cycle
|
136
|
+
@sunday = kwargs.delete(:sunday) || sunday
|
137
|
+
|
138
|
+
unless kwargs.empty?
|
139
|
+
raise ArgumentError.new('Unexpected keyword arguments: ' + kwargs.keys.inspect)
|
140
|
+
end
|
141
|
+
|
142
|
+
if @sunday && ![Ranks::SUNDAY_UNPRIVILEGED, Ranks::PRIMARY].include?(@rank)
|
143
|
+
raise ArgumentError.new("Rank #{@rank} cannot be Sunday")
|
144
|
+
end
|
145
|
+
end
|
58
146
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
147
|
+
# Build a new instance using the receiver's attributes
|
148
|
+
# for all properties for which (a non-nil) value was not passed.
|
149
|
+
#
|
150
|
+
# @return [Celebration]
|
151
|
+
# @since 0.5.0
|
152
|
+
def change(title: nil, rank: nil, colour: nil, color: nil, symbol: nil, date: nil, cycle: nil, sunday: nil)
|
153
|
+
self.class.new(
|
154
|
+
title: title || self.title,
|
155
|
+
rank: rank || self.rank,
|
156
|
+
colour: colour || color || self.colour,
|
157
|
+
symbol: symbol || self.symbol,
|
158
|
+
date: date || self.date,
|
159
|
+
cycle: cycle || self.cycle,
|
160
|
+
sunday: sunday || @sunday
|
161
|
+
)
|
64
162
|
end
|
65
163
|
|
164
|
+
# @return [Rank]
|
66
165
|
attr_reader :rank
|
67
|
-
def_delegators :@rank, :solemnity?, :feast?, :memorial?
|
68
166
|
|
167
|
+
# Feast title/name
|
168
|
+
#
|
169
|
+
# @return [String]
|
69
170
|
def title
|
70
171
|
if @title.respond_to? :call
|
71
172
|
@title.call
|
@@ -74,25 +175,79 @@ module CalendariumRomanum
|
|
74
175
|
end
|
75
176
|
end
|
76
177
|
|
178
|
+
# Liturgical colour
|
179
|
+
#
|
180
|
+
# @return [Colour]
|
77
181
|
attr_reader :colour
|
78
182
|
alias color colour
|
79
183
|
|
184
|
+
# Symbol uniquely identifying the celebration
|
185
|
+
#
|
186
|
+
# @return [Symbol, nil]
|
187
|
+
# @since 0.5.0
|
80
188
|
attr_reader :symbol
|
81
189
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
190
|
+
# Usual date of the celebration.
|
191
|
+
#
|
192
|
+
# Only set for celebrations with fixed date.
|
193
|
+
# (Only) In case of solemnities it may happen that
|
194
|
+
# {Celebration#date} differs from {Day#date} due to
|
195
|
+
# transfer of an impeded solemnity.
|
196
|
+
#
|
197
|
+
# @return [AbstractDate, nil]
|
198
|
+
# @since 0.6.0
|
199
|
+
attr_reader :date
|
200
|
+
|
201
|
+
# Describes the celebration as belonging either to the
|
202
|
+
# temporale or sanctorale cycle
|
203
|
+
#
|
204
|
+
# @return [:sanctorale, :temporale]
|
205
|
+
# @since 0.6.0
|
206
|
+
attr_reader :cycle
|
207
|
+
|
208
|
+
def ==(b)
|
209
|
+
self.class == b.class &&
|
210
|
+
title == b.title &&
|
211
|
+
rank == b.rank &&
|
212
|
+
colour == b.colour &&
|
213
|
+
symbol == b.symbol &&
|
214
|
+
date == b.date &&
|
215
|
+
cycle == b.cycle
|
87
216
|
end
|
88
217
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
218
|
+
# Does the celebration belong to the temporale cycle?
|
219
|
+
#
|
220
|
+
# @return [Boolean]
|
221
|
+
# @since 0.6.0
|
222
|
+
def temporale?
|
223
|
+
cycle == :temporale
|
224
|
+
end
|
225
|
+
|
226
|
+
# Does the celebration belong to the sanctorale cycle?
|
227
|
+
#
|
228
|
+
# @return [Boolean]
|
229
|
+
# @since 0.6.0
|
230
|
+
def sanctorale?
|
231
|
+
cycle == :sanctorale
|
232
|
+
end
|
233
|
+
|
234
|
+
# Is the celebration a Sunday?
|
235
|
+
#
|
236
|
+
# Please note that for "privileged Sundays" true is returned, while {Rank#sunday?}
|
237
|
+
# returns false (because not all celebrations of that rank are Sundays).
|
238
|
+
#
|
239
|
+
# @return [Boolean]
|
240
|
+
def sunday?
|
241
|
+
rank.sunday? || @sunday
|
242
|
+
end
|
243
|
+
|
244
|
+
# String representation of the object's contents
|
245
|
+
# (not very pretty, intended mostly for development inspections).
|
246
|
+
#
|
247
|
+
# @return [String]
|
248
|
+
# @since 0.7.0
|
249
|
+
def to_s
|
250
|
+
"#<#{self.class.name} @title=\"#{title}\" @rank=#{rank} @colour=#{colour} symbol=#{symbol.inspect} date=#{date.inspect} cycle=#{cycle.inspect}>"
|
96
251
|
end
|
97
252
|
end
|
98
253
|
end
|