calendarium-romanum 0.4.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +22 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +431 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +86 -0
- data/README.md +598 -0
- data/Rakefile +16 -0
- data/bin/calendariumrom +4 -1
- data/calendarium-romanum.gemspec +31 -0
- data/config/locales/cs.yml +5 -0
- data/config/locales/en.yml +21 -14
- data/config/locales/es.yml +94 -0
- data/config/locales/fr.yml +7 -0
- data/config/locales/it.yml +7 -0
- data/config/locales/la.yml +7 -0
- data/data/README.md +70 -24
- data/data/czech-brno-cs.txt +4 -6
- data/data/czech-budejovice-cs.txt +4 -6
- data/data/czech-cechy-cs.txt +4 -5
- data/data/czech-cs.txt +236 -234
- data/data/czech-hradec-cs.txt +3 -5
- data/data/czech-litomerice-cs.txt +5 -7
- data/data/czech-morava-cs.txt +4 -5
- data/data/czech-olomouc-cs.txt +2 -4
- data/data/czech-ostrava-cs.txt +3 -5
- data/data/czech-plzen-cs.txt +3 -5
- data/data/czech-praha-cs.txt +3 -4
- data/data/easter_dates.txt +67 -0
- data/data/universal-1969-la.txt +234 -0
- data/data/universal-en.txt +214 -211
- data/data/universal-es.txt +243 -0
- data/data/universal-fr.txt +214 -210
- data/data/universal-it.txt +214 -211
- data/data/universal-la.txt +214 -210
- data/doc/data_readme.md +2 -0
- data/doc/images/class_diagram.png +0 -0
- data/doc/images/class_diagram.puml +44 -0
- data/doc/yard_readme.rdoc +76 -0
- data/lib/calendarium-romanum.rb +35 -22
- data/lib/calendarium-romanum/abstract_date.rb +15 -0
- data/lib/calendarium-romanum/calendar.rb +207 -42
- data/lib/calendarium-romanum/cli.rb +63 -80
- data/lib/calendarium-romanum/cli/comparator.rb +63 -0
- data/lib/calendarium-romanum/cli/date_parser.rb +30 -0
- data/lib/calendarium-romanum/cli/dumper.rb +68 -0
- data/lib/calendarium-romanum/cli/helper.rb +23 -0
- data/lib/calendarium-romanum/cli/querier.rb +73 -0
- data/lib/calendarium-romanum/cr.rb +16 -0
- data/lib/calendarium-romanum/data.rb +50 -20
- data/lib/calendarium-romanum/day.rb +208 -32
- data/lib/calendarium-romanum/enum.rb +42 -25
- data/lib/calendarium-romanum/enums.rb +124 -44
- data/lib/calendarium-romanum/errors.rb +4 -0
- data/lib/calendarium-romanum/ordinalizer.rb +23 -2
- data/lib/calendarium-romanum/perpetual_calendar.rb +58 -7
- data/lib/calendarium-romanum/rank.rb +43 -12
- data/lib/calendarium-romanum/rank_predicates.rb +43 -0
- data/lib/calendarium-romanum/sanctorale.rb +164 -24
- data/lib/calendarium-romanum/sanctorale_factory.rb +74 -3
- data/lib/calendarium-romanum/sanctorale_loader.rb +180 -0
- data/lib/calendarium-romanum/sanctorale_writer.rb +119 -0
- data/lib/calendarium-romanum/temporale.rb +226 -94
- data/lib/calendarium-romanum/temporale/celebration_factory.rb +107 -0
- data/lib/calendarium-romanum/temporale/dates.rb +84 -16
- data/lib/calendarium-romanum/temporale/easter_table.rb +27 -0
- data/lib/calendarium-romanum/temporale/extensions.rb +15 -0
- data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +16 -3
- data/lib/calendarium-romanum/temporale/extensions/dedication_before_all_saints.rb +73 -0
- data/lib/calendarium-romanum/transfers.rb +60 -15
- data/lib/calendarium-romanum/util.rb +22 -3
- data/lib/calendarium-romanum/version.rb +5 -1
- data/liturgical_law/1969_normae_universales.md +568 -0
- data/liturgical_law/1977_decretum_de_celebratione_baptismatis_domini.md +58 -0
- data/liturgical_law/1990_decretum_de_variatione_inducenda.md +67 -0
- data/liturgical_law/1998_notificatio_de_occurrentia.md +57 -0
- data/liturgical_law/2002_normae_universales.md +946 -0
- data/liturgical_law/2006_notification.md +37 -0
- data/liturgical_law/2012_declarationes.md +38 -0
- data/liturgical_law/README.md +74 -0
- metadata +50 -28
- data/lib/calendarium-romanum/sanctoraleloader.rb +0 -115
- data/spec/abstract_date_spec.rb +0 -62
- data/spec/calendar_spec.rb +0 -330
- data/spec/celebration_spec.rb +0 -23
- data/spec/cli_spec.rb +0 -26
- data/spec/colour_spec.rb +0 -17
- data/spec/data_spec.rb +0 -23
- data/spec/date_spec.rb +0 -61
- data/spec/dates_spec.rb +0 -45
- data/spec/day_spec.rb +0 -59
- data/spec/enum_spec.rb +0 -51
- data/spec/i18n_spec.rb +0 -59
- data/spec/ordinalizer_spec.rb +0 -22
- data/spec/perpetual_calendar_spec.rb +0 -91
- data/spec/rank_spec.rb +0 -57
- data/spec/readme_spec.rb +0 -52
- data/spec/sanctorale_factory_spec.rb +0 -42
- data/spec/sanctorale_spec.rb +0 -191
- data/spec/sanctoraleloader_spec.rb +0 -171
- data/spec/season_spec.rb +0 -17
- data/spec/spec_helper.rb +0 -35
- data/spec/temporale_spec.rb +0 -519
@@ -1,104 +1,87 @@
|
|
1
1
|
require 'thor'
|
2
2
|
|
3
|
+
# monkey patch preventing Thor from screwing formatting in our commands' long_desc
|
4
|
+
# credits: https://github.com/erikhuda/thor/issues/398#issuecomment-237400762
|
5
|
+
class Thor
|
6
|
+
module Shell
|
7
|
+
class Basic
|
8
|
+
def print_wrapped(message, options = {})
|
9
|
+
stdout.puts message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
module CalendariumRomanum
|
4
16
|
|
17
|
+
# Implementation of the +calendariumrom+ executable.
|
18
|
+
# _Not_ loaded by default when you +require+ the gem.
|
19
|
+
#
|
20
|
+
# @api private
|
5
21
|
class CLI < Thor
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
if date_str
|
23
|
-
begin
|
24
|
-
Date.parse(date_str)
|
25
|
-
rescue ArgumentError
|
26
|
-
STDERR.puts 'Invalid date.'
|
27
|
-
exit 1
|
28
|
-
end
|
29
|
-
else
|
30
|
-
Date.today
|
31
|
-
end
|
32
|
-
calendar = Calendar.for_day(date, sanctorale)
|
33
|
-
day = calendar.day date
|
34
|
-
|
35
|
-
puts date
|
36
|
-
puts "season: #{day.season}"
|
37
|
-
puts
|
38
|
-
|
39
|
-
rank_length = day.celebrations.collect {|c| c.rank.short_desc.size }.max
|
40
|
-
day.celebrations.each do |c|
|
41
|
-
print c.rank.short_desc.rjust(rank_length)
|
42
|
-
print ' : '
|
43
|
-
puts c.title
|
44
|
-
end
|
22
|
+
desc 'query [DATE]', 'show calendar information for a specified date/month/year'
|
23
|
+
long_desc <<-EOS
|
24
|
+
show calendar information for a specified date/month/year
|
25
|
+
|
26
|
+
DATE formats:
|
27
|
+
not specified - today
|
28
|
+
2000-01-02 - single date
|
29
|
+
2000-01 - month
|
30
|
+
2000 - year
|
31
|
+
EOS
|
32
|
+
option :calendar, default: Data::GENERAL_ROMAN_ENGLISH.siglum, aliases: :c, desc: 'sanctorale data file to use (filesystem path or identifier of a bundled one)'
|
33
|
+
option :locale, default: 'en', aliases: :l, desc: 'locale to use for localized strings'
|
34
|
+
def query(date_str = nil)
|
35
|
+
Querier
|
36
|
+
.new(locale: options[:locale], calendar: options[:calendar])
|
37
|
+
.call(date_str)
|
45
38
|
end
|
46
39
|
|
47
|
-
desc 'calendars', '
|
40
|
+
desc 'calendars', 'list calendars available for querying'
|
48
41
|
def calendars
|
49
42
|
Data.each {|c| puts c.siglum }
|
50
43
|
end
|
51
44
|
|
52
|
-
desc 'errors FILE1, ...', '
|
45
|
+
desc 'errors FILE1, ...', 'find errors in sanctorale data files'
|
53
46
|
def errors(*files)
|
54
|
-
loader = SanctoraleLoader.new
|
55
47
|
files.each do |path|
|
56
|
-
|
57
|
-
|
48
|
+
begin
|
49
|
+
sanctorale_from_path path
|
50
|
+
rescue Errno::ENOENT, InvalidDataError => err
|
51
|
+
die! err.message
|
52
|
+
end
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
61
|
-
desc 'cmp FILE1, FILE2', 'detect differences
|
56
|
+
desc 'cmp FILE1, FILE2', 'detect differences between two sanctorale data files'
|
62
57
|
def cmp(a, b)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
[a, b].each do |source|
|
67
|
-
s = Sanctorale.new
|
68
|
-
loader.load_from_file source, s
|
69
|
-
sanctorales << s
|
70
|
-
end
|
71
|
-
|
72
|
-
# a leap year must be chosen in order to iterate over
|
73
|
-
# all possible days of a Sanctorale
|
74
|
-
Year.new(1990).each_day do |d|
|
75
|
-
celebs = sanctorales.collect {|s| s.get d.month, d.day }
|
76
|
-
if celebs.find {|cc| cc.nil? }
|
77
|
-
next
|
78
|
-
end
|
79
|
-
|
80
|
-
celebs[0].each_index do |i|
|
81
|
-
if i >= celebs[1].size
|
82
|
-
break
|
83
|
-
end
|
58
|
+
Comparator.new.call(a, b)
|
59
|
+
end
|
84
60
|
|
85
|
-
|
86
|
-
|
61
|
+
desc 'dump YEAR', 'print calendar of the specified year for use in regression tests'
|
62
|
+
def dump(year)
|
63
|
+
Dumper.new.regression_tests_dump year.to_i
|
64
|
+
end
|
87
65
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
puts
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
66
|
+
desc 'version', 'print version information'
|
67
|
+
def version
|
68
|
+
puts 'calendarium-romanum CLI'
|
69
|
+
puts "calendarium-romanum: version #{CalendariumRomanum::VERSION}, released #{CalendariumRomanum::RELEASE_DATE}"
|
96
70
|
end
|
71
|
+
end
|
72
|
+
end
|
97
73
|
|
98
|
-
|
74
|
+
# required files reopen the CLI class - require after the class'es main definition
|
75
|
+
# in order to prevent superclass mismatch errors
|
76
|
+
require_relative 'cli/helper'
|
99
77
|
|
100
|
-
|
101
|
-
|
102
|
-
|
78
|
+
module CalendariumRomanum
|
79
|
+
class CLI
|
80
|
+
include Helper
|
103
81
|
end
|
104
82
|
end
|
83
|
+
|
84
|
+
require_relative 'cli/comparator'
|
85
|
+
require_relative 'cli/date_parser'
|
86
|
+
require_relative 'cli/dumper'
|
87
|
+
require_relative 'cli/querier'
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# Compares two sanctorale data files, reports differences.
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
class Comparator
|
7
|
+
include Helper
|
8
|
+
|
9
|
+
def call(path_a, path_b)
|
10
|
+
paths = [path_a, path_b]
|
11
|
+
sanctoralia = paths.collect {|source| sanctorale_from_path source }
|
12
|
+
names = paths.collect {|source| File.basename source }
|
13
|
+
|
14
|
+
all_possible_dates.each do |d|
|
15
|
+
a, b = sanctoralia.collect {|sanctorale| sanctorale[d] }
|
16
|
+
|
17
|
+
0.upto([a.size, b.size].max - 1) do |i|
|
18
|
+
ca = a[i]
|
19
|
+
cb = b[i]
|
20
|
+
compared = [ca, cb]
|
21
|
+
|
22
|
+
if compared.index(&:nil?)
|
23
|
+
notnili = compared.index {|c| !c.nil? }
|
24
|
+
|
25
|
+
print date(d)
|
26
|
+
puts " only in #{names[notnili]}:"
|
27
|
+
puts celebration(compared[notnili])
|
28
|
+
puts
|
29
|
+
next
|
30
|
+
end
|
31
|
+
|
32
|
+
differences = %i(rank colour symbol).select do |property|
|
33
|
+
ca.public_send(property) != cb.public_send(property)
|
34
|
+
end
|
35
|
+
|
36
|
+
next if differences.empty?
|
37
|
+
print date(d)
|
38
|
+
puts " differs in #{differences.join(', ')}"
|
39
|
+
puts celebration(ca)
|
40
|
+
puts celebration(cb)
|
41
|
+
puts
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def all_possible_dates
|
49
|
+
# a leap year must be chosen in order to iterate over
|
50
|
+
# all possible days of a Sanctorale
|
51
|
+
Util::Year.new(1990).each_day
|
52
|
+
end
|
53
|
+
|
54
|
+
def date(d)
|
55
|
+
"#{d.month}/#{d.day}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def celebration(c)
|
59
|
+
"#{c.rank.priority} #{c.colour.symbol} | #{c.title}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# @api private
|
4
|
+
class DateParser
|
5
|
+
def self.parse(date_str)
|
6
|
+
/(?<year>\d{4})([\/-](?<month>\d{1,2})([\/-](?<day>\d{1,2}))?)?/.match(date_str) do |m|
|
7
|
+
date_segments =
|
8
|
+
%i(year month day)
|
9
|
+
.collect {|name| m[name] }
|
10
|
+
.compact
|
11
|
+
.collect(&:to_i)
|
12
|
+
|
13
|
+
build_range(*date_segments)
|
14
|
+
end || raise(ArgumentError.new('Unparseable date'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.build_range(*args)
|
18
|
+
case args.size
|
19
|
+
when 1
|
20
|
+
Util::Year.new(*args)
|
21
|
+
when 2
|
22
|
+
Util::Month.new(*args)
|
23
|
+
else
|
24
|
+
date = Date.new(*args)
|
25
|
+
date..date
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# Produces a condensed text representation of a Calendar, used in regression tests.
|
4
|
+
# Not loaded by default by +require 'calendarium-romanum'+
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Dumper
|
8
|
+
def initialize(io=STDOUT)
|
9
|
+
@io = io
|
10
|
+
end
|
11
|
+
|
12
|
+
# Dumps +calendar+. If +other_calendars+ are specified, dumps an alternative entry
|
13
|
+
# for any date for which any of +other_calendars+ differs from +calendar+.
|
14
|
+
def call(calendar, *other_calendars)
|
15
|
+
@io.puts "Calendar for liturgical year #{calendar.year}"
|
16
|
+
calendar.each do |day|
|
17
|
+
dump_day(day)
|
18
|
+
|
19
|
+
other_calendars.each do |cal|
|
20
|
+
day2 = cal[day.date]
|
21
|
+
if day2 != day
|
22
|
+
@io.print 'or '
|
23
|
+
dump_day(day2)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Produces the dump used for regression tests for the specified +year+.
|
30
|
+
def regression_tests_dump(year)
|
31
|
+
sanctorale = Data::GENERAL_ROMAN_LATIN.load
|
32
|
+
calendar = Calendar.new(
|
33
|
+
year,
|
34
|
+
sanctorale,
|
35
|
+
vespers: true
|
36
|
+
)
|
37
|
+
calendar_with_transfers = Calendar.new(
|
38
|
+
Temporale.new(year, transfer_to_sunday: Temporale::SUNDAY_TRANSFERABLE_SOLEMNITIES),
|
39
|
+
sanctorale,
|
40
|
+
vespers: true
|
41
|
+
)
|
42
|
+
calendar_with_extensions = Calendar.new(
|
43
|
+
Temporale.new(year, extensions: Temporale::Extensions.all),
|
44
|
+
sanctorale,
|
45
|
+
vespers: true
|
46
|
+
)
|
47
|
+
|
48
|
+
I18n.with_locale(:la) do
|
49
|
+
call(
|
50
|
+
calendar,
|
51
|
+
calendar_with_transfers,
|
52
|
+
calendar_with_extensions,
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def dump_day(day)
|
60
|
+
@io.puts [day.date, day.season.symbol, day.season_week, !day.vespers.nil?].join(' ')
|
61
|
+
|
62
|
+
day.celebrations.each do |c|
|
63
|
+
@io.puts ['-', c.title.inspect, c.rank.priority, c.colour.symbol, c.symbol, (c.date && "#{c.date.month}/#{c.date.day}"), c.cycle].join(' ')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# Mixin providing helper methods used by multiple CLI-related classes.
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
module Helper
|
7
|
+
def sanctorale_from_path(path)
|
8
|
+
loader = SanctoraleLoader.new
|
9
|
+
|
10
|
+
if path == '-'
|
11
|
+
loader.load(STDIN)
|
12
|
+
else
|
13
|
+
loader.load_from_file(path)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def die!(message, code = 1)
|
18
|
+
STDERR.puts message
|
19
|
+
exit code
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module CalendariumRomanum
|
2
|
+
class CLI
|
3
|
+
# "Queries" a Calendar.
|
4
|
+
# Builds liturgical calendar according to the specified options and
|
5
|
+
# prints calendar entries for the specified period.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Querier
|
9
|
+
include Helper
|
10
|
+
|
11
|
+
def initialize(locale: :en, calendar: 'universal-en')
|
12
|
+
@locale = locale
|
13
|
+
@calendar = calendar
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(date_str = nil)
|
17
|
+
I18n.locale = @locale
|
18
|
+
|
19
|
+
pcal = PerpetualCalendar.new sanctorale: sanctorale
|
20
|
+
|
21
|
+
today = Date.today
|
22
|
+
date_range = today..today
|
23
|
+
|
24
|
+
if date_str
|
25
|
+
begin
|
26
|
+
date_range = DateParser.parse(date_str)
|
27
|
+
rescue ArgumentError
|
28
|
+
die! 'Invalid date.'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
date_range.each do |day|
|
33
|
+
print_single_date(pcal, day)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def print_single_date(calendar, date)
|
40
|
+
day = calendar.day date
|
41
|
+
|
42
|
+
puts date
|
43
|
+
puts "season: #{day.season.name}"
|
44
|
+
puts
|
45
|
+
|
46
|
+
rank_length = day.celebrations.collect {|c| c.rank.short_desc.nil? ? 0 : c.rank.short_desc.size }.max
|
47
|
+
day.celebrations.each do |c|
|
48
|
+
if [Ranks::PRIMARY, Ranks::TRIDUUM].include? c.rank
|
49
|
+
puts c.title
|
50
|
+
elsif !c.rank.short_desc.nil?
|
51
|
+
print c.rank.short_desc.rjust(rank_length)
|
52
|
+
print ' : '
|
53
|
+
puts c.title
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def sanctorale
|
59
|
+
if File.exist?(@calendar)
|
60
|
+
begin
|
61
|
+
sanctorale_from_path(@calendar)
|
62
|
+
rescue CalendariumRomanum::InvalidDataError
|
63
|
+
die! 'Invalid file format.'
|
64
|
+
end
|
65
|
+
elsif data_file = Data[@calendar]
|
66
|
+
data_file.load
|
67
|
+
else
|
68
|
+
die! "Invalid calendar. Either loading a calendar from filesystem did not succeed, \n or a preinstalled calendar was specified which doesn't exist. See subcommand `calendars` for valid options."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'calendarium-romanum'
|
2
|
+
|
3
|
+
# The module name {CalendariumRomanum} is quite long,
|
4
|
+
# hence constant +CR+ is provided as a convenient shortcut.
|
5
|
+
# It is _not_ loaded by +require 'calendarium-romanum'+,
|
6
|
+
# must be required explicitly +require 'calendarium-romanum/cr'+ -
|
7
|
+
# because there's a good chance
|
8
|
+
# that the short constant name clashes with a constant
|
9
|
+
# defined by some other code.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# require 'calendarium-romanum/cr'
|
13
|
+
#
|
14
|
+
# calendar = CR::Calendar.new 2000
|
15
|
+
# @since 0.7.0
|
16
|
+
CR = CalendariumRomanum
|