calendarium-romanum 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8ee4894a3821935522076c8a8c749be997e243ee
4
+ data.tar.gz: bbc5bc6e3c9dd24427eac5d9bef2fa51a73122e3
5
+ SHA512:
6
+ metadata.gz: 0d38d06d95abf7994515a338fff2cf2b08970b2a19952eb39132ccc058f4c2e19e6673267461a4fd0e41dd4e95618cc2a8067981ded24c9477f27743bdd8c5f3
7
+ data.tar.gz: 79b0b9fa0aaaf6f1a2fbec31661b53c15b38fd4b60e23d8585813cbc61c4b3f73dd5a8978d6e52deda6e76be19c2833f73d92ba92ba93fa9e88f7899589e67ca
@@ -0,0 +1,65 @@
1
+ #!/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'calendarium-romanum'
5
+ require 'log4r'
6
+
7
+ module CalendariumRomanum
8
+
9
+ class CLI < Thor
10
+ include CalendariumRomanum::Util
11
+
12
+ desc 'errors FILE1, ...', 'finds errors in sanctorale data files'
13
+ def errors(*files)
14
+ logger = Log4r::Logger['CalendariumRomanum::SanctoraleLoader']
15
+ logger.outputters << Log4r::StderrOutputter.new('stderr')
16
+
17
+ loader = SanctoraleLoader.new
18
+ files.each do |path|
19
+ s = Sanctorale.new
20
+ loader.load_from_file s, path
21
+ end
22
+ end
23
+
24
+ desc 'cmp FILE1, FILE2', 'detect differences in rank and colour of corresponding celebrations'
25
+ def rccompare(a, b)
26
+ loader = SanctoraleLoader.new
27
+ sanctorales = []
28
+
29
+ [a, b].each do |source|
30
+ s = Sanctorale.new
31
+ loader.load_from_file s, source
32
+ sanctorales << s
33
+ end
34
+
35
+ Year.new(1990).each_day do |d|
36
+ celebs = sanctorales.collect {|s| s.get d.month, d.day }
37
+ if celebs.find {|cc| cc.nil? }
38
+ next
39
+ end
40
+
41
+ celebs[0].each_index do |i|
42
+ if i >= celebs[1].size
43
+ break
44
+ end
45
+
46
+ ca = celebs[0][i]
47
+ cb = celebs[1][i]
48
+
49
+ _print_cel = Proc.new {|c| puts "#{c.rank.priority} #{c.colour} | #{c.title}" }
50
+
51
+ if ca.rank != cb.rank || ca.colour != cb.colour
52
+ puts "#{d.month}/#{d.day}"
53
+ _print_cel.call ca
54
+ _print_cel.call cb
55
+ puts
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ if __FILE__ == $0
64
+ CalendariumRomanum::CLI.start ARGV
65
+ end
@@ -0,0 +1,13 @@
1
+ %w{
2
+ enums
3
+ calendar
4
+ temporale
5
+ sanctorale
6
+ sanctoraleloader
7
+ transfers
8
+ day
9
+ abstract_date
10
+ util
11
+ }.each do |f|
12
+ require_relative File.join('calendarium-romanum', f)
13
+ end
@@ -0,0 +1,59 @@
1
+ module CalendariumRomanum
2
+
3
+ # a date not bound to a particular year
4
+ class AbstractDate
5
+ include Comparable
6
+
7
+ def initialize(month, day)
8
+ validate! month, day
9
+ @month = month
10
+ @day = day
11
+ end
12
+
13
+ attr_reader :month, :day
14
+
15
+ def <=>(other)
16
+ if month != other.month
17
+ month <=> other.month
18
+ else
19
+ day <=> other.day
20
+ end
21
+ end
22
+
23
+ def hash
24
+ (month * 100 + day).hash
25
+ end
26
+
27
+ def eql?(other)
28
+ month == other.month && day == other.day
29
+ end
30
+
31
+ def concretize(year)
32
+ Date.new(year, month, day)
33
+ end
34
+
35
+ private
36
+
37
+ def validate!(month, day)
38
+ unless month >= 1 && month <= 12
39
+ raise RangeError.new("Invalid month #{month}.")
40
+ end
41
+
42
+ day_lte = case month
43
+ when 2
44
+ 28
45
+ when 1, 3, 5, 7, 8, 10, 12
46
+ 31
47
+ else
48
+ 30
49
+ end
50
+
51
+ unless day > 0 && day <= 31
52
+ raise RangeError.new("Invalid day #{day}.")
53
+ end
54
+ unless day <= day_lte
55
+ raise RangeError.new("Invalid day #{day} for month #{month}.")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,130 @@
1
+ require 'date'
2
+ require 'forwardable'
3
+
4
+ module CalendariumRomanum
5
+
6
+ # Provides complete information concerning a liturgical year,
7
+ # it's days and celebrations occurring on them.
8
+ class Calendar
9
+
10
+ extend Forwardable
11
+
12
+ # year: Integer
13
+ # returns a calendar for the liturgical year beginning with
14
+ # Advent of the specified civil year.
15
+ def initialize(year, sanctorale=nil)
16
+ @year = year
17
+ @temporale = Temporale.new(year)
18
+ @sanctorale = sanctorale || Sanctorale.new
19
+ @transferred = Transfers.new(@temporale, @sanctorale)
20
+ end
21
+
22
+ class << self
23
+ def mk_date(*args)
24
+ ex = TypeError.new('Date, DateTime or three Integers expected')
25
+
26
+ if args.size == 3 then
27
+ args.each do |a|
28
+ unless a.is_a? Integer
29
+ raise ex
30
+ end
31
+ end
32
+ return Date.new *args
33
+
34
+ elsif args.size == 1 then
35
+ a = args.first
36
+ unless a.is_a? Date or a.is_a? DateTime
37
+ raise ex
38
+ end
39
+ return a
40
+
41
+ else
42
+ raise ex
43
+ end
44
+ end
45
+
46
+ # creates a Calendar for the liturgical year including given
47
+ # date
48
+ def for_day(date, sanctorale=nil)
49
+ return new(Temporale.liturgical_year(date), sanctorale)
50
+ end
51
+ end # class << self
52
+
53
+ def_delegators :@temporale, :range_check, :season
54
+ attr_reader :year
55
+ attr_reader :temporale
56
+ attr_reader :sanctorale
57
+
58
+ # returns a Calendar for the subsequent year
59
+ def succ
60
+ c = Calendar.new @year + 1, @sanctorale
61
+ return c
62
+ end
63
+
64
+ # returns a Calendar for the previous year
65
+ def pred
66
+ c = Calendar.new @year - 1, @sanctorale
67
+ return c
68
+ end
69
+
70
+ def ==(obj)
71
+ unless obj.is_a? Calendar
72
+ return false
73
+ end
74
+
75
+ return year == obj.year
76
+ end
77
+
78
+ # returns filled Day for the specified day
79
+ def day(*args)
80
+ if args.size == 2
81
+ date = Date.new(@year, *args)
82
+ unless @temporale.date_range.include? date
83
+ date = Date.new(@year + 1, *args)
84
+ end
85
+ else
86
+ date = self.class.mk_date *args
87
+ range_check date
88
+ end
89
+
90
+ s = @temporale.season(date)
91
+ return Day.new(
92
+ date: date,
93
+ season: s,
94
+ season_week: @temporale.season_week(s, date),
95
+ celebrations: celebrations_for(date)
96
+ )
97
+ end
98
+
99
+ # Sunday lectionary cycle
100
+ def lectionary
101
+ LECTIONARY_CYCLES[@year % 3]
102
+ end
103
+
104
+ # Ferial lectionary cycle
105
+ def ferial_lectionary
106
+ @year % 2 + 1
107
+ end
108
+
109
+ def celebrations_for(date)
110
+ tr = @transferred.get(date)
111
+ return [tr] if tr
112
+
113
+ t = @temporale.get date
114
+ st = @sanctorale.get date
115
+
116
+ unless st.empty?
117
+ if st.first.rank > t.rank
118
+ if st.first.rank == Ranks::MEMORIAL_OPTIONAL
119
+ st.unshift t
120
+ return st
121
+ else
122
+ return st
123
+ end
124
+ end
125
+ end
126
+
127
+ return [t]
128
+ end
129
+ end # class Calendar
130
+ end
@@ -0,0 +1,59 @@
1
+ require 'forwardable'
2
+
3
+ module CalendariumRomanum
4
+
5
+ # information on one particular day of the liturgical year
6
+ class Day
7
+ def initialize(args={})
8
+ %i(date season season_week celebrations).each do |a|
9
+ if args.include? a
10
+ instance_variable_set "@#{a}", args.delete(a)
11
+ end
12
+ end
13
+
14
+ unless args.empty?
15
+ raise ArgumentError.new "Unexpected arguments #{args.keys.join(', ')}"
16
+ end
17
+ end
18
+
19
+ attr_reader :date
20
+
21
+ def weekday
22
+ date.wday
23
+ end
24
+
25
+ # one of the Seasons (Symbol)
26
+ attr_reader :season
27
+
28
+ # week of the season (Integer)
29
+ attr_reader :season_week
30
+
31
+ # an Array of Celebrations, possibly empty
32
+ attr_reader :celebrations
33
+
34
+ # Celebration of the following day if it has first vespers
35
+ attr_reader :vespers
36
+ end
37
+
38
+ # information on one particular celebration of the liturgical year
39
+ # (like a Sunday, feast or memorial);
40
+ # some days have no (ferial office is used), some have one,
41
+ # some have more among which one may and may not be chosen
42
+ class Celebration
43
+ extend Forwardable
44
+
45
+ def initialize(title='', rank=Ranks::FERIAL, colour=Colours::GREEN)
46
+ @title = title
47
+ @rank = rank
48
+ @colour = colour
49
+ end
50
+
51
+ attr_reader :rank
52
+ def_delegators :@rank, :solemnity?, :feast?, :memorial?
53
+
54
+ attr_reader :title
55
+
56
+ attr_reader :colour
57
+ alias_method :color, :colour
58
+ end
59
+ end
@@ -0,0 +1,84 @@
1
+ module CalendariumRomanum
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
11
+ end
12
+
13
+ LECTIONARY_CYCLES = [:A, :B, :C]
14
+
15
+ class Rank < Struct.new(:priority, :desc, :short_desc)
16
+ include Comparable
17
+
18
+ @@instances = {}
19
+
20
+ def initialize(*args)
21
+ super(*args)
22
+
23
+ @@instances[self.priority] = self
24
+ end
25
+
26
+ def <=>(b)
27
+ b.priority <=> self.priority
28
+ end
29
+
30
+ alias_method :to_f, :priority
31
+ alias_method :to_s, :desc
32
+
33
+ def self.[](priority)
34
+ @@instances[priority]
35
+ end
36
+
37
+ def solemnity?
38
+ priority.to_i == 1
39
+ end
40
+
41
+ def feast?
42
+ priority.to_i == 2
43
+ end
44
+
45
+ def memorial?
46
+ priority.to_i == 3
47
+ end
48
+ end
49
+
50
+ # ranks of celebrations
51
+ module Ranks
52
+ # Values are at the same time references to sections
53
+ # of the Table of Liturgical Days.
54
+ # The lower value, the higher rank.
55
+ TRIDUUM = Rank.new 1.1, 'Easter triduum'
56
+ PRIMARY = Rank.new 1.2, 'Primary liturgical days' # description may not be exact
57
+ SOLEMNITY_GENERAL = Rank.new 1.3, 'Solemnities in the General Calendar', 'solemnity' # description may not be exact
58
+ SOLEMNITY_PROPER = Rank.new 1.4, 'Proper solemnities', 'solemnity'
59
+
60
+ FEAST_LORD_GENERAL = Rank.new 2.5, 'Feasts of the Lord in the General Calendar', 'feast'
61
+ SUNDAY_UNPRIVILEGED = Rank.new 2.6, 'Unprivileged Sundays'
62
+ FEAST_GENERAL = Rank.new 2.7, 'Feasts of saints in the General Calendar', 'feast'
63
+ FEAST_PROPER = Rank.new 2.8, 'Proper feasts', 'feast'
64
+ FERIAL_PRIVILEGED = Rank.new 2.9, 'Privileged ferials'
65
+
66
+ MEMORIAL_GENERAL = Rank.new 3.10, 'Obligatory memorials in the General Calendar', 'memorial'
67
+ MEMORIAL_PROPER = Rank.new 3.11, 'Proper obligatory memorials', 'memorial'
68
+ MEMORIAL_OPTIONAL = Rank.new 3.12, 'Optional memorials', 'optional memorial'
69
+ FERIAL = Rank.new 3.13, 'Unprivileged ferials', 'ferial'
70
+
71
+ def self.[](priority)
72
+ Rank[priority]
73
+ end
74
+ end
75
+
76
+ module Colours
77
+ GREEN = :green
78
+ VIOLET = :violet
79
+ WHITE = :white
80
+ RED = :red
81
+ end
82
+
83
+ Colors = Colours
84
+ end
@@ -0,0 +1,80 @@
1
+ module CalendariumRomanum
2
+
3
+ # knows the fixed-date celebrations
4
+ class Sanctorale
5
+
6
+ def initialize
7
+ @days = {}
8
+
9
+ @solemnities = {}
10
+ end
11
+
12
+ attr_reader :solemnities
13
+
14
+ def add(month, day, celebration)
15
+ date = AbstractDate.new(month, day)
16
+ unless @days.has_key? date
17
+ @days[date] = []
18
+ end
19
+
20
+ if celebration.solemnity?
21
+ @solemnities[date] = celebration
22
+ end
23
+
24
+ @days[date] << celebration
25
+ end
26
+
27
+ # replaces content of the given day by given celebrations
28
+ def replace(month, day, celebrations)
29
+ date = AbstractDate.new(month, day)
30
+
31
+ if celebrations.first.solemnity?
32
+ @solemnities[date] = celebrations.first
33
+ elsif @solemnities.has_key? date
34
+ @solemnities.delete date
35
+ end
36
+
37
+ @days[date] = celebrations
38
+ end
39
+
40
+ # adds all Celebrations from another instance
41
+ def update(sanctorale)
42
+ sanctorale.each_day do |date, celebrations|
43
+ replace date.month, date.day, celebrations
44
+ end
45
+ end
46
+
47
+ # returns an Array with one or more Celebrations
48
+ # scheduled for the given day
49
+ #
50
+ # expected arguments: Date or two Integers (month, day)
51
+ def get(*args)
52
+ if args.size == 1 && args[0].is_a?(Date)
53
+ month = args[0].month
54
+ day = args[0].day
55
+ else
56
+ month, day = args
57
+ end
58
+
59
+ date = AbstractDate.new(month, day)
60
+ return @days[date] || []
61
+ end
62
+
63
+ # for each day for which an entry is available
64
+ # yields an AbstractDate and an Array of Celebrations
65
+ def each_day
66
+ @days.each_pair do |date, celebrations|
67
+ yield date, celebrations
68
+ end
69
+ end
70
+
71
+ # returns count of the _days_ with celebrations filled
72
+ def size
73
+ @days.size
74
+ end
75
+
76
+ def empty?
77
+ @days.empty?
78
+ end
79
+ end
80
+ end