calendarium-romanum 0.2.1 → 0.3.0
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 +4 -4
- data/config/locales/cs.yml +37 -1
- data/config/locales/en.yml +37 -1
- data/config/locales/it.yml +36 -2
- data/config/locales/la.yml +35 -1
- data/data/README.md +62 -4
- data/data/czech-brno-cs.txt +10 -2
- data/data/czech-budejovice-cs.txt +10 -2
- data/data/czech-cechy-cs.txt +9 -2
- data/data/czech-cs.txt +7 -1
- data/data/czech-hradec-cs.txt +10 -2
- data/data/czech-litomerice-cs.txt +10 -2
- data/data/czech-morava-cs.txt +9 -2
- data/data/czech-olomouc-cs.txt +10 -2
- data/data/czech-ostrava-cs.txt +10 -2
- data/data/czech-plzen-cs.txt +10 -2
- data/data/czech-praha-cs.txt +10 -2
- data/data/universal-en.txt +4 -1
- data/data/universal-it.txt +4 -1
- data/data/universal-la.txt +4 -1
- data/lib/calendarium-romanum.rb +3 -0
- data/lib/calendarium-romanum/calendar.rb +13 -6
- data/lib/calendarium-romanum/data.rb +1 -1
- data/lib/calendarium-romanum/day.rb +0 -3
- data/lib/calendarium-romanum/enums.rb +41 -21
- data/lib/calendarium-romanum/ordinalizer.rb +37 -0
- data/lib/calendarium-romanum/sanctoraleloader.rb +13 -2
- data/lib/calendarium-romanum/temporale.rb +145 -232
- data/lib/calendarium-romanum/temporale/dates.rb +151 -0
- data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +25 -0
- data/lib/calendarium-romanum/transfers.rb +23 -5
- data/lib/calendarium-romanum/version.rb +1 -1
- data/spec/calendar_spec.rb +72 -19
- data/spec/dates_spec.rb +45 -0
- data/spec/rank_spec.rb +2 -2
- data/spec/readme_spec.rb +11 -9
- data/spec/spec_helper.rb +16 -1
- data/spec/temporale_spec.rb +252 -126
- metadata +19 -1
@@ -0,0 +1,151 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class Temporale
|
3
|
+
# dates of movable feasts
|
4
|
+
module Dates
|
5
|
+
def self.first_advent_sunday(year)
|
6
|
+
sunday_before(nativity(year)) - 3 * Temporale::WEEK
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.nativity(year)
|
10
|
+
Date.new(year, 12, 25)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.holy_family(year)
|
14
|
+
xmas = nativity(year)
|
15
|
+
if xmas.sunday?
|
16
|
+
return Date.new(year, 12, 30)
|
17
|
+
else
|
18
|
+
sunday_after(xmas)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.mother_of_god(year)
|
23
|
+
octave_of(nativity(year))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.epiphany(year)
|
27
|
+
Date.new(year+1, 1, 6)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.baptism_of_lord(year)
|
31
|
+
sunday_after epiphany(year)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.ash_wednesday(year)
|
35
|
+
easter_sunday(year) - (6 * Temporale::WEEK + 4)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.easter_sunday(year)
|
39
|
+
year += 1
|
40
|
+
|
41
|
+
# algorithm below taken from the 'easter' gem:
|
42
|
+
# https://github.com/jrobertson/easter
|
43
|
+
|
44
|
+
golden_number = (year % 19) + 1
|
45
|
+
if year <= 1752 then
|
46
|
+
# Julian calendar
|
47
|
+
dominical_number = (year + (year / 4) + 5) % 7
|
48
|
+
paschal_full_moon = (3 - (11 * golden_number) - 7) % 30
|
49
|
+
else
|
50
|
+
# Gregorian calendar
|
51
|
+
dominical_number = (year + (year / 4) - (year / 100) + (year / 400)) % 7
|
52
|
+
solar_correction = (year - 1600) / 100 - (year - 1600) / 400
|
53
|
+
lunar_correction = (((year - 1400) / 100) * 8) / 25
|
54
|
+
paschal_full_moon = (3 - 11 * golden_number + solar_correction - lunar_correction) % 30
|
55
|
+
end
|
56
|
+
dominical_number += 7 until dominical_number > 0
|
57
|
+
paschal_full_moon += 30 until paschal_full_moon > 0
|
58
|
+
paschal_full_moon -= 1 if paschal_full_moon == 29 or (paschal_full_moon == 28 and golden_number > 11)
|
59
|
+
difference = (4 - paschal_full_moon - dominical_number) % 7
|
60
|
+
difference += 7 if difference < 0
|
61
|
+
day_easter = paschal_full_moon + difference + 1
|
62
|
+
if day_easter < 11 then
|
63
|
+
# Easter occurs in March.
|
64
|
+
return Date.new(y=year, m=3, d=day_easter + 21)
|
65
|
+
else
|
66
|
+
# Easter occurs in April.
|
67
|
+
return Date.new(y=year, m=4, d=day_easter - 10)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.palm_sunday(year)
|
72
|
+
easter_sunday(year) - 7
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.good_friday(year)
|
76
|
+
easter_sunday(year) - 2
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.holy_saturday(year)
|
80
|
+
easter_sunday(year) - 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.ascension(year)
|
84
|
+
pentecost(year) - 10
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.pentecost(year)
|
88
|
+
easter_sunday(year) + 7 * Temporale::WEEK
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.holy_trinity(year)
|
92
|
+
octave_of(pentecost(year))
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.body_blood(year)
|
96
|
+
holy_trinity(year) + 4
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.sacred_heart(year)
|
100
|
+
body_blood(year) + 8
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.immaculate_heart(year)
|
104
|
+
pentecost(year) + 20
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.christ_king(year)
|
108
|
+
first_advent_sunday(year + 1) - 7
|
109
|
+
end
|
110
|
+
|
111
|
+
# utility methods
|
112
|
+
|
113
|
+
def self.weekday_before(weekday, date)
|
114
|
+
if date.wday == weekday then
|
115
|
+
return date - Temporale::WEEK
|
116
|
+
elsif weekday < date.wday
|
117
|
+
return date - (date.wday - weekday)
|
118
|
+
else
|
119
|
+
return date - (date.wday + Temporale::WEEK - weekday)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.weekday_after(weekday, date)
|
124
|
+
if date.wday == weekday then
|
125
|
+
return date + Temporale::WEEK
|
126
|
+
elsif weekday > date.wday
|
127
|
+
return date + (weekday - date.wday)
|
128
|
+
else
|
129
|
+
return date + (Temporale::WEEK - date.wday + weekday)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.octave_of(date)
|
134
|
+
date + Temporale::WEEK
|
135
|
+
end
|
136
|
+
|
137
|
+
class << self
|
138
|
+
WEEKDAYS = %w{sunday monday tuesday wednesday thursday friday saturday}
|
139
|
+
WEEKDAYS.each_with_index do |weekday, weekday_i|
|
140
|
+
define_method "#{weekday}_before" do |date|
|
141
|
+
send('weekday_before', weekday_i, date)
|
142
|
+
end
|
143
|
+
|
144
|
+
define_method "#{weekday}_after" do |date|
|
145
|
+
send('weekday_after', weekday_i, date)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class Temporale
|
3
|
+
module Extensions
|
4
|
+
# Temporale extension adding feast of Christ Eternal Priests,
|
5
|
+
# included in some local calendars
|
6
|
+
module ChristEternalPriest
|
7
|
+
def self.included(mod)
|
8
|
+
mod.add_celebration(
|
9
|
+
:christ_eternal_priest,
|
10
|
+
Celebration.new(
|
11
|
+
proc { I18n.t('temporale.extension.christ_eternal_priest') },
|
12
|
+
Ranks::FEAST_PROPER,
|
13
|
+
Colours::WHITE
|
14
|
+
)
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
# method computing date
|
19
|
+
def christ_eternal_priest
|
20
|
+
pentecost + 4
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -4,9 +4,11 @@ module CalendariumRomanum
|
|
4
4
|
class Transfers
|
5
5
|
def initialize(temporale, sanctorale)
|
6
6
|
@transferred = {}
|
7
|
+
@temporale = temporale
|
8
|
+
@sanctorale = sanctorale
|
7
9
|
|
8
10
|
dates = sanctorale.solemnities.keys.collect do |abstract_date|
|
9
|
-
|
11
|
+
concretize_abstract_date abstract_date
|
10
12
|
end.sort
|
11
13
|
|
12
14
|
dates.each do |date|
|
@@ -21,7 +23,7 @@ module CalendariumRomanum
|
|
21
23
|
transfer_to = date
|
22
24
|
begin
|
23
25
|
transfer_to = transfer_to.succ
|
24
|
-
end until valid_destination?(transfer_to
|
26
|
+
end until valid_destination?(transfer_to)
|
25
27
|
@transferred[transfer_to] = loser
|
26
28
|
end
|
27
29
|
end
|
@@ -32,13 +34,29 @@ module CalendariumRomanum
|
|
32
34
|
|
33
35
|
private
|
34
36
|
|
35
|
-
def valid_destination?(day
|
36
|
-
return false if temporale.get(day).rank >= Ranks::FEAST_PROPER
|
37
|
+
def valid_destination?(day)
|
38
|
+
return false if @temporale.get(day).rank >= Ranks::FEAST_PROPER
|
37
39
|
|
38
|
-
sc = sanctorale.get(day)
|
40
|
+
sc = @sanctorale.get(day)
|
39
41
|
return false if sc.size > 0 && sc.first.rank >= Ranks::FEAST_PROPER
|
40
42
|
|
41
43
|
true
|
42
44
|
end
|
45
|
+
|
46
|
+
# Converts an AbstractDate to a Date in the given
|
47
|
+
# liturgical year.
|
48
|
+
# It isn't guaranteed to work well (and probably doesn't work well)
|
49
|
+
# for the grey zone of dates between earliest and latest
|
50
|
+
# possible date of the first Advent Sunday, but that's no problem
|
51
|
+
# as long as there are no sanctorale solemnities in this
|
52
|
+
# date range.
|
53
|
+
def concretize_abstract_date(abstract_date)
|
54
|
+
d = abstract_date.concretize(@temporale.year + 1)
|
55
|
+
if @temporale.date_range.include? d
|
56
|
+
d
|
57
|
+
else
|
58
|
+
abstract_date.concretize(@temporale.year)
|
59
|
+
end
|
60
|
+
end
|
43
61
|
end
|
44
62
|
end
|
data/spec/calendar_spec.rb
CHANGED
@@ -9,36 +9,36 @@ describe CR::Calendar do
|
|
9
9
|
|
10
10
|
describe '#==' do
|
11
11
|
it 'considers calendars with the same year same' do
|
12
|
-
described_class.new(2014)
|
12
|
+
expect(described_class.new(2014) == described_class.new(2014)).to be true
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'considers calendars with different year different' do
|
16
|
-
described_class.new(2014)
|
16
|
+
expect(described_class.new(2014) == described_class.new(2010)).to be false
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
describe '#lectionary' do
|
21
21
|
it 'detects correctly' do
|
22
|
-
described_class.new(2014).lectionary.
|
23
|
-
described_class.new(2013).lectionary.
|
24
|
-
described_class.new(2012).lectionary.
|
22
|
+
expect(described_class.new(2014).lectionary).to eq :B
|
23
|
+
expect(described_class.new(2013).lectionary).to eq :A
|
24
|
+
expect(described_class.new(2012).lectionary).to eq :C
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
describe '#ferial_lectionary' do
|
29
29
|
it 'detects correctly' do
|
30
|
-
described_class.new(2014).ferial_lectionary.
|
31
|
-
described_class.new(2013).ferial_lectionary.
|
30
|
+
expect(described_class.new(2014).ferial_lectionary).to eq 1
|
31
|
+
expect(described_class.new(2013).ferial_lectionary).to eq 2
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe '.for_day' do
|
36
36
|
it 'continues the previous year\'s calendar in summer' do
|
37
|
-
described_class.for_day(Date.new(2014, 6, 9)).
|
37
|
+
expect(described_class.for_day(Date.new(2014, 6, 9))).to eq described_class.new(2013)
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'provides the current year\'s calendar in December' do
|
41
|
-
described_class.for_day(Date.new(2014, 12, 20)).
|
41
|
+
expect(described_class.for_day(Date.new(2014, 12, 20))).to eq described_class.new(2014)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -46,19 +46,19 @@ describe CR::Calendar do
|
|
46
46
|
describe 'received arguments' do
|
47
47
|
describe 'Date' do
|
48
48
|
it 'returns a Day' do
|
49
|
-
@c.day(Date.new(2013, 12, 10)).
|
49
|
+
expect(@c.day(Date.new(2013, 12, 10))).to be_a CR::Day
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
describe 'DateTime' do
|
54
54
|
it 'returns a Day' do
|
55
|
-
@c.day(DateTime.new(2013, 12, 10, 12, 10, 0)).
|
55
|
+
expect(@c.day(DateTime.new(2013, 12, 10, 12, 10, 0))).to be_a CR::Day
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
describe 'three Integers' do
|
60
60
|
it 'returns a Day' do
|
61
|
-
@c.day(2013, 12, 10).
|
61
|
+
expect(@c.day(2013, 12, 10)).to be_a CR::Day
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -78,6 +78,24 @@ describe CR::Calendar do
|
|
78
78
|
expect(day.date).to eq Date.new(2014, 4, 10)
|
79
79
|
end
|
80
80
|
end
|
81
|
+
|
82
|
+
describe 'invalid' do
|
83
|
+
describe 'absolutely' do
|
84
|
+
it 'fails' do
|
85
|
+
expect do
|
86
|
+
day = @c.day(0, 34)
|
87
|
+
end.to raise_exception(ArgumentError, 'invalid date')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'for the given year' do
|
92
|
+
it 'fails' do
|
93
|
+
expect do
|
94
|
+
day = @c.day(2, 29)
|
95
|
+
end.to raise_exception(ArgumentError, 'invalid date')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
81
99
|
end
|
82
100
|
end
|
83
101
|
|
@@ -88,7 +106,7 @@ describe CR::Calendar do
|
|
88
106
|
describe 'temporale features' do
|
89
107
|
describe 'season' do
|
90
108
|
it 'detects Advent correctly' do
|
91
|
-
@c.day(2013, 12, 10).season.
|
109
|
+
expect(@c.day(2013, 12, 10).season).to eq CR::Seasons::ADVENT
|
92
110
|
end
|
93
111
|
end
|
94
112
|
|
@@ -188,9 +206,7 @@ describe CR::Calendar do
|
|
188
206
|
|
189
207
|
describe 'Temporale x Sanctorale resolution' do
|
190
208
|
before :all do
|
191
|
-
@s = CR::
|
192
|
-
loader = CR::SanctoraleLoader.new
|
193
|
-
loader.load_from_file(File.join(File.dirname(__FILE__), '..', 'data', 'universal-en.txt'), @s)
|
209
|
+
@s = CR::Data::GENERAL_ROMAN_ENGLISH.load
|
194
210
|
@c = described_class.new 2013, @s
|
195
211
|
end
|
196
212
|
|
@@ -217,13 +233,22 @@ describe CR::Calendar do
|
|
217
233
|
expect(d.celebrations[1].title).to include 'Lellis'
|
218
234
|
end
|
219
235
|
|
220
|
-
it '
|
236
|
+
it 'obligatory memorial does suppress ferial' do
|
221
237
|
d = @c.day(1, 17)
|
222
238
|
expect(d.celebrations.size).to eq 1
|
223
239
|
|
224
240
|
expect(d.celebrations[0].rank).to eq CR::Ranks::MEMORIAL_GENERAL
|
225
241
|
end
|
226
242
|
|
243
|
+
it 'memorial in Lent becomes mere commemoration' do
|
244
|
+
d = @c.day(4, 2)
|
245
|
+
expect(d.celebrations.size).to eq 2
|
246
|
+
|
247
|
+
comm = d.celebrations[1]
|
248
|
+
expect(comm.rank).to eq CR::Ranks::COMMEMORATION
|
249
|
+
expect(comm.title).to eq 'Saint Francis of Paola, hermit'
|
250
|
+
end
|
251
|
+
|
227
252
|
it 'Sunday suppresses feast' do
|
228
253
|
san = CR::Sanctorale.new
|
229
254
|
|
@@ -251,7 +276,7 @@ describe CR::Calendar do
|
|
251
276
|
celebs = c.day(d).celebrations
|
252
277
|
expect(celebs.size).to eq 1
|
253
278
|
expect(celebs[0].rank).to eq CR::Ranks::TRIDUUM
|
254
|
-
expect(celebs[0].title).to
|
279
|
+
expect(celebs[0].title).to have_translation 'Friday of the Passion of the Lord'
|
255
280
|
|
256
281
|
# it is transferred on a day after the Easter octave
|
257
282
|
d = c.temporale.easter_sunday + 8
|
@@ -269,7 +294,7 @@ describe CR::Calendar do
|
|
269
294
|
celebs = c.day(d).celebrations
|
270
295
|
expect(celebs.size).to eq 1
|
271
296
|
expect(celebs[0].rank).to eq CR::Ranks::TRIDUUM
|
272
|
-
expect(celebs[0].title).to
|
297
|
+
expect(celebs[0].title).to have_translation 'Friday of the Passion of the Lord'
|
273
298
|
|
274
299
|
# it is transferred on a day after the Easter octave
|
275
300
|
d = c.temporale.easter_sunday + 8
|
@@ -286,6 +311,20 @@ describe CR::Calendar do
|
|
286
311
|
expect(new_cal.year).to eq(@c.year - 1)
|
287
312
|
expect(new_cal.sanctorale).to eq (@c.sanctorale)
|
288
313
|
end
|
314
|
+
|
315
|
+
it 'preserves sanctorale' do
|
316
|
+
sanctorale = CR::Sanctorale.new
|
317
|
+
cal = described_class.new(2000, sanctorale)
|
318
|
+
new_cal = cal.pred
|
319
|
+
expect(new_cal.sanctorale).to be sanctorale
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'preserves temporale class' do
|
323
|
+
t_class = Class.new(CR::Temporale)
|
324
|
+
cal = described_class.new(2000, nil, t_class)
|
325
|
+
new_cal = cal.pred
|
326
|
+
expect(new_cal.temporale).to be_a t_class
|
327
|
+
end
|
289
328
|
end
|
290
329
|
|
291
330
|
describe '#succ' do
|
@@ -294,6 +333,20 @@ describe CR::Calendar do
|
|
294
333
|
expect(new_cal.year).to eq(@c.year + 1)
|
295
334
|
expect(new_cal.sanctorale).to eq (@c.sanctorale)
|
296
335
|
end
|
336
|
+
|
337
|
+
it 'preserves sanctorale' do
|
338
|
+
sanctorale = CR::Sanctorale.new
|
339
|
+
cal = described_class.new(2000, sanctorale)
|
340
|
+
new_cal = cal.succ
|
341
|
+
expect(new_cal.sanctorale).to be sanctorale
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'preserves temporale class' do
|
345
|
+
t_class = Class.new(CR::Temporale)
|
346
|
+
cal = described_class.new(2000, nil, t_class)
|
347
|
+
new_cal = cal.succ
|
348
|
+
expect(new_cal.temporale).to be_a t_class
|
349
|
+
end
|
297
350
|
end
|
298
351
|
end
|
299
352
|
end
|
data/spec/dates_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe CR::Temporale::Dates do
|
4
|
+
let(:today) { Date.new 2014, 3, 16 }
|
5
|
+
|
6
|
+
describe '#weekday_before' do
|
7
|
+
describe 'works well for all 7 weekdays' do
|
8
|
+
[
|
9
|
+
[0, Date.new(2014, 3, 9)],
|
10
|
+
[1, Date.new(2014, 3, 10)],
|
11
|
+
[2, Date.new(2014, 3, 11)],
|
12
|
+
[3, Date.new(2014, 3, 12)],
|
13
|
+
[4, Date.new(2014, 3, 13)],
|
14
|
+
[5, Date.new(2014, 3, 14)],
|
15
|
+
[6, Date.new(2014, 3, 15)],
|
16
|
+
].each do |e|
|
17
|
+
day_num, expected = e
|
18
|
+
it day_num do
|
19
|
+
actual = described_class.weekday_before(day_num, today)
|
20
|
+
expect(actual).to eq expected
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#weekday_after aliases' do
|
27
|
+
describe 'works well for all 7 weekdays' do
|
28
|
+
[
|
29
|
+
[:monday_after, Date.new(2014, 3, 17)],
|
30
|
+
[:tuesday_after, Date.new(2014, 3, 18)],
|
31
|
+
[:wednesday_after, Date.new(2014, 3, 19)],
|
32
|
+
[:thursday_after, Date.new(2014, 3, 20)],
|
33
|
+
[:friday_after, Date.new(2014, 3, 21)],
|
34
|
+
[:saturday_after, Date.new(2014, 3, 22)],
|
35
|
+
[:sunday_after, Date.new(2014, 3, 23)],
|
36
|
+
].each do |e|
|
37
|
+
method, expected = e
|
38
|
+
it method do
|
39
|
+
actual = described_class.public_send(method, today)
|
40
|
+
expect(actual).to eq expected
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|