calendarium-romanum 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/bin/calendariumrom +2 -61
  3. data/config/locales/cs.yml +40 -0
  4. data/config/locales/en.yml +4 -1
  5. data/config/locales/it.yml +40 -0
  6. data/config/locales/la.yml +40 -0
  7. data/data/README.md +87 -0
  8. data/data/czech-brno-cs.txt +7 -0
  9. data/data/czech-budejovice-cs.txt +8 -0
  10. data/data/czech-cechy-cs.txt +8 -0
  11. data/data/czech-cs.txt +259 -0
  12. data/data/czech-hradec-cs.txt +6 -0
  13. data/data/czech-litomerice-cs.txt +8 -0
  14. data/data/czech-morava-cs.txt +7 -0
  15. data/data/czech-olomouc-cs.txt +4 -0
  16. data/data/czech-ostrava-cs.txt +6 -0
  17. data/data/czech-plzen-cs.txt +6 -0
  18. data/data/czech-praha-cs.txt +4 -0
  19. data/data/universal-en.txt +237 -0
  20. data/data/universal-it.txt +236 -0
  21. data/data/universal-la.txt +236 -0
  22. data/lib/calendarium-romanum.rb +2 -0
  23. data/lib/calendarium-romanum/calendar.rb +4 -1
  24. data/lib/calendarium-romanum/cli.rb +100 -0
  25. data/lib/calendarium-romanum/data.rb +41 -0
  26. data/lib/calendarium-romanum/day.rb +7 -1
  27. data/lib/calendarium-romanum/enum.rb +33 -0
  28. data/lib/calendarium-romanum/enums.rb +43 -35
  29. data/lib/calendarium-romanum/rank.rb +16 -12
  30. data/lib/calendarium-romanum/sanctorale.rb +9 -0
  31. data/lib/calendarium-romanum/sanctoraleloader.rb +8 -8
  32. data/lib/calendarium-romanum/temporale.rb +24 -9
  33. data/lib/calendarium-romanum/version.rb +1 -1
  34. data/spec/calendar_spec.rb +89 -7
  35. data/spec/cli_spec.rb +26 -0
  36. data/spec/data_spec.rb +16 -8
  37. data/spec/date_spec.rb +52 -1
  38. data/spec/enum_spec.rb +51 -0
  39. data/spec/i18n_spec.rb +59 -0
  40. data/spec/readme_spec.rb +50 -0
  41. data/spec/sanctorale_spec.rb +24 -1
  42. data/spec/sanctoraleloader_spec.rb +30 -1
  43. data/spec/temporale_spec.rb +24 -0
  44. metadata +28 -2
@@ -1,48 +1,56 @@
1
1
  module CalendariumRomanum
2
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
3
+ class Seasons < Enum
4
+ values do
5
+ [
6
+ ADVENT = :advent,
7
+ CHRISTMAS = :christmas,
8
+ LENT = :lent,
9
+ EASTER = :easter,
10
+ ORDINARY = :ordinary,
11
+ # is Triduum Sacrum a special season? For now I count Friday and Saturday
12
+ # to the Lent, Sunday to the Easter time
13
+ ]
14
+ end
11
15
  end
12
16
 
13
17
  LECTIONARY_CYCLES = [:A, :B, :C]
14
18
 
15
19
  # ranks of celebrations
16
- module Ranks
17
- # Values are at the same time references to sections
18
- # of the Table of Liturgical Days.
19
- # The lower value, the higher rank.
20
- TRIDUUM = Rank.new 1.1, I18n.t('rank.1_1')
21
- PRIMARY = Rank.new 1.2, I18n.t('rank.1_2') # description may not be exact
22
- SOLEMNITY_GENERAL = Rank.new 1.3, I18n.t('rank.1_3'), I18n.t('rank.short.solemnity') # description may not be exact
23
- SOLEMNITY_PROPER = Rank.new 1.4, I18n.t('rank.1_4'), I18n.t('rank.short.solemnity')
24
-
25
- FEAST_LORD_GENERAL = Rank.new 2.5, I18n.t('rank.2_5'), I18n.t('rank.short.feast')
26
- SUNDAY_UNPRIVILEGED = Rank.new 2.6, I18n.t('rank.2_6'), I18n.t('rank.short.sunday')
27
- FEAST_GENERAL = Rank.new 2.7, I18n.t('rank.2_7'), I18n.t('rank.short.feast')
28
- FEAST_PROPER = Rank.new 2.8, I18n.t('rank.2_8'), I18n.t('rank.short.feast')
29
- FERIAL_PRIVILEGED = Rank.new 2.9, I18n.t('rank.2_9'), I18n.t('rank.short.ferial')
30
-
31
- MEMORIAL_GENERAL = Rank.new 3.10, I18n.t('rank.3_10'), I18n.t('rank.short.memorial')
32
- MEMORIAL_PROPER = Rank.new 3.11, I18n.t('rank.3_11'), I18n.t('rank.short.memorial')
33
- MEMORIAL_OPTIONAL = Rank.new 3.12, I18n.t('rank.3_12'), I18n.t('rank.short.memorial_opt')
34
- FERIAL = Rank.new 3.13, I18n.t('rank.3_13'), I18n.t('rank.short.ferial')
35
-
36
- def self.[](priority)
37
- Rank[priority]
20
+ class Ranks < Enum
21
+ values(index_by: :priority) do
22
+ # Values are at the same time references to sections
23
+ # of the Table of Liturgical Days.
24
+ # The lower value, the higher rank.
25
+ [
26
+ TRIDUUM = Rank.new(1.1, 'rank.1_1'),
27
+ PRIMARY = Rank.new(1.2, 'rank.1_2'), # description may not be exact
28
+ SOLEMNITY_GENERAL = Rank.new(1.3, 'rank.1_3', 'rank.short.solemnity'), # description may not be exact
29
+ SOLEMNITY_PROPER = Rank.new(1.4, 'rank.1_4', 'rank.short.solemnity'),
30
+
31
+ FEAST_LORD_GENERAL = Rank.new(2.5, 'rank.2_5', 'rank.short.feast'),
32
+ SUNDAY_UNPRIVILEGED = Rank.new(2.6, 'rank.2_6', 'rank.short.sunday'),
33
+ FEAST_GENERAL = Rank.new(2.7, 'rank.2_7', 'rank.short.feast'),
34
+ FEAST_PROPER = Rank.new(2.8, 'rank.2_8', 'rank.short.feast'),
35
+ FERIAL_PRIVILEGED = Rank.new(2.9, 'rank.2_9', 'rank.short.ferial'),
36
+
37
+ MEMORIAL_GENERAL = Rank.new(3.10, 'rank.3_10', 'rank.short.memorial'),
38
+ MEMORIAL_PROPER = Rank.new(3.11, 'rank.3_11', 'rank.short.memorial'),
39
+ MEMORIAL_OPTIONAL = Rank.new(3.12, 'rank.3_12', 'rank.short.memorial_opt'),
40
+ FERIAL = Rank.new(3.13, 'rank.3_13', 'rank.short.ferial')
41
+ ]
38
42
  end
39
43
  end
40
44
 
41
- module Colours
42
- GREEN = :green
43
- VIOLET = :violet
44
- WHITE = :white
45
- RED = :red
45
+ class Colours < Enum
46
+ values do
47
+ [
48
+ GREEN = :green,
49
+ VIOLET = :violet,
50
+ WHITE = :white,
51
+ RED = :red
52
+ ]
53
+ end
46
54
  end
47
55
 
48
56
  Colors = Colours
@@ -1,24 +1,28 @@
1
1
  module CalendariumRomanum
2
- class Rank < Struct.new(:priority, :desc, :short_desc)
2
+ class Rank
3
3
  include Comparable
4
4
 
5
- @@instances = {}
6
-
7
- def initialize(*args)
8
- super(*args)
9
-
10
- @@instances[self.priority] = self
5
+ def initialize(priority=nil, desc=nil, short_desc=nil)
6
+ @priority = priority
7
+ @desc = desc
8
+ @short_desc = short_desc
11
9
  end
12
10
 
13
- def <=>(b)
14
- b.priority <=> self.priority
11
+ attr_reader :priority
12
+ alias_method :to_f, :priority
13
+
14
+ def desc
15
+ @desc && I18n.t(@desc)
15
16
  end
16
17
 
17
- alias_method :to_f, :priority
18
18
  alias_method :to_s, :desc
19
19
 
20
- def self.[](priority)
21
- @@instances[priority]
20
+ def short_desc
21
+ @short_desc && I18n.t(@short_desc)
22
+ end
23
+
24
+ def <=>(b)
25
+ b.priority <=> self.priority
22
26
  end
23
27
 
24
28
  def solemnity?
@@ -21,6 +21,15 @@ module CalendariumRomanum
21
21
  @solemnities[date] = celebration
22
22
  end
23
23
 
24
+ unless @days[date].empty?
25
+ present = @days[date][0]
26
+ if present.rank != Ranks::MEMORIAL_OPTIONAL
27
+ raise ArgumentError.new("On #{date} there is already a #{present.rank}. No more celebrations can be added.")
28
+ elsif celebration.rank != Ranks::MEMORIAL_OPTIONAL
29
+ raise ArgumentError.new("Celebration of rank #{celebration.rank} cannot be grouped, but there is already another celebration on #{date}")
30
+ end
31
+ end
32
+
24
33
  @days[date] << celebration
25
34
  end
26
35
 
@@ -19,10 +19,10 @@ module CalendariumRomanum
19
19
  }
20
20
  COLOUR_CODES = {
21
21
  nil => Colours::WHITE,
22
- 'W' => Colours::WHITE,
23
- 'V' => Colours::VIOLET,
24
- 'G' => Colours::GREEN,
25
- 'R' => Colours::RED
22
+ 'w' => Colours::WHITE,
23
+ 'v' => Colours::VIOLET,
24
+ 'g' => Colours::GREEN,
25
+ 'r' => Colours::RED
26
26
  }
27
27
 
28
28
  # dest should be a Sanctorale,
@@ -50,7 +50,7 @@ module CalendariumRomanum
50
50
  end
51
51
 
52
52
  # celebration record
53
- m = l.match /^((\d+)\/)?(\d+)\s*(([mfs])(\d\.\d+)?)?\s*([WVRG])?\s*:(.*)$/
53
+ m = l.match /^((\d+)\/)?(\d+)\s*(([mfs])?(\d\.\d{1,2})?)?\s*([WVRG])?\s*:(.*)$/i
54
54
  if m.nil?
55
55
  raise error("Syntax error, line skipped '#{l}'", line_num)
56
56
  next
@@ -61,7 +61,7 @@ module CalendariumRomanum
61
61
  day = day.to_i
62
62
  month = month.to_i
63
63
 
64
- rank = RANK_CODES[rank_char]
64
+ rank = RANK_CODES[rank_char && rank_char.downcase]
65
65
  if rank.nil?
66
66
  raise error("Invalid celebration rank code #{rank_char}", line_num)
67
67
  end
@@ -72,7 +72,7 @@ module CalendariumRomanum
72
72
 
73
73
  if rank_by_num.nil?
74
74
  raise error("Invalid celebration rank code #{rank_num}", line_num)
75
- elsif rank.priority.to_i != rank_by_num.priority.to_i
75
+ elsif rank_char && (rank.priority.to_i != rank_by_num.priority.to_i)
76
76
  raise error("Invalid combination of rank letter #{rank_char.inspect} and number #{rank_num}.", line_num)
77
77
  end
78
78
 
@@ -82,7 +82,7 @@ module CalendariumRomanum
82
82
  dest.add month, day, Celebration.new(
83
83
  title.strip,
84
84
  rank,
85
- COLOUR_CODES[colour]
85
+ COLOUR_CODES[colour && colour.downcase]
86
86
  )
87
87
  end
88
88
 
@@ -55,6 +55,9 @@ module CalendariumRomanum
55
55
  end
56
56
 
57
57
  def range_check(date)
58
+ # necessary in order to handle Date correctly
59
+ date = date.to_date if date.class != Date
60
+
58
61
  unless date_range.include? date
59
62
  raise RangeError.new "Date out of range #{date}"
60
63
  end
@@ -191,12 +194,20 @@ module CalendariumRomanum
191
194
  end
192
195
  end
193
196
 
197
+ def palm_sunday(year=nil)
198
+ return easter_sunday(year) - 7
199
+ end
200
+
194
201
  def good_friday(year=nil)
195
- return friday_before(easter_sunday(year))
202
+ return easter_sunday(year) - 2
196
203
  end
197
204
 
198
205
  def holy_saturday(year=nil)
199
- return saturday_before(easter_sunday(year))
206
+ return easter_sunday(year) - 1
207
+ end
208
+
209
+ def ascension(year=nil)
210
+ return pentecost(year) - 10
200
211
  end
201
212
 
202
213
  def pentecost(year=nil)
@@ -275,8 +286,9 @@ module CalendariumRomanum
275
286
  week += 1
276
287
 
277
288
  if date > pentecost
278
- # gap made by Lent and Easter time
279
- week -= 12
289
+ weeks_after_date = date_difference(first_advent_sunday(@year + 1), date) / 7
290
+ week = 34 - weeks_after_date
291
+ week += 1 if date.sunday?
280
292
  end
281
293
  end
282
294
 
@@ -362,15 +374,18 @@ module CalendariumRomanum
362
374
  @solemnities = {}
363
375
 
364
376
  {
365
- nativity: [nil, nil],
377
+ nativity: [Ranks::PRIMARY, nil],
366
378
  holy_family: [Ranks::FEAST_LORD_GENERAL, nil],
367
379
  mother_of_god: [Ranks::SOLEMNITY_GENERAL],
368
- epiphany: [nil, nil],
380
+ epiphany: [Ranks::PRIMARY, nil],
369
381
  baptism_of_lord: [Ranks::FEAST_LORD_GENERAL, nil],
382
+ ash_wednesday: [Ranks::PRIMARY, nil],
370
383
  good_friday: [Ranks::TRIDUUM, Colours::RED],
371
384
  holy_saturday: [Ranks::TRIDUUM, nil],
385
+ palm_sunday: [Ranks::PRIMARY, Colours::RED],
372
386
  easter_sunday: [Ranks::TRIDUUM, nil],
373
- pentecost: [nil, Colours::RED],
387
+ ascension: [Ranks::PRIMARY, Colours::WHITE],
388
+ pentecost: [Ranks::PRIMARY, Colours::RED],
374
389
  holy_trinity: [Ranks::SOLEMNITY_GENERAL, Colours::WHITE],
375
390
  body_blood: [Ranks::SOLEMNITY_GENERAL, Colours::WHITE],
376
391
  sacred_heart: [Ranks::SOLEMNITY_GENERAL, Colours::WHITE],
@@ -379,8 +394,8 @@ module CalendariumRomanum
379
394
  date = send(method_name)
380
395
  rank, colour = data
381
396
  @solemnities[date] = Celebration.new(
382
- I18n.t("temporale.solemnity.#{method_name}"),
383
- rank || Ranks::PRIMARY,
397
+ proc { I18n.t("temporale.solemnity.#{method_name}") },
398
+ rank,
384
399
  colour || SEASON_COLOUR[season(date)]
385
400
  )
386
401
  end
@@ -1,3 +1,3 @@
1
1
  module CalendariumRomanum
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -43,12 +43,42 @@ describe CR::Calendar do
43
43
  end
44
44
 
45
45
  describe '#day' do
46
- it 'returns a Day' do
47
- @c.day(2013, 12, 10).should be_a CR::Day
48
- end
46
+ describe 'received arguments' do
47
+ describe 'Date' do
48
+ it 'returns a Day' do
49
+ @c.day(Date.new(2013, 12, 10)).should be_a CR::Day
50
+ end
51
+ end
52
+
53
+ describe 'DateTime' do
54
+ it 'returns a Day' do
55
+ @c.day(DateTime.new(2013, 12, 10, 12, 10, 0)).should be_a CR::Day
56
+ end
57
+ end
49
58
 
50
- it 'inserts correct year if not given' do
51
- expect(@c.day(12, 10).date).to eq Date.new(2013, 12, 10)
59
+ describe 'three Integers' do
60
+ it 'returns a Day' do
61
+ @c.day(2013, 12, 10).should be_a CR::Day
62
+ end
63
+ end
64
+
65
+ describe 'two integers' do
66
+ describe 'autumn' do
67
+ it 'supplies year' do
68
+ day = @c.day(12, 10)
69
+ expect(day).to be_a CR::Day
70
+ expect(day.date).to eq Date.new(2013, 12, 10)
71
+ end
72
+ end
73
+
74
+ describe 'spring' do
75
+ it 'supplies year' do
76
+ day = @c.day(4, 10)
77
+ expect(day).to be_a CR::Day
78
+ expect(day.date).to eq Date.new(2014, 4, 10)
79
+ end
80
+ end
81
+ end
52
82
  end
53
83
 
54
84
  it 'throws RangeError if given date not included in the year' do
@@ -97,8 +127,60 @@ describe CR::Calendar do
97
127
  expect(@c.day(2014, 1, 13).season_week).to eq 1
98
128
  end
99
129
 
100
- it 'Continue after Pentecost' do
101
- expect(@c.day(2014, 6, 9).season_week).to eq 10
130
+ describe 'after Pentecost' do
131
+ it '2014' do
132
+ c = described_class.new(2013)
133
+ expect(c.day(2014, 6, 9).season_week).to eq 10
134
+ end
135
+
136
+ it '2015' do
137
+ c = described_class.new(2014)
138
+ expect(c.day(2015, 5, 25).season_week).to eq 8
139
+ end
140
+
141
+ it '2016' do
142
+ c = described_class.new(2015)
143
+ expect(c.day(2016, 5, 16).season_week).to eq 7
144
+ end
145
+
146
+ it '2017' do
147
+ c = described_class.new(2016)
148
+ expect(c.day(2017, 6, 5).season_week).to eq 9
149
+ end
150
+
151
+ describe 'works correctly for the whole week' do
152
+ describe 'first' do
153
+ Date.new(2014, 6, 9).upto(Date.new(2014, 6, 14)) do |date|
154
+ it date do
155
+ expect(@c.day(date).season_week).to eq 10
156
+ end
157
+ end
158
+ end
159
+
160
+ describe 'second' do
161
+ Date.new(2014, 6, 15).upto(Date.new(2014, 6, 21)) do |date|
162
+ it date do
163
+ expect(@c.day(date).season_week).to eq 11
164
+ end
165
+ end
166
+ end
167
+
168
+ describe 'second last' do
169
+ Date.new(2014, 11, 16).upto(Date.new(2014, 11, 22)) do |date|
170
+ it date do
171
+ expect(@c.day(date).season_week).to eq 33
172
+ end
173
+ end
174
+ end
175
+
176
+ describe 'last' do
177
+ Date.new(2014, 11, 23).upto(Date.new(2014, 11, 29)) do |date|
178
+ it date do
179
+ expect(@c.day(date).season_week).to eq 34
180
+ end
181
+ end
182
+ end
183
+ end
102
184
  end
103
185
  end
104
186
  end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'calendarium-romanum/cli'
3
+
4
+ describe CalendariumRomanum::CLI do
5
+ let(:path_universal_la) { File.expand_path('../../data/universal-la.txt', __FILE__) }
6
+ let(:path_universal_en) { File.expand_path('../../data/universal-en.txt', __FILE__) }
7
+ describe 'subcommands' do
8
+ describe 'errors' do
9
+ it 'raises no exception' do
10
+ described_class.start(['errors', path_universal_la])
11
+ end
12
+
13
+ it 'fails on a non-existent file' do
14
+ expect do
15
+ described_class.start(['errors', 'does-not-exist.txt'])
16
+ end.to raise_exception Errno::ENOENT
17
+ end
18
+ end
19
+
20
+ describe 'cmp' do
21
+ it 'raises no exception' do
22
+ described_class.start(['cmp', path_universal_la, path_universal_en])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,15 +1,23 @@
1
1
  require_relative 'spec_helper'
2
2
 
3
- describe 'sanctorale data files' do
4
- let(:loader) { CR::SanctoraleLoader.new }
3
+ describe CalendariumRomanum::Data do
4
+ describe 'all available data files are included' do
5
+ data_path = File.expand_path '../data', File.dirname(__FILE__)
6
+ glob = File.join(data_path, '*.txt')
5
7
 
6
- data_path = File.expand_path '../data', File.dirname(__FILE__)
7
- glob = File.join(data_path, '*.txt')
8
+ Dir[glob].each do |file|
9
+ it file do
10
+ in_data = described_class.all.find {|f| f.path == file }
11
+ expect(in_data).not_to be nil
12
+ end
13
+ end
14
+ end
8
15
 
9
- Dir[glob].each do |file|
10
- it "#{file} is loadable" do
11
- sanctorale = loader.load_from_file file
12
- expect(sanctorale).not_to be_empty
16
+ describe 'all can be loaded' do
17
+ described_class.each do |data|
18
+ it data.siglum do
19
+ expect { data.load }.not_to raise_exception
20
+ end
13
21
  end
14
22
  end
15
23
  end