calendarium-romanum 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/calendariumrom +65 -0
- data/lib/calendarium-romanum.rb +13 -0
- data/lib/calendarium-romanum/abstract_date.rb +59 -0
- data/lib/calendarium-romanum/calendar.rb +130 -0
- data/lib/calendarium-romanum/day.rb +59 -0
- data/lib/calendarium-romanum/enums.rb +84 -0
- data/lib/calendarium-romanum/sanctorale.rb +80 -0
- data/lib/calendarium-romanum/sanctoraleloader.rb +100 -0
- data/lib/calendarium-romanum/temporale.rb +382 -0
- data/lib/calendarium-romanum/transfers.rb +44 -0
- data/lib/calendarium-romanum/util.rb +40 -0
- data/spec/abstract_date_spec.rb +45 -0
- data/spec/calendar_spec.rb +217 -0
- data/spec/date_spec.rb +10 -0
- data/spec/rank_spec.rb +30 -0
- data/spec/sanctorale_spec.rb +144 -0
- data/spec/sanctoraleloader_spec.rb +142 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/temporale_spec.rb +342 -0
- metadata +231 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8ee4894a3821935522076c8a8c749be997e243ee
|
4
|
+
data.tar.gz: bbc5bc6e3c9dd24427eac5d9bef2fa51a73122e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d38d06d95abf7994515a338fff2cf2b08970b2a19952eb39132ccc058f4c2e19e6673267461a4fd0e41dd4e95618cc2a8067981ded24c9477f27743bdd8c5f3
|
7
|
+
data.tar.gz: 79b0b9fa0aaaf6f1a2fbec31661b53c15b38fd4b60e23d8585813cbc61c4b3f73dd5a8978d6e52deda6e76be19c2833f73d92ba92ba93fa9e88f7899589e67ca
|
data/bin/calendariumrom
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'calendarium-romanum'
|
5
|
+
require 'log4r'
|
6
|
+
|
7
|
+
module CalendariumRomanum
|
8
|
+
|
9
|
+
class CLI < Thor
|
10
|
+
include CalendariumRomanum::Util
|
11
|
+
|
12
|
+
desc 'errors FILE1, ...', 'finds errors in sanctorale data files'
|
13
|
+
def errors(*files)
|
14
|
+
logger = Log4r::Logger['CalendariumRomanum::SanctoraleLoader']
|
15
|
+
logger.outputters << Log4r::StderrOutputter.new('stderr')
|
16
|
+
|
17
|
+
loader = SanctoraleLoader.new
|
18
|
+
files.each do |path|
|
19
|
+
s = Sanctorale.new
|
20
|
+
loader.load_from_file s, path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'cmp FILE1, FILE2', 'detect differences in rank and colour of corresponding celebrations'
|
25
|
+
def rccompare(a, b)
|
26
|
+
loader = SanctoraleLoader.new
|
27
|
+
sanctorales = []
|
28
|
+
|
29
|
+
[a, b].each do |source|
|
30
|
+
s = Sanctorale.new
|
31
|
+
loader.load_from_file s, source
|
32
|
+
sanctorales << s
|
33
|
+
end
|
34
|
+
|
35
|
+
Year.new(1990).each_day do |d|
|
36
|
+
celebs = sanctorales.collect {|s| s.get d.month, d.day }
|
37
|
+
if celebs.find {|cc| cc.nil? }
|
38
|
+
next
|
39
|
+
end
|
40
|
+
|
41
|
+
celebs[0].each_index do |i|
|
42
|
+
if i >= celebs[1].size
|
43
|
+
break
|
44
|
+
end
|
45
|
+
|
46
|
+
ca = celebs[0][i]
|
47
|
+
cb = celebs[1][i]
|
48
|
+
|
49
|
+
_print_cel = Proc.new {|c| puts "#{c.rank.priority} #{c.colour} | #{c.title}" }
|
50
|
+
|
51
|
+
if ca.rank != cb.rank || ca.colour != cb.colour
|
52
|
+
puts "#{d.month}/#{d.day}"
|
53
|
+
_print_cel.call ca
|
54
|
+
_print_cel.call cb
|
55
|
+
puts
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if __FILE__ == $0
|
64
|
+
CalendariumRomanum::CLI.start ARGV
|
65
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
|
3
|
+
# a date not bound to a particular year
|
4
|
+
class AbstractDate
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
def initialize(month, day)
|
8
|
+
validate! month, day
|
9
|
+
@month = month
|
10
|
+
@day = day
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :month, :day
|
14
|
+
|
15
|
+
def <=>(other)
|
16
|
+
if month != other.month
|
17
|
+
month <=> other.month
|
18
|
+
else
|
19
|
+
day <=> other.day
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
(month * 100 + day).hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def eql?(other)
|
28
|
+
month == other.month && day == other.day
|
29
|
+
end
|
30
|
+
|
31
|
+
def concretize(year)
|
32
|
+
Date.new(year, month, day)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def validate!(month, day)
|
38
|
+
unless month >= 1 && month <= 12
|
39
|
+
raise RangeError.new("Invalid month #{month}.")
|
40
|
+
end
|
41
|
+
|
42
|
+
day_lte = case month
|
43
|
+
when 2
|
44
|
+
28
|
45
|
+
when 1, 3, 5, 7, 8, 10, 12
|
46
|
+
31
|
47
|
+
else
|
48
|
+
30
|
49
|
+
end
|
50
|
+
|
51
|
+
unless day > 0 && day <= 31
|
52
|
+
raise RangeError.new("Invalid day #{day}.")
|
53
|
+
end
|
54
|
+
unless day <= day_lte
|
55
|
+
raise RangeError.new("Invalid day #{day} for month #{month}.")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module CalendariumRomanum
|
5
|
+
|
6
|
+
# Provides complete information concerning a liturgical year,
|
7
|
+
# it's days and celebrations occurring on them.
|
8
|
+
class Calendar
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
# year: Integer
|
13
|
+
# returns a calendar for the liturgical year beginning with
|
14
|
+
# Advent of the specified civil year.
|
15
|
+
def initialize(year, sanctorale=nil)
|
16
|
+
@year = year
|
17
|
+
@temporale = Temporale.new(year)
|
18
|
+
@sanctorale = sanctorale || Sanctorale.new
|
19
|
+
@transferred = Transfers.new(@temporale, @sanctorale)
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def mk_date(*args)
|
24
|
+
ex = TypeError.new('Date, DateTime or three Integers expected')
|
25
|
+
|
26
|
+
if args.size == 3 then
|
27
|
+
args.each do |a|
|
28
|
+
unless a.is_a? Integer
|
29
|
+
raise ex
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return Date.new *args
|
33
|
+
|
34
|
+
elsif args.size == 1 then
|
35
|
+
a = args.first
|
36
|
+
unless a.is_a? Date or a.is_a? DateTime
|
37
|
+
raise ex
|
38
|
+
end
|
39
|
+
return a
|
40
|
+
|
41
|
+
else
|
42
|
+
raise ex
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# creates a Calendar for the liturgical year including given
|
47
|
+
# date
|
48
|
+
def for_day(date, sanctorale=nil)
|
49
|
+
return new(Temporale.liturgical_year(date), sanctorale)
|
50
|
+
end
|
51
|
+
end # class << self
|
52
|
+
|
53
|
+
def_delegators :@temporale, :range_check, :season
|
54
|
+
attr_reader :year
|
55
|
+
attr_reader :temporale
|
56
|
+
attr_reader :sanctorale
|
57
|
+
|
58
|
+
# returns a Calendar for the subsequent year
|
59
|
+
def succ
|
60
|
+
c = Calendar.new @year + 1, @sanctorale
|
61
|
+
return c
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns a Calendar for the previous year
|
65
|
+
def pred
|
66
|
+
c = Calendar.new @year - 1, @sanctorale
|
67
|
+
return c
|
68
|
+
end
|
69
|
+
|
70
|
+
def ==(obj)
|
71
|
+
unless obj.is_a? Calendar
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
|
75
|
+
return year == obj.year
|
76
|
+
end
|
77
|
+
|
78
|
+
# returns filled Day for the specified day
|
79
|
+
def day(*args)
|
80
|
+
if args.size == 2
|
81
|
+
date = Date.new(@year, *args)
|
82
|
+
unless @temporale.date_range.include? date
|
83
|
+
date = Date.new(@year + 1, *args)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
date = self.class.mk_date *args
|
87
|
+
range_check date
|
88
|
+
end
|
89
|
+
|
90
|
+
s = @temporale.season(date)
|
91
|
+
return Day.new(
|
92
|
+
date: date,
|
93
|
+
season: s,
|
94
|
+
season_week: @temporale.season_week(s, date),
|
95
|
+
celebrations: celebrations_for(date)
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sunday lectionary cycle
|
100
|
+
def lectionary
|
101
|
+
LECTIONARY_CYCLES[@year % 3]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Ferial lectionary cycle
|
105
|
+
def ferial_lectionary
|
106
|
+
@year % 2 + 1
|
107
|
+
end
|
108
|
+
|
109
|
+
def celebrations_for(date)
|
110
|
+
tr = @transferred.get(date)
|
111
|
+
return [tr] if tr
|
112
|
+
|
113
|
+
t = @temporale.get date
|
114
|
+
st = @sanctorale.get date
|
115
|
+
|
116
|
+
unless st.empty?
|
117
|
+
if st.first.rank > t.rank
|
118
|
+
if st.first.rank == Ranks::MEMORIAL_OPTIONAL
|
119
|
+
st.unshift t
|
120
|
+
return st
|
121
|
+
else
|
122
|
+
return st
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
return [t]
|
128
|
+
end
|
129
|
+
end # class Calendar
|
130
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module CalendariumRomanum
|
4
|
+
|
5
|
+
# information on one particular day of the liturgical year
|
6
|
+
class Day
|
7
|
+
def initialize(args={})
|
8
|
+
%i(date season season_week celebrations).each do |a|
|
9
|
+
if args.include? a
|
10
|
+
instance_variable_set "@#{a}", args.delete(a)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
unless args.empty?
|
15
|
+
raise ArgumentError.new "Unexpected arguments #{args.keys.join(', ')}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :date
|
20
|
+
|
21
|
+
def weekday
|
22
|
+
date.wday
|
23
|
+
end
|
24
|
+
|
25
|
+
# one of the Seasons (Symbol)
|
26
|
+
attr_reader :season
|
27
|
+
|
28
|
+
# week of the season (Integer)
|
29
|
+
attr_reader :season_week
|
30
|
+
|
31
|
+
# an Array of Celebrations, possibly empty
|
32
|
+
attr_reader :celebrations
|
33
|
+
|
34
|
+
# Celebration of the following day if it has first vespers
|
35
|
+
attr_reader :vespers
|
36
|
+
end
|
37
|
+
|
38
|
+
# information on one particular celebration of the liturgical year
|
39
|
+
# (like a Sunday, feast or memorial);
|
40
|
+
# some days have no (ferial office is used), some have one,
|
41
|
+
# some have more among which one may and may not be chosen
|
42
|
+
class Celebration
|
43
|
+
extend Forwardable
|
44
|
+
|
45
|
+
def initialize(title='', rank=Ranks::FERIAL, colour=Colours::GREEN)
|
46
|
+
@title = title
|
47
|
+
@rank = rank
|
48
|
+
@colour = colour
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :rank
|
52
|
+
def_delegators :@rank, :solemnity?, :feast?, :memorial?
|
53
|
+
|
54
|
+
attr_reader :title
|
55
|
+
|
56
|
+
attr_reader :colour
|
57
|
+
alias_method :color, :colour
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
|
3
|
+
module Seasons
|
4
|
+
ADVENT = :advent
|
5
|
+
CHRISTMAS = :christmas
|
6
|
+
LENT = :lent
|
7
|
+
EASTER = :easter
|
8
|
+
ORDINARY = :ordinary
|
9
|
+
# is Triduum Sacrum a special season? For now I count Friday and Saturday
|
10
|
+
# to the Lent, Sunday to the Easter time
|
11
|
+
end
|
12
|
+
|
13
|
+
LECTIONARY_CYCLES = [:A, :B, :C]
|
14
|
+
|
15
|
+
class Rank < Struct.new(:priority, :desc, :short_desc)
|
16
|
+
include Comparable
|
17
|
+
|
18
|
+
@@instances = {}
|
19
|
+
|
20
|
+
def initialize(*args)
|
21
|
+
super(*args)
|
22
|
+
|
23
|
+
@@instances[self.priority] = self
|
24
|
+
end
|
25
|
+
|
26
|
+
def <=>(b)
|
27
|
+
b.priority <=> self.priority
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :to_f, :priority
|
31
|
+
alias_method :to_s, :desc
|
32
|
+
|
33
|
+
def self.[](priority)
|
34
|
+
@@instances[priority]
|
35
|
+
end
|
36
|
+
|
37
|
+
def solemnity?
|
38
|
+
priority.to_i == 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def feast?
|
42
|
+
priority.to_i == 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def memorial?
|
46
|
+
priority.to_i == 3
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# ranks of celebrations
|
51
|
+
module Ranks
|
52
|
+
# Values are at the same time references to sections
|
53
|
+
# of the Table of Liturgical Days.
|
54
|
+
# The lower value, the higher rank.
|
55
|
+
TRIDUUM = Rank.new 1.1, 'Easter triduum'
|
56
|
+
PRIMARY = Rank.new 1.2, 'Primary liturgical days' # description may not be exact
|
57
|
+
SOLEMNITY_GENERAL = Rank.new 1.3, 'Solemnities in the General Calendar', 'solemnity' # description may not be exact
|
58
|
+
SOLEMNITY_PROPER = Rank.new 1.4, 'Proper solemnities', 'solemnity'
|
59
|
+
|
60
|
+
FEAST_LORD_GENERAL = Rank.new 2.5, 'Feasts of the Lord in the General Calendar', 'feast'
|
61
|
+
SUNDAY_UNPRIVILEGED = Rank.new 2.6, 'Unprivileged Sundays'
|
62
|
+
FEAST_GENERAL = Rank.new 2.7, 'Feasts of saints in the General Calendar', 'feast'
|
63
|
+
FEAST_PROPER = Rank.new 2.8, 'Proper feasts', 'feast'
|
64
|
+
FERIAL_PRIVILEGED = Rank.new 2.9, 'Privileged ferials'
|
65
|
+
|
66
|
+
MEMORIAL_GENERAL = Rank.new 3.10, 'Obligatory memorials in the General Calendar', 'memorial'
|
67
|
+
MEMORIAL_PROPER = Rank.new 3.11, 'Proper obligatory memorials', 'memorial'
|
68
|
+
MEMORIAL_OPTIONAL = Rank.new 3.12, 'Optional memorials', 'optional memorial'
|
69
|
+
FERIAL = Rank.new 3.13, 'Unprivileged ferials', 'ferial'
|
70
|
+
|
71
|
+
def self.[](priority)
|
72
|
+
Rank[priority]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Colours
|
77
|
+
GREEN = :green
|
78
|
+
VIOLET = :violet
|
79
|
+
WHITE = :white
|
80
|
+
RED = :red
|
81
|
+
end
|
82
|
+
|
83
|
+
Colors = Colours
|
84
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
|
3
|
+
# knows the fixed-date celebrations
|
4
|
+
class Sanctorale
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@days = {}
|
8
|
+
|
9
|
+
@solemnities = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :solemnities
|
13
|
+
|
14
|
+
def add(month, day, celebration)
|
15
|
+
date = AbstractDate.new(month, day)
|
16
|
+
unless @days.has_key? date
|
17
|
+
@days[date] = []
|
18
|
+
end
|
19
|
+
|
20
|
+
if celebration.solemnity?
|
21
|
+
@solemnities[date] = celebration
|
22
|
+
end
|
23
|
+
|
24
|
+
@days[date] << celebration
|
25
|
+
end
|
26
|
+
|
27
|
+
# replaces content of the given day by given celebrations
|
28
|
+
def replace(month, day, celebrations)
|
29
|
+
date = AbstractDate.new(month, day)
|
30
|
+
|
31
|
+
if celebrations.first.solemnity?
|
32
|
+
@solemnities[date] = celebrations.first
|
33
|
+
elsif @solemnities.has_key? date
|
34
|
+
@solemnities.delete date
|
35
|
+
end
|
36
|
+
|
37
|
+
@days[date] = celebrations
|
38
|
+
end
|
39
|
+
|
40
|
+
# adds all Celebrations from another instance
|
41
|
+
def update(sanctorale)
|
42
|
+
sanctorale.each_day do |date, celebrations|
|
43
|
+
replace date.month, date.day, celebrations
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns an Array with one or more Celebrations
|
48
|
+
# scheduled for the given day
|
49
|
+
#
|
50
|
+
# expected arguments: Date or two Integers (month, day)
|
51
|
+
def get(*args)
|
52
|
+
if args.size == 1 && args[0].is_a?(Date)
|
53
|
+
month = args[0].month
|
54
|
+
day = args[0].day
|
55
|
+
else
|
56
|
+
month, day = args
|
57
|
+
end
|
58
|
+
|
59
|
+
date = AbstractDate.new(month, day)
|
60
|
+
return @days[date] || []
|
61
|
+
end
|
62
|
+
|
63
|
+
# for each day for which an entry is available
|
64
|
+
# yields an AbstractDate and an Array of Celebrations
|
65
|
+
def each_day
|
66
|
+
@days.each_pair do |date, celebrations|
|
67
|
+
yield date, celebrations
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# returns count of the _days_ with celebrations filled
|
72
|
+
def size
|
73
|
+
@days.size
|
74
|
+
end
|
75
|
+
|
76
|
+
def empty?
|
77
|
+
@days.empty?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|