calendarium-romanum 0.2.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/bin/calendariumrom +4 -1
  3. data/config/locales/cs.yml +54 -2
  4. data/config/locales/en.yml +64 -14
  5. data/config/locales/es.yml +90 -0
  6. data/config/locales/fr.yml +90 -0
  7. data/config/locales/it.yml +54 -4
  8. data/config/locales/la.yml +52 -2
  9. data/data/README.md +105 -5
  10. data/data/czech-brno-cs.txt +11 -5
  11. data/data/czech-budejovice-cs.txt +11 -5
  12. data/data/czech-cechy-cs.txt +11 -5
  13. data/data/czech-cs.txt +243 -234
  14. data/data/czech-hradec-cs.txt +10 -4
  15. data/data/czech-litomerice-cs.txt +12 -6
  16. data/data/czech-morava-cs.txt +11 -5
  17. data/data/czech-olomouc-cs.txt +9 -3
  18. data/data/czech-ostrava-cs.txt +10 -4
  19. data/data/czech-plzen-cs.txt +10 -4
  20. data/data/czech-praha-cs.txt +10 -3
  21. data/data/universal-en.txt +218 -212
  22. data/data/universal-es.txt +243 -0
  23. data/data/universal-fr.txt +243 -0
  24. data/data/universal-it.txt +218 -212
  25. data/data/universal-la.txt +218 -211
  26. data/lib/calendarium-romanum.rb +30 -18
  27. data/lib/calendarium-romanum/abstract_date.rb +12 -0
  28. data/lib/calendarium-romanum/calendar.rb +210 -48
  29. data/lib/calendarium-romanum/cli.rb +101 -52
  30. data/lib/calendarium-romanum/cr.rb +16 -0
  31. data/lib/calendarium-romanum/data.rb +46 -18
  32. data/lib/calendarium-romanum/day.rb +200 -21
  33. data/lib/calendarium-romanum/enum.rb +24 -5
  34. data/lib/calendarium-romanum/enums.rb +123 -37
  35. data/lib/calendarium-romanum/errors.rb +4 -0
  36. data/lib/calendarium-romanum/ordinalizer.rb +61 -0
  37. data/lib/calendarium-romanum/perpetual_calendar.rb +97 -0
  38. data/lib/calendarium-romanum/rank.rb +43 -6
  39. data/lib/calendarium-romanum/sanctorale.rb +142 -22
  40. data/lib/calendarium-romanum/sanctorale_factory.rb +74 -3
  41. data/lib/calendarium-romanum/sanctorale_loader.rb +176 -0
  42. data/lib/calendarium-romanum/temporale.rb +296 -251
  43. data/lib/calendarium-romanum/temporale/celebration_factory.rb +106 -0
  44. data/lib/calendarium-romanum/temporale/dates.rb +232 -0
  45. data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +37 -0
  46. data/lib/calendarium-romanum/transfers.rb +43 -6
  47. data/lib/calendarium-romanum/util.rb +36 -3
  48. data/lib/calendarium-romanum/version.rb +5 -1
  49. data/spec/abstract_date_spec.rb +11 -3
  50. data/spec/calendar_spec.rb +645 -188
  51. data/spec/celebration_factory_spec.rb +40 -0
  52. data/spec/celebration_spec.rb +67 -0
  53. data/spec/cli_spec.rb +154 -11
  54. data/spec/colour_spec.rb +22 -0
  55. data/spec/data_spec.rb +26 -3
  56. data/spec/date_parser_spec.rb +68 -0
  57. data/spec/date_spec.rb +8 -8
  58. data/spec/dates_spec.rb +73 -0
  59. data/spec/day_spec.rb +151 -0
  60. data/spec/i18n_spec.rb +11 -2
  61. data/spec/ordinalizer_spec.rb +44 -0
  62. data/spec/perpetual_calendar_spec.rb +125 -0
  63. data/spec/rank_spec.rb +42 -7
  64. data/spec/readme_spec.rb +18 -10
  65. data/spec/sanctorale_factory_spec.rb +113 -9
  66. data/spec/sanctorale_loader_spec.rb +229 -0
  67. data/spec/sanctorale_spec.rb +176 -62
  68. data/spec/season_spec.rb +22 -0
  69. data/spec/spec_helper.rb +27 -1
  70. data/spec/temporale_spec.rb +473 -154
  71. data/spec/year_spec.rb +25 -0
  72. metadata +42 -7
  73. data/lib/calendarium-romanum/sanctoraleloader.rb +0 -104
  74. data/spec/sanctoraleloader_spec.rb +0 -171
@@ -0,0 +1,106 @@
1
+ module CalendariumRomanum
2
+ class Temporale
3
+ # Provides factory methods building {Celebration}s
4
+ # for temporale feasts
5
+ class CelebrationFactory
6
+ class << self
7
+ # @yield [Symbol]
8
+ # @return [void, Enumerator]
9
+ def each
10
+ return to_enum(__method__) unless block_given?
11
+
12
+ celebrations.each do |symbol|
13
+ yield public_send(symbol)
14
+ end
15
+ end
16
+
17
+ # @return [Celebration]
18
+ def first_advent_sunday
19
+ Temporale.create_celebration(
20
+ I18n.t('temporale.advent.sunday', week: Ordinalizer.ordinal(1)),
21
+ Ranks::PRIMARY,
22
+ Colours::VIOLET
23
+ )
24
+ end
25
+
26
+ private
27
+
28
+ def celebrations
29
+ @celebrations ||= [:first_advent_sunday]
30
+ end
31
+
32
+ def celebration(symbol, rank, colour = Colours::WHITE, fixed_date: false)
33
+ define_singleton_method(symbol) do
34
+ Temporale.create_celebration(
35
+ proc { I18n.t("temporale.solemnity.#{symbol}") },
36
+ rank,
37
+ colour,
38
+ symbol: symbol,
39
+ date: fixed_date
40
+ )
41
+ end
42
+
43
+ celebrations << symbol
44
+ end
45
+ end
46
+
47
+ # @return [Celebration]
48
+ # @!scope class
49
+ celebration(:nativity, Ranks::PRIMARY, fixed_date: AbstractDate.new(12, 25))
50
+ # @return [Celebration]
51
+ # @!scope class
52
+ celebration(:holy_family, Ranks::FEAST_LORD_GENERAL)
53
+ # @return [Celebration]
54
+ # @!scope class
55
+ celebration(:mother_of_god, Ranks::SOLEMNITY_GENERAL, fixed_date: AbstractDate.new(1, 1))
56
+ # @return [Celebration]
57
+ # @!scope class
58
+ celebration(:epiphany, Ranks::PRIMARY)
59
+ # @return [Celebration]
60
+ # @!scope class
61
+ celebration(:baptism_of_lord, Ranks::FEAST_LORD_GENERAL)
62
+ # @return [Celebration]
63
+ # @!scope class
64
+ celebration(:ash_wednesday, Ranks::PRIMARY, Colours::VIOLET)
65
+ # @return [Celebration]
66
+ # @!scope class
67
+ celebration(:good_friday, Ranks::TRIDUUM, Colours::RED)
68
+ # @return [Celebration]
69
+ # @!scope class
70
+ celebration(:holy_saturday, Ranks::TRIDUUM, Colours::VIOLET)
71
+ # @return [Celebration]
72
+ # @!scope class
73
+ celebration(:palm_sunday, Ranks::PRIMARY, Colours::RED)
74
+ # @return [Celebration]
75
+ # @!scope class
76
+ celebration(:easter_sunday, Ranks::TRIDUUM)
77
+ # @return [Celebration]
78
+ # @!scope class
79
+ celebration(:ascension, Ranks::PRIMARY)
80
+ # @return [Celebration]
81
+ # @!scope class
82
+ celebration(:pentecost, Ranks::PRIMARY, Colours::RED)
83
+ # @return [Celebration]
84
+ # @!scope class
85
+ celebration(:holy_trinity, Ranks::SOLEMNITY_GENERAL)
86
+ # @return [Celebration]
87
+ # @!scope class
88
+ celebration(:corpus_christi, Ranks::SOLEMNITY_GENERAL)
89
+ # @return [Celebration]
90
+ # @!scope class
91
+ celebration(:sacred_heart, Ranks::SOLEMNITY_GENERAL)
92
+ # @return [Celebration]
93
+ # @!scope class
94
+ celebration(:christ_king, Ranks::SOLEMNITY_GENERAL)
95
+ # @return [Celebration]
96
+ # @!scope class
97
+ celebration(:mother_of_church, Ranks::MEMORIAL_GENERAL)
98
+ # @return [Celebration]
99
+ # @!scope class
100
+ celebration(:immaculate_heart, Ranks::MEMORIAL_GENERAL)
101
+ # @return [Celebration]
102
+ # @!scope class
103
+ celebration(:saturday_memorial_bvm, Ranks::MEMORIAL_OPTIONAL)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,232 @@
1
+ module CalendariumRomanum
2
+ class Temporale
3
+ # Provides methods computing dates of movable feasts
4
+ # and utilities for common computations of relative dates
5
+ module Dates
6
+ # (see .nativity)
7
+ def self.first_advent_sunday(year)
8
+ sunday_before(nativity(year)) - 3 * WEEK
9
+ end
10
+
11
+ # @param year [Fixnum] liturgical year
12
+ # @return [Date]
13
+ def self.nativity(year)
14
+ Date.new(year, 12, 25)
15
+ end
16
+
17
+ # (see .nativity)
18
+ def self.holy_family(year)
19
+ xmas = nativity(year)
20
+ if xmas.sunday?
21
+ return Date.new(year, 12, 30)
22
+ else
23
+ sunday_after(xmas)
24
+ end
25
+ end
26
+
27
+ # (see .nativity)
28
+ def self.mother_of_god(year)
29
+ octave_of(nativity(year))
30
+ end
31
+
32
+ # @param year [Fixnum] liturgical year
33
+ # @param sunday [Boolean] transfer to Sunday?
34
+ # @return [Date]
35
+ def self.epiphany(year, sunday: false)
36
+ if sunday
37
+ # GNLYC 7 a)
38
+ return sunday_after(Date.new(year + 1, 1, 1))
39
+ end
40
+
41
+ Date.new(year + 1, 1, 6)
42
+ end
43
+
44
+ # @param year [Fixnum] liturgical year
45
+ # @param epiphany_on_sunday [Boolean] was Epiphany transferred to Sunday?
46
+ # @return [Date]
47
+ def self.baptism_of_lord(year, epiphany_on_sunday: false)
48
+ e = epiphany(year, sunday: epiphany_on_sunday)
49
+ if epiphany_on_sunday
50
+ e + 1
51
+ else
52
+ sunday_after e
53
+ end
54
+ end
55
+
56
+ # (see .nativity)
57
+ def self.ash_wednesday(year)
58
+ easter_sunday(year) - (6 * WEEK + 4)
59
+ end
60
+
61
+ # (see .nativity)
62
+ def self.easter_sunday(year)
63
+ year += 1
64
+
65
+ # algorithm below taken from the 'easter' gem:
66
+ # https://github.com/jrobertson/easter
67
+
68
+ golden_number = (year % 19) + 1
69
+ dominical_number = (year + (year / 4) - (year / 100) + (year / 400)) % 7
70
+ solar_correction = (year - 1600) / 100 - (year - 1600) / 400
71
+ lunar_correction = (((year - 1400) / 100) * 8) / 25
72
+ paschal_full_moon = (3 - 11 * golden_number + solar_correction - lunar_correction) % 30
73
+ dominical_number += 7 until dominical_number > 0
74
+ paschal_full_moon += 30 until paschal_full_moon > 0
75
+ paschal_full_moon -= 1 if (paschal_full_moon == 29) || ((paschal_full_moon == 28) && golden_number > 11)
76
+ difference = (4 - paschal_full_moon - dominical_number) % 7
77
+ difference += 7 if difference < 0
78
+ day_easter = paschal_full_moon + difference + 1
79
+ if day_easter < 11
80
+ # Easter occurs in March.
81
+ return Date.new(year, 3, day_easter + 21)
82
+ else
83
+ # Easter occurs in April.
84
+ return Date.new(year, 4, day_easter - 10)
85
+ end
86
+ end
87
+
88
+ # (see .nativity)
89
+ def self.palm_sunday(year)
90
+ easter_sunday(year) - 7
91
+ end
92
+
93
+ # (see .nativity)
94
+ def self.good_friday(year)
95
+ easter_sunday(year) - 2
96
+ end
97
+
98
+ # (see .nativity)
99
+ def self.holy_saturday(year)
100
+ easter_sunday(year) - 1
101
+ end
102
+
103
+ # (see .epiphany)
104
+ def self.ascension(year, sunday: false)
105
+ if sunday
106
+ # GNLYC 7 b)
107
+ return easter_sunday(year) + 6 * WEEK
108
+ end
109
+
110
+ pentecost(year) - 10
111
+ end
112
+
113
+ # (see .nativity)
114
+ def self.pentecost(year)
115
+ easter_sunday(year) + 7 * WEEK
116
+ end
117
+
118
+ # (see .nativity)
119
+ def self.holy_trinity(year)
120
+ octave_of(pentecost(year))
121
+ end
122
+
123
+ # (see .epiphany)
124
+ def self.corpus_christi(year, sunday: false)
125
+ if sunday
126
+ # GNLYC 7 c)
127
+ return holy_trinity(year) + WEEK
128
+ end
129
+
130
+ holy_trinity(year) + 4
131
+ end
132
+
133
+ # (see .nativity)
134
+ def self.sacred_heart(year)
135
+ corpus_christi(year) + 8
136
+ end
137
+
138
+ # (see .nativity)
139
+ def self.mother_of_church(year)
140
+ pentecost(year) + 1
141
+ end
142
+
143
+ # (see .nativity)
144
+ def self.immaculate_heart(year)
145
+ pentecost(year) + 20
146
+ end
147
+
148
+ # (see .nativity)
149
+ def self.christ_king(year)
150
+ first_advent_sunday(year + 1) - 7
151
+ end
152
+
153
+ # utility methods
154
+
155
+ # @param weekday [Fixnum]
156
+ # @param date [Date]
157
+ # @return [Date]
158
+ def self.weekday_before(weekday, date)
159
+ if date.wday == weekday
160
+ date - WEEK
161
+ elsif weekday < date.wday
162
+ date - (date.wday - weekday)
163
+ else
164
+ date - (date.wday + WEEK - weekday)
165
+ end
166
+ end
167
+
168
+ # (see .weekday_before)
169
+ def self.weekday_after(weekday, date)
170
+ if date.wday == weekday
171
+ date + WEEK
172
+ elsif weekday > date.wday
173
+ date + (weekday - date.wday)
174
+ else
175
+ date + (WEEK - date.wday + weekday)
176
+ end
177
+ end
178
+
179
+ # @param date [Date]
180
+ # @return [Date]
181
+ def self.octave_of(date)
182
+ date + WEEK
183
+ end
184
+
185
+ class << self
186
+ # @!method sunday_before(date)
187
+ # @param date [Date]
188
+ # @return [Date]
189
+ # @!method monday_before(date)
190
+ # (see .sunday_before)
191
+ # @!method tuesday_before(date)
192
+ # (see .sunday_before)
193
+ # @!method wednesday_before(date)
194
+ # (see .sunday_before)
195
+ # @!method thursday_before(date)
196
+ # (see .sunday_before)
197
+ # @!method friday_before(date)
198
+ # (see .sunday_before)
199
+ # @!method saturday_before(date)
200
+ # (see .sunday_before)
201
+
202
+ # @!method sunday_after(date)
203
+ # @param date [Date]
204
+ # @return [Date]
205
+ # @!method monday_after(date)
206
+ # (see .sunday_after)
207
+ # @!method tuesday_after(date)
208
+ # (see .sunday_after)
209
+ # @!method wednesday_after(date)
210
+ # (see .sunday_after)
211
+ # @!method thursday_after(date)
212
+ # (see .sunday_after)
213
+ # @!method friday_after(date)
214
+ # (see .sunday_after)
215
+ # @!method saturday_after(date)
216
+ # (see .sunday_after)
217
+
218
+ # @api private
219
+ WEEKDAYS = %w(sunday monday tuesday wednesday thursday friday saturday).freeze
220
+ WEEKDAYS.each_with_index do |weekday, weekday_i|
221
+ define_method "#{weekday}_before" do |date|
222
+ send('weekday_before', weekday_i, date)
223
+ end
224
+
225
+ define_method "#{weekday}_after" do |date|
226
+ send('weekday_after', weekday_i, date)
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,37 @@
1
+ module CalendariumRomanum
2
+ class Temporale
3
+ module Extensions
4
+ # {Temporale} extension adding the movable feast
5
+ # of "Christ Eternal Priests",
6
+ # included in some local calendars
7
+ #
8
+ # @example
9
+ # temporale = Temporale.new(2015, extensions: [
10
+ # Temporale::Extensions::ChristEternalPriest
11
+ # ])
12
+ module ChristEternalPriest
13
+ # @yield [Symbol, Celebration]
14
+ # @return [void]
15
+ def self.each_celebration
16
+ yield(
17
+ # symbol refers to the date-computing method
18
+ :christ_eternal_priest,
19
+ Celebration.new(
20
+ proc { I18n.t('temporale.extension.christ_eternal_priest') },
21
+ Ranks::FEAST_PROPER,
22
+ Colours::WHITE
23
+ )
24
+ )
25
+ end
26
+
27
+ # Computes the feast's date
28
+ #
29
+ # @param year [Fixnum] liturgical year
30
+ # @return [Date]
31
+ def self.christ_eternal_priest(year)
32
+ Dates.pentecost(year) + 4
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,12 +1,29 @@
1
1
  module CalendariumRomanum
2
2
 
3
- # Resolves transfers of solemnities.
3
+ # Internal {Calendar} component.
4
+ # Resolves transfers of conflicting solemnities.
5
+ #
6
+ # For any day {Temporale} has a {Celebration}.
7
+ # Often {Sanctorale} has one (or more), too.
8
+ # {Calendar} handles these conflicts, in most cases
9
+ # by throwing away all the proposed {Celebration}s except
10
+ # of the one of highest rank.
11
+ # But when there are two conflicting _solemnities_,
12
+ # one is celebrated on the given day and the less lucky one
13
+ # must be transferred to another day.
14
+ # However, not all days are valid as targets of solemnity transfer.
15
+ #
16
+ # @api private
4
17
  class Transfers
18
+ # @param temporale [Temporale]
19
+ # @param sanctorale [Sanctorale]
5
20
  def initialize(temporale, sanctorale)
6
21
  @transferred = {}
22
+ @temporale = temporale
23
+ @sanctorale = sanctorale
7
24
 
8
25
  dates = sanctorale.solemnities.keys.collect do |abstract_date|
9
- temporale.concretize_abstract_date abstract_date
26
+ concretize_abstract_date abstract_date
10
27
  end.sort
11
28
 
12
29
  dates.each do |date|
@@ -21,24 +38,44 @@ module CalendariumRomanum
21
38
  transfer_to = date
22
39
  begin
23
40
  transfer_to = transfer_to.succ
24
- end until valid_destination?(transfer_to, temporale, sanctorale)
41
+ end until valid_destination?(transfer_to)
25
42
  @transferred[transfer_to] = loser
26
43
  end
27
44
  end
28
45
 
46
+ # Retrieve solemnity for the specified day
47
+ #
48
+ # @param date [Date]
49
+ # @return [Celebration, nil]
29
50
  def get(date)
30
51
  @transferred[date]
31
52
  end
32
53
 
33
54
  private
34
55
 
35
- def valid_destination?(day, temporale, sanctorale)
36
- return false if temporale.get(day).rank >= Ranks::FEAST_PROPER
56
+ def valid_destination?(day)
57
+ return false if @temporale.get(day).rank >= Ranks::FEAST_PROPER
37
58
 
38
- sc = sanctorale.get(day)
59
+ sc = @sanctorale.get(day)
39
60
  return false if sc.size > 0 && sc.first.rank >= Ranks::FEAST_PROPER
40
61
 
41
62
  true
42
63
  end
64
+
65
+ # Converts an AbstractDate to a Date in the given
66
+ # liturgical year.
67
+ # It isn't guaranteed to work well (and probably doesn't work well)
68
+ # for the grey zone of dates between earliest and latest
69
+ # possible date of the first Advent Sunday, but that's no problem
70
+ # as long as there are no sanctorale solemnities in this
71
+ # date range.
72
+ def concretize_abstract_date(abstract_date)
73
+ d = abstract_date.concretize(@temporale.year + 1)
74
+ if @temporale.date_range.include? d
75
+ d
76
+ else
77
+ abstract_date.concretize(@temporale.year)
78
+ end
79
+ end
43
80
  end
44
81
  end