calendarium-romanum 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|