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