calendarium-romanum 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/calendariumrom +1 -1
  3. data/config/locales/cs.yml +1 -0
  4. data/config/locales/en.yml +1 -0
  5. data/config/locales/fr.yml +1 -0
  6. data/config/locales/it.yml +1 -0
  7. data/config/locales/la.yml +1 -0
  8. data/data/czech-cs.txt +2 -1
  9. data/data/universal-la.txt +2 -0
  10. data/lib/calendarium-romanum.rb +24 -22
  11. data/lib/calendarium-romanum/calendar.rb +66 -16
  12. data/lib/calendarium-romanum/cli.rb +84 -52
  13. data/lib/calendarium-romanum/data.rb +12 -12
  14. data/lib/calendarium-romanum/day.rb +35 -14
  15. data/lib/calendarium-romanum/enum.rb +2 -4
  16. data/lib/calendarium-romanum/enums.rb +1 -1
  17. data/lib/calendarium-romanum/errors.rb +4 -0
  18. data/lib/calendarium-romanum/ordinalizer.rb +13 -1
  19. data/lib/calendarium-romanum/rank.rb +5 -5
  20. data/lib/calendarium-romanum/sanctorale.rb +2 -2
  21. data/lib/calendarium-romanum/sanctoraleloader.rb +31 -24
  22. data/lib/calendarium-romanum/temporale.rb +64 -83
  23. data/lib/calendarium-romanum/temporale/celebration_factory.rb +48 -0
  24. data/lib/calendarium-romanum/temporale/dates.rb +14 -14
  25. data/lib/calendarium-romanum/util.rb +22 -1
  26. data/lib/calendarium-romanum/version.rb +4 -1
  27. data/spec/calendar_spec.rb +232 -3
  28. data/spec/celebration_factory_spec.rb +16 -0
  29. data/spec/celebration_spec.rb +20 -0
  30. data/spec/cli_spec.rb +140 -11
  31. data/spec/date_parser_spec.rb +68 -0
  32. data/spec/date_spec.rb +8 -8
  33. data/spec/day_spec.rb +57 -8
  34. data/spec/i18n_spec.rb +0 -1
  35. data/spec/ordinalizer_spec.rb +29 -15
  36. data/spec/readme_spec.rb +4 -0
  37. data/spec/sanctorale_spec.rb +3 -3
  38. data/spec/sanctoraleloader_spec.rb +16 -11
  39. data/spec/spec_helper.rb +11 -0
  40. data/spec/temporale_spec.rb +56 -3
  41. metadata +6 -2
@@ -0,0 +1,48 @@
1
+ module CalendariumRomanum
2
+ class Temporale
3
+ # builds temporale Celebrations
4
+ class CelebrationFactory
5
+ class << self
6
+ def first_advent_sunday
7
+ Celebration.new(
8
+ I18n.t('temporale.advent.sunday', week: Ordinalizer.ordinal(1)),
9
+ Ranks::PRIMARY,
10
+ Colours::VIOLET
11
+ )
12
+ end
13
+
14
+ private
15
+
16
+ def celebration(symbol, rank, colour = Colours::WHITE)
17
+ define_singleton_method(symbol) do
18
+ Celebration.new(
19
+ proc { I18n.t("temporale.solemnity.#{symbol}") },
20
+ rank,
21
+ colour,
22
+ symbol
23
+ )
24
+ end
25
+ end
26
+ end
27
+
28
+ # define factory methods
29
+ celebration(:nativity, Ranks::PRIMARY)
30
+ celebration(:holy_family, Ranks::FEAST_LORD_GENERAL)
31
+ celebration(:mother_of_god, Ranks::SOLEMNITY_GENERAL)
32
+ celebration(:epiphany, Ranks::PRIMARY)
33
+ celebration(:baptism_of_lord, Ranks::FEAST_LORD_GENERAL)
34
+ celebration(:ash_wednesday, Ranks::PRIMARY, Colours::VIOLET)
35
+ celebration(:good_friday, Ranks::TRIDUUM, Colours::RED)
36
+ celebration(:holy_saturday, Ranks::TRIDUUM, Colours::VIOLET)
37
+ celebration(:palm_sunday, Ranks::PRIMARY, Colours::RED)
38
+ celebration(:easter_sunday, Ranks::TRIDUUM)
39
+ celebration(:ascension, Ranks::PRIMARY)
40
+ celebration(:pentecost, Ranks::PRIMARY, Colours::RED)
41
+ celebration(:holy_trinity, Ranks::SOLEMNITY_GENERAL)
42
+ celebration(:corpus_christi, Ranks::SOLEMNITY_GENERAL)
43
+ celebration(:sacred_heart, Ranks::SOLEMNITY_GENERAL)
44
+ celebration(:christ_king, Ranks::SOLEMNITY_GENERAL)
45
+ celebration(:immaculate_heart, Ranks::MEMORIAL_GENERAL)
46
+ end
47
+ end
48
+ end
@@ -29,7 +29,7 @@ module CalendariumRomanum
29
29
  return sunday_after(Date.new(year + 1, 1, 1))
30
30
  end
31
31
 
32
- Date.new(year+1, 1, 6)
32
+ Date.new(year + 1, 1, 6)
33
33
  end
34
34
 
35
35
  def self.baptism_of_lord(year, epiphany_on_sunday: false)
@@ -58,16 +58,16 @@ module CalendariumRomanum
58
58
  paschal_full_moon = (3 - 11 * golden_number + solar_correction - lunar_correction) % 30
59
59
  dominical_number += 7 until dominical_number > 0
60
60
  paschal_full_moon += 30 until paschal_full_moon > 0
61
- paschal_full_moon -= 1 if paschal_full_moon == 29 or (paschal_full_moon == 28 and golden_number > 11)
61
+ paschal_full_moon -= 1 if (paschal_full_moon == 29) || ((paschal_full_moon == 28) && golden_number > 11)
62
62
  difference = (4 - paschal_full_moon - dominical_number) % 7
63
63
  difference += 7 if difference < 0
64
64
  day_easter = paschal_full_moon + difference + 1
65
- if day_easter < 11 then
65
+ if day_easter < 11
66
66
  # Easter occurs in March.
67
- return Date.new(y=year, m=3, d=day_easter + 21)
67
+ return Date.new(year, 3, day_easter + 21)
68
68
  else
69
69
  # Easter occurs in April.
70
- return Date.new(y=year, m=4, d=day_easter - 10)
70
+ return Date.new(year, 4, day_easter - 10)
71
71
  end
72
72
  end
73
73
 
@@ -124,22 +124,22 @@ module CalendariumRomanum
124
124
  # utility methods
125
125
 
126
126
  def self.weekday_before(weekday, date)
127
- if date.wday == weekday then
128
- return date - WEEK
127
+ if date.wday == weekday
128
+ date - WEEK
129
129
  elsif weekday < date.wday
130
- return date - (date.wday - weekday)
130
+ date - (date.wday - weekday)
131
131
  else
132
- return date - (date.wday + WEEK - weekday)
132
+ date - (date.wday + WEEK - weekday)
133
133
  end
134
134
  end
135
135
 
136
136
  def self.weekday_after(weekday, date)
137
- if date.wday == weekday then
138
- return date + WEEK
137
+ if date.wday == weekday
138
+ date + WEEK
139
139
  elsif weekday > date.wday
140
- return date + (weekday - date.wday)
140
+ date + (weekday - date.wday)
141
141
  else
142
- return date + (WEEK - date.wday + weekday)
142
+ date + (WEEK - date.wday + weekday)
143
143
  end
144
144
  end
145
145
 
@@ -148,7 +148,7 @@ module CalendariumRomanum
148
148
  end
149
149
 
150
150
  class << self
151
- WEEKDAYS = %w{sunday monday tuesday wednesday thursday friday saturday}
151
+ WEEKDAYS = %w(sunday monday tuesday wednesday thursday friday saturday).freeze
152
152
  WEEKDAYS.each_with_index do |weekday, weekday_i|
153
153
  define_method "#{weekday}_before" do |date|
154
154
  send('weekday_before', weekday_i, date)
@@ -18,7 +18,7 @@ module CalendariumRomanum
18
18
  @start.send(@prop) != date.send(@prop)
19
19
  end
20
20
 
21
- alias_method :each_day, :each
21
+ alias each_day each
22
22
  end
23
23
 
24
24
  # enumerates days of a year
@@ -36,5 +36,26 @@ module CalendariumRomanum
36
36
  @prop = :month
37
37
  end
38
38
  end
39
+
40
+ class DateParser
41
+ attr_reader :date_range
42
+ def initialize(date_str)
43
+ if date_str =~ /((\d{4})(\/|-)?(\d{0,2})(\/|-)?(\d{0,2}))\z/ # Accepts YYYY-MM-DD, YYYY/MM/DD where both day and month are optional
44
+ year = Regexp.last_match(2).to_i
45
+ month = Regexp.last_match(4).to_i
46
+ day = Regexp.last_match(6).to_i
47
+ @date_range = if (day == 0) && (month == 0) # Only year is given
48
+ Year.new(year)
49
+ elsif day == 0 # Year and month are given
50
+ Month.new(year, month)
51
+ else
52
+ Date.new(year, month, day)..Date.new(year, month, day)
53
+ end
54
+ else
55
+ raise ArgumentError, 'Unparseable date'
56
+ end
57
+ end
58
+ end
59
+
39
60
  end
40
61
  end
@@ -1,3 +1,6 @@
1
+ require 'date'
2
+
1
3
  module CalendariumRomanum
2
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'.freeze
5
+ RELEASE_DATE = Date.new(2017, 11, 1).freeze
3
6
  end
@@ -5,6 +5,8 @@ describe CR::Calendar do
5
5
  @c = described_class.new(2013).freeze
6
6
  end
7
7
 
8
+ let(:celfactory) { CR::Temporale::CelebrationFactory }
9
+
8
10
  describe '.new' do
9
11
  it 'throws RangeError on invalid year' do
10
12
  expect do
@@ -56,6 +58,24 @@ describe CR::Calendar do
56
58
  end
57
59
  end
58
60
 
61
+ describe '#[]' do
62
+ describe 'received arguments' do
63
+ describe 'Date' do
64
+ it 'returns a Day' do
65
+ expect(@c[Date.new(2013, 12, 10)]).to be_a CR::Day
66
+ end
67
+ end
68
+
69
+ describe 'Date range' do
70
+ it 'returns an array of Days' do
71
+ array = @c[Date.new(2013, 12, 10)..Date.new(2014, 4, 10)]
72
+ expect(array).to be_a Array
73
+ array.each{|day| expect(day).to be_a CR::Day}
74
+ end
75
+ end
76
+ end
77
+ end
78
+
59
79
  describe '#day' do
60
80
  describe 'received arguments' do
61
81
  describe 'Date' do
@@ -206,7 +226,7 @@ describe CR::Calendar do
206
226
  end
207
227
  end
208
228
 
209
- describe 'second last' do
229
+ describe 'second last' do
210
230
  Date.new(2014, 11, 16).upto(Date.new(2014, 11, 22)) do |date|
211
231
  it date do
212
232
  expect(@c.day(date).season_week).to eq 33
@@ -316,8 +336,7 @@ describe CR::Calendar do
316
336
  # Good Friday suppresses the solemnity
317
337
  celebs = c.day(d).celebrations
318
338
  expect(celebs.size).to eq 1
319
- expect(celebs[0].rank).to eq CR::Ranks::TRIDUUM
320
- expect(celebs[0].title).to have_translation 'Friday of the Passion of the Lord'
339
+ expect(celebs[0]).to eq celfactory.good_friday
321
340
 
322
341
  # it is transferred on a day after the Easter octave
323
342
  d = c.temporale.easter_sunday + 8
@@ -325,6 +344,216 @@ describe CR::Calendar do
325
344
  expect(celebs.size).to eq 1
326
345
  expect(celebs[0].title).to eq 'Annunciation of the Lord'
327
346
  end
347
+
348
+ describe 'collision of Immaculate Heart with another obligatory memorial' do
349
+ let(:year) { 2002 }
350
+ let(:c) { described_class.new year, @s }
351
+ let(:date) { Date.new(2003, 6, 28) }
352
+
353
+ it 'makes both optional memorials' do
354
+ # make sure
355
+ expect(c.sanctorale.get(date).first.rank).to eq CR::Ranks::MEMORIAL_GENERAL
356
+ expect(c.temporale.get(date).rank).to eq CR::Ranks::MEMORIAL_GENERAL
357
+
358
+ celebrations = c.day(date).celebrations
359
+ expect(celebrations.size).to eq 3
360
+
361
+ expect(celebrations[0].rank).to eq CR::Ranks::FERIAL
362
+ expect(celebrations[1..-1].collect(&:rank).uniq)
363
+ .to eq([CR::Ranks::MEMORIAL_OPTIONAL])
364
+ end
365
+ end
366
+ end
367
+
368
+ describe 'Vespers' do
369
+ let(:saturday) { Date.new(2014, 1, 4) }
370
+ let(:year) { 2013 }
371
+ let(:calendar) { described_class.new(year) }
372
+
373
+ describe 'not opted in' do
374
+ it 'does not fill Vespers' do
375
+ day = calendar.day saturday
376
+ expect(day.vespers).to be nil
377
+ end
378
+ end
379
+
380
+ describe 'opted in by constructor argument' do
381
+ let(:calendar) { described_class.new(year, nil, nil, vespers: true) }
382
+
383
+ it 'fills Vespers' do
384
+ day = calendar.day saturday
385
+ expect(day.vespers).to be_a CR::Celebration
386
+ end
387
+
388
+ describe 'but the day has not Vespers from following' do
389
+ it 'does not fill Vespers' do
390
+ friday = saturday - 1
391
+ day = calendar.day friday
392
+ expect(day.vespers).to be nil
393
+ end
394
+ end
395
+ end
396
+
397
+ describe 'opted in by argument' do
398
+ it 'fills Vespers' do
399
+ day = calendar.day saturday, vespers: true
400
+ expect(day.vespers).to be_a CR::Celebration
401
+ end
402
+ end
403
+
404
+ describe 'first Vespers of' do
405
+ let(:sanctorale) { CR::Data::GENERAL_ROMAN_ENGLISH.load }
406
+ let(:calendar) { described_class.new(year, sanctorale, nil, vespers: true) }
407
+
408
+ describe 'a Sunday' do
409
+ it 'has first Vespers' do
410
+ day = calendar.day saturday
411
+ expect(day.vespers.rank).to eq CR::Ranks::SUNDAY_UNPRIVILEGED
412
+ end
413
+ end
414
+
415
+ describe 'a solemnity' do
416
+ let(:testing_solemnity) do
417
+ CR::Celebration.new(
418
+ 'Testing solemnity',
419
+ CR::Ranks::SOLEMNITY_GENERAL,
420
+ CR::Colours::WHITE,
421
+ :test
422
+ )
423
+ end
424
+
425
+ it 'has first Vespers' do
426
+ day = calendar.day(Date.new(2014, 11, 1) - 1)
427
+ expect(day.vespers.rank).to be CR::Ranks::SOLEMNITY_GENERAL
428
+ end
429
+
430
+ describe 'clash with Sunday Vespers' do
431
+ it 'wins over Sunday' do
432
+ sunday = Date.new(2014, 8, 17)
433
+ expect(sunday).to be_sunday # make sure
434
+ sanctorale.replace(8, 17, [testing_solemnity])
435
+
436
+ day = calendar.day(sunday - 1)
437
+ expect(day.vespers.symbol).to eq :test
438
+ end
439
+ end
440
+
441
+ describe 'clash with second Vespers of another solemnity' do
442
+ it "the day's Vespers win" do
443
+ assumption = Date.new(2014, 8, 15)
444
+ sanctorale.replace(8, 16, [testing_solemnity])
445
+
446
+ day = calendar.day(assumption)
447
+ expect(day.celebrations.first.rank).to be CR::Ranks::SOLEMNITY_GENERAL
448
+ expect(day.vespers).to be nil
449
+
450
+ # make sure
451
+ next_day = calendar.day(assumption + 1)
452
+ expect(next_day.celebrations.first).to be testing_solemnity
453
+ end
454
+ end
455
+ end
456
+
457
+ describe 'feast of the Lord' do
458
+ describe 'not falling on a Sunday' do
459
+ it 'does not have first Vespers' do
460
+ calendar = described_class.new(2015, sanctorale, nil, vespers: true)
461
+ presentation = Date.new(2016, 2, 2)
462
+ expect(presentation).not_to be_sunday # make sure
463
+
464
+ day = calendar.day(presentation - 1)
465
+ expect(day.vespers).to be nil
466
+ end
467
+ end
468
+
469
+ describe 'falling on a Sunday' do
470
+ it 'has first Vespers' do
471
+ presentation = Date.new(2014, 2, 2)
472
+ expect(presentation).to be_sunday # make sure
473
+
474
+ day = calendar.day(presentation - 1)
475
+ expect(day.vespers.rank).to be CR::Ranks::FEAST_LORD_GENERAL
476
+ end
477
+ end
478
+ end
479
+
480
+ # this group contains both days having and days not having
481
+ # first Vespers: special care must be taken
482
+ describe 'primary liturgical days' do
483
+ describe 'Ash Wednesday' do
484
+ it 'does not have first Vespers' do
485
+ aw = CR::Temporale::Dates.ash_wednesday year
486
+ day = calendar.day(aw - 1)
487
+ expect(day.vespers).to be nil
488
+ end
489
+ end
490
+
491
+ describe 'Nativity' do
492
+ it 'has first Vespers' do
493
+ day = calendar.day Date.new(2013, 12, 24)
494
+ expect(day.vespers).to eq celfactory.nativity
495
+ end
496
+ end
497
+
498
+ describe 'Epiphany' do
499
+ it 'has first Vespers' do
500
+ day = calendar.day Date.new(2014, 1, 5)
501
+ expect(day.vespers.rank).to be CR::Ranks::PRIMARY
502
+ expect(day.vespers.symbol).to be :epiphany
503
+ end
504
+ end
505
+
506
+ describe 'Palm Sunday' do
507
+ it 'has first Vespers' do
508
+ ps = CR::Temporale::Dates.palm_sunday year
509
+ day = calendar.day(ps - 1)
510
+ expect(day.vespers).to eq celfactory.palm_sunday
511
+ end
512
+ end
513
+
514
+ describe 'day in the Holy week' do
515
+ it 'does not have first Vespers' do
516
+ tuesday = CR::Temporale::Dates.palm_sunday(year) + 2
517
+ day = calendar.day(tuesday - 1)
518
+ expect(day.vespers).to be nil
519
+ end
520
+ end
521
+
522
+ describe 'Good Friday' do
523
+ it 'does not have first Vespers' do
524
+ gf = CR::Temporale::Dates.good_friday(year)
525
+ day = calendar.day(gf - 1)
526
+ expect(day.vespers).to be nil
527
+ end
528
+ end
529
+
530
+ describe 'Easter' do
531
+ it 'has first Vespers' do
532
+ es = CR::Temporale::Dates.easter_sunday year
533
+ day = calendar.day(es - 1)
534
+ expect(day.vespers).to eq celfactory.easter_sunday
535
+ end
536
+ end
537
+
538
+ describe 'day in Easter octave' do
539
+ it 'does not have first Vespers' do
540
+ tuesday = CR::Temporale::Dates.easter_sunday(year) + 2
541
+ day = calendar.day(tuesday - 1)
542
+ expect(day.vespers).to be nil
543
+ end
544
+ end
545
+ end
546
+
547
+ describe 'edge cases' do
548
+ describe 'First Sunday of Advent' do
549
+ it 'has first Vespers (and does not cause an exception)' do
550
+ sunday = CR::Temporale::Dates.first_advent_sunday(year + 1)
551
+ day = calendar.day(sunday - 1)
552
+ expect(day.vespers).to eq celfactory.first_advent_sunday
553
+ end
554
+ end
555
+ end
556
+ end
328
557
  end
329
558
  end
330
559
  end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe CR::Temporale::CelebrationFactory do
4
+ describe '.first_advent_sunday' do
5
+ it 'returns Celebration equal to the one returned by Temporale' do
6
+ year = 2000
7
+ temporale = CR::Temporale.new(year)
8
+ date = CR::Temporale::Dates.first_advent_sunday(year)
9
+
10
+ c = temporale.get(date)
11
+ c2 = described_class.first_advent_sunday
12
+
13
+ expect(c2).to eq c
14
+ end
15
+ end
16
+ end