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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/config/locales/cs.yml +37 -1
  3. data/config/locales/en.yml +37 -1
  4. data/config/locales/it.yml +36 -2
  5. data/config/locales/la.yml +35 -1
  6. data/data/README.md +62 -4
  7. data/data/czech-brno-cs.txt +10 -2
  8. data/data/czech-budejovice-cs.txt +10 -2
  9. data/data/czech-cechy-cs.txt +9 -2
  10. data/data/czech-cs.txt +7 -1
  11. data/data/czech-hradec-cs.txt +10 -2
  12. data/data/czech-litomerice-cs.txt +10 -2
  13. data/data/czech-morava-cs.txt +9 -2
  14. data/data/czech-olomouc-cs.txt +10 -2
  15. data/data/czech-ostrava-cs.txt +10 -2
  16. data/data/czech-plzen-cs.txt +10 -2
  17. data/data/czech-praha-cs.txt +10 -2
  18. data/data/universal-en.txt +4 -1
  19. data/data/universal-it.txt +4 -1
  20. data/data/universal-la.txt +4 -1
  21. data/lib/calendarium-romanum.rb +3 -0
  22. data/lib/calendarium-romanum/calendar.rb +13 -6
  23. data/lib/calendarium-romanum/data.rb +1 -1
  24. data/lib/calendarium-romanum/day.rb +0 -3
  25. data/lib/calendarium-romanum/enums.rb +41 -21
  26. data/lib/calendarium-romanum/ordinalizer.rb +37 -0
  27. data/lib/calendarium-romanum/sanctoraleloader.rb +13 -2
  28. data/lib/calendarium-romanum/temporale.rb +145 -232
  29. data/lib/calendarium-romanum/temporale/dates.rb +151 -0
  30. data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +25 -0
  31. data/lib/calendarium-romanum/transfers.rb +23 -5
  32. data/lib/calendarium-romanum/version.rb +1 -1
  33. data/spec/calendar_spec.rb +72 -19
  34. data/spec/dates_spec.rb +45 -0
  35. data/spec/rank_spec.rb +2 -2
  36. data/spec/readme_spec.rb +11 -9
  37. data/spec/spec_helper.rb +16 -1
  38. data/spec/temporale_spec.rb +252 -126
  39. 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
- temporale.concretize_abstract_date abstract_date
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, temporale, sanctorale)
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, temporale, sanctorale)
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
@@ -1,3 +1,3 @@
1
1
  module CalendariumRomanum
2
- VERSION = '0.2.1'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -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).should == 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).should_not == described_class.new(2010)
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.should eq :B
23
- described_class.new(2013).lectionary.should eq :A
24
- described_class.new(2012).lectionary.should eq :C
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.should eq 1
31
- described_class.new(2013).ferial_lectionary.should eq 2
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)).should eq described_class.new(2013)
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)).should eq described_class.new(2014)
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)).should be_a CR::Day
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)).should be_a CR::Day
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).should be_a CR::Day
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.should eq :advent
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::Sanctorale.new
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 'obligate memorial does suppress ferial' do
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 eq 'Friday of the Passion of the Lord'
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 eq 'Friday of the Passion of the Lord'
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
@@ -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