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.
- checksums.yaml +5 -5
- data/bin/calendariumrom +4 -1
- data/config/locales/cs.yml +54 -2
- data/config/locales/en.yml +64 -14
- data/config/locales/es.yml +90 -0
- data/config/locales/fr.yml +90 -0
- data/config/locales/it.yml +54 -4
- data/config/locales/la.yml +52 -2
- data/data/README.md +105 -5
- data/data/czech-brno-cs.txt +11 -5
- data/data/czech-budejovice-cs.txt +11 -5
- data/data/czech-cechy-cs.txt +11 -5
- data/data/czech-cs.txt +243 -234
- data/data/czech-hradec-cs.txt +10 -4
- data/data/czech-litomerice-cs.txt +12 -6
- data/data/czech-morava-cs.txt +11 -5
- data/data/czech-olomouc-cs.txt +9 -3
- data/data/czech-ostrava-cs.txt +10 -4
- data/data/czech-plzen-cs.txt +10 -4
- data/data/czech-praha-cs.txt +10 -3
- data/data/universal-en.txt +218 -212
- data/data/universal-es.txt +243 -0
- data/data/universal-fr.txt +243 -0
- data/data/universal-it.txt +218 -212
- data/data/universal-la.txt +218 -211
- data/lib/calendarium-romanum.rb +30 -18
- data/lib/calendarium-romanum/abstract_date.rb +12 -0
- data/lib/calendarium-romanum/calendar.rb +210 -48
- data/lib/calendarium-romanum/cli.rb +101 -52
- data/lib/calendarium-romanum/cr.rb +16 -0
- data/lib/calendarium-romanum/data.rb +46 -18
- data/lib/calendarium-romanum/day.rb +200 -21
- data/lib/calendarium-romanum/enum.rb +24 -5
- data/lib/calendarium-romanum/enums.rb +123 -37
- data/lib/calendarium-romanum/errors.rb +4 -0
- data/lib/calendarium-romanum/ordinalizer.rb +61 -0
- data/lib/calendarium-romanum/perpetual_calendar.rb +97 -0
- data/lib/calendarium-romanum/rank.rb +43 -6
- data/lib/calendarium-romanum/sanctorale.rb +142 -22
- data/lib/calendarium-romanum/sanctorale_factory.rb +74 -3
- data/lib/calendarium-romanum/sanctorale_loader.rb +176 -0
- data/lib/calendarium-romanum/temporale.rb +296 -251
- data/lib/calendarium-romanum/temporale/celebration_factory.rb +106 -0
- data/lib/calendarium-romanum/temporale/dates.rb +232 -0
- data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +37 -0
- data/lib/calendarium-romanum/transfers.rb +43 -6
- data/lib/calendarium-romanum/util.rb +36 -3
- data/lib/calendarium-romanum/version.rb +5 -1
- data/spec/abstract_date_spec.rb +11 -3
- data/spec/calendar_spec.rb +645 -188
- data/spec/celebration_factory_spec.rb +40 -0
- data/spec/celebration_spec.rb +67 -0
- data/spec/cli_spec.rb +154 -11
- data/spec/colour_spec.rb +22 -0
- data/spec/data_spec.rb +26 -3
- data/spec/date_parser_spec.rb +68 -0
- data/spec/date_spec.rb +8 -8
- data/spec/dates_spec.rb +73 -0
- data/spec/day_spec.rb +151 -0
- data/spec/i18n_spec.rb +11 -2
- data/spec/ordinalizer_spec.rb +44 -0
- data/spec/perpetual_calendar_spec.rb +125 -0
- data/spec/rank_spec.rb +42 -7
- data/spec/readme_spec.rb +18 -10
- data/spec/sanctorale_factory_spec.rb +113 -9
- data/spec/sanctorale_loader_spec.rb +229 -0
- data/spec/sanctorale_spec.rb +176 -62
- data/spec/season_spec.rb +22 -0
- data/spec/spec_helper.rb +27 -1
- data/spec/temporale_spec.rb +473 -154
- data/spec/year_spec.rb +25 -0
- metadata +42 -7
- data/lib/calendarium-romanum/sanctoraleloader.rb +0 -104
- data/spec/sanctoraleloader_spec.rb +0 -171
data/lib/calendarium-romanum.rb
CHANGED
@@ -1,19 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
# Module wrapping the gem's classes
|
2
|
+
#
|
3
|
+
# If you hate typing the long module name, see {CR}
|
4
|
+
module CalendariumRomanum
|
5
|
+
end
|
6
|
+
|
7
|
+
%w(
|
8
|
+
version
|
9
|
+
i18n_setup
|
10
|
+
abstract_date
|
11
|
+
rank
|
12
|
+
enum
|
13
|
+
enums
|
14
|
+
errors
|
15
|
+
data
|
16
|
+
day
|
17
|
+
calendar
|
18
|
+
perpetual_calendar
|
19
|
+
temporale/dates
|
20
|
+
temporale/celebration_factory
|
21
|
+
temporale/extensions/christ_eternal_priest
|
22
|
+
temporale
|
23
|
+
sanctorale
|
24
|
+
sanctorale_loader
|
25
|
+
sanctorale_factory
|
26
|
+
transfers
|
27
|
+
util
|
28
|
+
ordinalizer
|
29
|
+
).each do |f|
|
30
|
+
require_relative File.join('calendarium-romanum', f)
|
19
31
|
end
|
@@ -4,12 +4,20 @@ module CalendariumRomanum
|
|
4
4
|
class AbstractDate
|
5
5
|
include Comparable
|
6
6
|
|
7
|
+
# @param month [Fixnum]
|
8
|
+
# @param day [Fixnum]
|
9
|
+
# @raise [RangeError] on invalid +month+/+day+ value
|
7
10
|
def initialize(month, day)
|
8
11
|
validate! month, day
|
9
12
|
@month = month
|
10
13
|
@day = day
|
11
14
|
end
|
12
15
|
|
16
|
+
# Build a new instance from a +Date+ (or an object with
|
17
|
+
# similar public interface).
|
18
|
+
#
|
19
|
+
# @param date [Date]
|
20
|
+
# @return [AbstractDate]
|
13
21
|
def self.from_date(date)
|
14
22
|
new(date.month, date.day)
|
15
23
|
end
|
@@ -32,6 +40,10 @@ module CalendariumRomanum
|
|
32
40
|
month == other.month && day == other.day
|
33
41
|
end
|
34
42
|
|
43
|
+
# Produce a +Date+ by providing a year to an +AbstractDate+
|
44
|
+
#
|
45
|
+
# @param year [Fixnum]
|
46
|
+
# @return [Date]
|
35
47
|
def concretize(year)
|
36
48
|
Date.new(year, month, day)
|
37
49
|
end
|
@@ -5,37 +5,61 @@ module CalendariumRomanum
|
|
5
5
|
|
6
6
|
# Provides complete information concerning a liturgical year,
|
7
7
|
# it's days and celebrations occurring on them.
|
8
|
+
#
|
9
|
+
# {Calendar}'s business logic is mostly about correctly combining
|
10
|
+
# information from {Temporale} and {Sanctorale}.
|
8
11
|
class Calendar
|
9
|
-
|
10
12
|
extend Forwardable
|
11
13
|
|
12
|
-
#
|
13
|
-
|
14
|
+
# Day when the implemented calendar system became effective
|
15
|
+
EFFECTIVE_FROM = Date.new(1970, 1, 1).freeze
|
16
|
+
|
17
|
+
# Returns a calendar for the liturgical year beginning with
|
14
18
|
# Advent of the specified civil year.
|
15
|
-
|
19
|
+
#
|
20
|
+
# @param year [Fixnum]
|
21
|
+
# Civil year when the liturgical year begins.
|
22
|
+
# @param sanctorale [Sanctorale, nil]
|
23
|
+
# If not provided, the +Calendar+ will only know celebrations
|
24
|
+
# of the temporale cycle, no feasts of the saints!
|
25
|
+
# @param temporale [Temporale, nil]
|
26
|
+
# If not provided, +Temporale+ for the given year with default
|
27
|
+
# configuration will built.
|
28
|
+
# @param vespers [Boolean] Set to true if you want the +Calendar+ to populate {Day#vespers}
|
29
|
+
# @raise [RangeError]
|
30
|
+
# if +year+ is specified for which the implemented calendar
|
31
|
+
# system wasn't in force
|
32
|
+
def initialize(year, sanctorale = nil, temporale = nil, vespers: false)
|
33
|
+
if year < (EFFECTIVE_FROM.year - 1)
|
34
|
+
raise system_not_effective
|
35
|
+
end
|
36
|
+
|
37
|
+
if temporale && temporale.year != year
|
38
|
+
raise ArgumentError.new('Temporale year must be the same as year.')
|
39
|
+
end
|
40
|
+
|
16
41
|
@year = year
|
17
|
-
@temporale = Temporale.new(year)
|
18
42
|
@sanctorale = sanctorale || Sanctorale.new
|
43
|
+
@temporale = temporale || Temporale.new(year)
|
44
|
+
@populate_vespers = vespers
|
45
|
+
|
19
46
|
@transferred = Transfers.new(@temporale, @sanctorale)
|
20
47
|
end
|
21
48
|
|
22
49
|
class << self
|
50
|
+
# @api private
|
23
51
|
def mk_date(*args)
|
24
52
|
ex = TypeError.new('Date, DateTime or three Integers expected')
|
25
53
|
|
26
|
-
if args.size == 3
|
54
|
+
if args.size == 3
|
27
55
|
args.each do |a|
|
28
|
-
unless a.is_a? Integer
|
29
|
-
raise ex
|
30
|
-
end
|
56
|
+
raise ex unless a.is_a? Integer
|
31
57
|
end
|
32
|
-
return Date.new
|
58
|
+
return Date.new(*args)
|
33
59
|
|
34
|
-
elsif args.size == 1
|
60
|
+
elsif args.size == 1
|
35
61
|
a = args.first
|
36
|
-
unless a.is_a? Date
|
37
|
-
raise ex
|
38
|
-
end
|
62
|
+
raise ex unless a.is_a? Date
|
39
63
|
return a
|
40
64
|
|
41
65
|
else
|
@@ -43,91 +67,229 @@ module CalendariumRomanum
|
|
43
67
|
end
|
44
68
|
end
|
45
69
|
|
46
|
-
#
|
47
|
-
# date
|
48
|
-
|
49
|
-
|
70
|
+
# Creates a new instance for the liturgical year which includes
|
71
|
+
# given date
|
72
|
+
#
|
73
|
+
# @param date [Date]
|
74
|
+
# @param constructor_args
|
75
|
+
# arguments that will be passed to {initialize}
|
76
|
+
# @return [Calendar]
|
77
|
+
def for_day(date, *constructor_args)
|
78
|
+
new(Temporale.liturgical_year(date), *constructor_args)
|
50
79
|
end
|
51
80
|
end # class << self
|
52
81
|
|
82
|
+
# @!method range_check(date)
|
83
|
+
# @see Temporale#range_check
|
84
|
+
# @param date
|
85
|
+
# @return [void]
|
86
|
+
# @!method season(date)
|
87
|
+
# @see Temporale#season
|
88
|
+
# @param date
|
89
|
+
# @return [Season]
|
53
90
|
def_delegators :@temporale, :range_check, :season
|
91
|
+
|
92
|
+
# @return [Fixnum]
|
54
93
|
attr_reader :year
|
94
|
+
|
95
|
+
# @return [Temporale]
|
55
96
|
attr_reader :temporale
|
97
|
+
|
98
|
+
# @return [Sanctorale]
|
56
99
|
attr_reader :sanctorale
|
57
100
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
101
|
+
# Do {Day} instances returned by this +Calendar+
|
102
|
+
# have {Day#vespers} populated?
|
103
|
+
# @return [Boolean]
|
104
|
+
# @since 0.6.0
|
105
|
+
def populates_vespers?
|
106
|
+
@populate_vespers
|
62
107
|
end
|
63
108
|
|
64
|
-
#
|
65
|
-
|
66
|
-
|
67
|
-
|
109
|
+
# Two +Calendar+s are equal if they have equal settings
|
110
|
+
# (which means that to equal input they return equal data)
|
111
|
+
def ==(b)
|
112
|
+
b.class == self.class &&
|
113
|
+
year == b.year &&
|
114
|
+
populates_vespers? == b.populates_vespers? &&
|
115
|
+
temporale == b.temporale &&
|
116
|
+
sanctorale == b.sanctorale
|
68
117
|
end
|
69
118
|
|
70
|
-
|
71
|
-
|
72
|
-
|
119
|
+
# Retrieve liturgical calendar information for the specified day
|
120
|
+
# or range of days.
|
121
|
+
#
|
122
|
+
# @overload [](date)
|
123
|
+
# @param date [Date]
|
124
|
+
# @return [Day]
|
125
|
+
# @overload [](range)
|
126
|
+
# @param range [Range<Date>]
|
127
|
+
# @return [Array<Day>]
|
128
|
+
def [](args)
|
129
|
+
if args.is_a?(Range)
|
130
|
+
args.map {|date| day(date) }
|
131
|
+
else
|
132
|
+
day(args)
|
73
133
|
end
|
74
|
-
|
75
|
-
return year == obj.year
|
76
134
|
end
|
77
135
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
136
|
+
# Retrieve liturgical calendar information for the specified day
|
137
|
+
#
|
138
|
+
# @overload day(date, vespers: false)
|
139
|
+
# @param date [Date]
|
140
|
+
# @overload day(year, month, day, vespers: false)
|
141
|
+
# @param year [Fixnum]
|
142
|
+
# @param month [Fixnum]
|
143
|
+
# @param day [Fixnum]
|
144
|
+
# @param vespers [Boolean]
|
145
|
+
# Set to +true+ in order to get {Day} with {Day#vespers}
|
146
|
+
# populated (overrides instance-wide setting {#populates_vespers?}).
|
147
|
+
# @return [Day]
|
148
|
+
# @raise [RangeError]
|
149
|
+
# If a date is specified on which the implemented calendar
|
150
|
+
# system was not yet in force (it became effective during
|
151
|
+
# the liturgical year 1969/1970)
|
152
|
+
def day(*args, vespers: false)
|
83
153
|
if args.size == 2
|
84
154
|
date = Date.new(@year, *args)
|
85
155
|
unless @temporale.date_range.include? date
|
86
156
|
date = Date.new(@year + 1, *args)
|
87
157
|
end
|
88
158
|
else
|
89
|
-
date = self.class.mk_date
|
159
|
+
date = self.class.mk_date(*args)
|
90
160
|
range_check date
|
91
161
|
end
|
92
162
|
|
163
|
+
if date < EFFECTIVE_FROM
|
164
|
+
raise system_not_effective
|
165
|
+
end
|
166
|
+
|
167
|
+
celebrations = celebrations_for(date)
|
168
|
+
vespers_celebration = nil
|
169
|
+
if @populate_vespers || vespers
|
170
|
+
begin
|
171
|
+
vespers_celebration = first_vespers_on(date, celebrations)
|
172
|
+
rescue RangeError
|
173
|
+
# there is exactly one possible case when
|
174
|
+
# range_check(date) passes and range_check(date + 1) fails:
|
175
|
+
vespers_celebration = Temporale::CelebrationFactory.first_advent_sunday
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
93
179
|
s = @temporale.season(date)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
180
|
+
Day.new(
|
181
|
+
date: date,
|
182
|
+
season: s,
|
183
|
+
season_week: @temporale.season_week(s, date),
|
184
|
+
celebrations: celebrations,
|
185
|
+
vespers: vespers_celebration
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Iterate over the whole liturgical year, day by day,
|
190
|
+
# for each day yield calendar data.
|
191
|
+
# If called without a block, returns +Enumerator+.
|
192
|
+
#
|
193
|
+
# @yield [Day]
|
194
|
+
# @return [void, Enumerator]
|
195
|
+
# @since 0.6.0
|
196
|
+
def each
|
197
|
+
return to_enum(__method__) unless block_given?
|
198
|
+
|
199
|
+
temporale.date_range
|
200
|
+
.each {|date| yield(day(date)) }
|
100
201
|
end
|
101
202
|
|
102
203
|
# Sunday lectionary cycle
|
204
|
+
#
|
205
|
+
# @return [Symbol]
|
206
|
+
# For possible values see {LECTIONARY_CYCLES}
|
103
207
|
def lectionary
|
104
208
|
LECTIONARY_CYCLES[@year % 3]
|
105
209
|
end
|
106
210
|
|
107
211
|
# Ferial lectionary cycle
|
212
|
+
#
|
213
|
+
# @return [1, 2]
|
108
214
|
def ferial_lectionary
|
109
215
|
@year % 2 + 1
|
110
216
|
end
|
111
217
|
|
218
|
+
# Freezes the instance.
|
219
|
+
#
|
220
|
+
# *WARNING*: {Temporale} and {Sanctorale} instances passed
|
221
|
+
# to the +Calendar+ on initialization will be frozen, too!
|
222
|
+
# This is necessary, because a +Calendar+ would not really be
|
223
|
+
# frozen were it possible to mutate it's key components.
|
224
|
+
def freeze
|
225
|
+
@temporale.freeze
|
226
|
+
@sanctorale.freeze
|
227
|
+
super
|
228
|
+
end
|
229
|
+
|
230
|
+
private
|
231
|
+
|
112
232
|
def celebrations_for(date)
|
113
233
|
tr = @transferred.get(date)
|
114
234
|
return [tr] if tr
|
115
235
|
|
116
|
-
t = @temporale
|
117
|
-
st = @sanctorale
|
236
|
+
t = @temporale[date]
|
237
|
+
st = @sanctorale[date]
|
238
|
+
|
239
|
+
if date.saturday? &&
|
240
|
+
@temporale.season(date) == Seasons::ORDINARY &&
|
241
|
+
(st.empty? || st.first.rank == Ranks::MEMORIAL_OPTIONAL) &&
|
242
|
+
t.rank <= Ranks::MEMORIAL_OPTIONAL
|
243
|
+
st = st.dup << Temporale::CelebrationFactory.saturday_memorial_bvm
|
244
|
+
end
|
118
245
|
|
119
246
|
unless st.empty?
|
120
247
|
if st.first.rank > t.rank
|
121
248
|
if st.first.rank == Ranks::MEMORIAL_OPTIONAL
|
122
|
-
st.unshift t
|
123
|
-
return st
|
249
|
+
return st.dup.unshift t
|
124
250
|
else
|
125
251
|
return st
|
126
252
|
end
|
253
|
+
elsif t.rank == Ranks::FERIAL_PRIVILEGED && st.first.rank.memorial?
|
254
|
+
commemorations = st.collect do |c|
|
255
|
+
c.change(rank: Ranks::COMMEMORATION, colour: t.colour)
|
256
|
+
end
|
257
|
+
return commemorations.unshift t
|
258
|
+
elsif t.symbol == :immaculate_heart &&
|
259
|
+
[Ranks::MEMORIAL_GENERAL, Ranks::MEMORIAL_PROPER].include?(st.first.rank)
|
260
|
+
optional_memorials = ([t] + st).collect do |celebration|
|
261
|
+
celebration.change rank: Ranks::MEMORIAL_OPTIONAL
|
262
|
+
end
|
263
|
+
ferial = temporale.send :ferial, date # ugly and evil
|
264
|
+
return [ferial] + optional_memorials
|
127
265
|
end
|
128
266
|
end
|
129
267
|
|
130
|
-
|
268
|
+
[t]
|
269
|
+
end
|
270
|
+
|
271
|
+
def first_vespers_on(date, celebrations)
|
272
|
+
tomorrow = date + 1
|
273
|
+
tomorrow_celebrations = celebrations_for(tomorrow)
|
274
|
+
|
275
|
+
c = tomorrow_celebrations.first
|
276
|
+
if c.rank >= Ranks::SOLEMNITY_PROPER ||
|
277
|
+
c.rank == Ranks::SUNDAY_UNPRIVILEGED ||
|
278
|
+
(c.rank == Ranks::FEAST_LORD_GENERAL && tomorrow.sunday?)
|
279
|
+
if c.symbol == :ash_wednesday || c.symbol == :good_friday
|
280
|
+
return nil
|
281
|
+
end
|
282
|
+
|
283
|
+
if c.rank > celebrations.first.rank || c.symbol == :easter_sunday
|
284
|
+
return c
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
nil
|
289
|
+
end
|
290
|
+
|
291
|
+
def system_not_effective
|
292
|
+
RangeError.new('Year out of range. Implemented calendar system has been in use only since 1st January 1970.')
|
131
293
|
end
|
132
294
|
end # class Calendar
|
133
295
|
end
|
@@ -2,45 +2,47 @@ require 'thor'
|
|
2
2
|
|
3
3
|
module CalendariumRomanum
|
4
4
|
|
5
|
+
# Implementation of the +calendariumrom+ executable.
|
6
|
+
# _Not_ loaded by default when you +require+ the gem.
|
7
|
+
#
|
8
|
+
# @api private
|
5
9
|
class CLI < Thor
|
6
10
|
include CalendariumRomanum::Util
|
7
11
|
|
8
12
|
desc 'query 2007-06-05', 'show calendar information for a specified date'
|
9
13
|
option :calendar, default: 'universal-en', aliases: :c
|
10
14
|
option :locale, default: 'en', aliases: :l
|
11
|
-
def query(date_str=nil)
|
15
|
+
def query(date_str = nil)
|
12
16
|
I18n.locale = options[:locale]
|
17
|
+
calendar = options[:calendar]
|
18
|
+
if File.exist?(calendar)
|
19
|
+
begin
|
20
|
+
sanctorale = SanctoraleLoader.new.load_from_file(calendar)
|
21
|
+
rescue CalendariumRomanum::InvalidDataError
|
22
|
+
die! 'Invalid file format.'
|
23
|
+
end
|
24
|
+
else
|
25
|
+
data_file = Data[calendar]
|
13
26
|
|
14
|
-
|
15
|
-
|
16
|
-
STDERR.puts 'Invalid calendar. See subcommand `calendars` for valid options.'
|
17
|
-
exit 1
|
18
|
-
end
|
19
|
-
sanctorale = data_file.load
|
20
|
-
|
21
|
-
date =
|
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
|
27
|
+
if data_file.nil?
|
28
|
+
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."
|
31
29
|
end
|
32
|
-
|
33
|
-
|
30
|
+
sanctorale = data_file.load
|
31
|
+
end
|
34
32
|
|
35
|
-
|
36
|
-
puts "season: #{day.season}"
|
37
|
-
puts
|
33
|
+
pcal = PerpetualCalendar.new sanctorale: sanctorale
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
if date_str
|
36
|
+
begin
|
37
|
+
parsed_date = DateParser.new(date_str)
|
38
|
+
parsed_date.date_range.each do |day|
|
39
|
+
print_single_date(pcal, day)
|
40
|
+
end
|
41
|
+
rescue ArgumentError
|
42
|
+
die! 'Invalid date.'
|
43
|
+
end
|
44
|
+
else
|
45
|
+
print_single_date(pcal, Date.today)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
@@ -54,47 +56,94 @@ module CalendariumRomanum
|
|
54
56
|
loader = SanctoraleLoader.new
|
55
57
|
files.each do |path|
|
56
58
|
s = Sanctorale.new
|
57
|
-
|
59
|
+
begin
|
60
|
+
loader.load_from_file path, s
|
61
|
+
rescue Errno::ENOENT, InvalidDataError => err
|
62
|
+
die! err.message
|
63
|
+
end
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
61
67
|
desc 'cmp FILE1, FILE2', 'detect differences in rank and colour of corresponding celebrations'
|
62
68
|
def cmp(a, b)
|
63
69
|
loader = SanctoraleLoader.new
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
s = Sanctorale.new
|
68
|
-
loader.load_from_file source, s
|
69
|
-
sanctorales << s
|
70
|
-
end
|
70
|
+
paths = [a, b]
|
71
|
+
sanctoralia = paths.collect {|source| loader.load_from_file source }
|
72
|
+
names = paths.collect {|source| File.basename source }
|
71
73
|
|
72
74
|
# a leap year must be chosen in order to iterate over
|
73
75
|
# all possible days of a Sanctorale
|
74
76
|
Year.new(1990).each_day do |d|
|
75
|
-
|
76
|
-
if celebs.find {|cc| cc.nil? }
|
77
|
-
next
|
78
|
-
end
|
77
|
+
a, b = sanctoralia.collect {|s| s.get(d) }
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
ca = celebs[0][i]
|
86
|
-
cb = celebs[1][i]
|
79
|
+
0.upto([a.size, b.size].max - 1) do |i|
|
80
|
+
ca = a[i]
|
81
|
+
cb = b[i]
|
82
|
+
compared = [ca, cb]
|
87
83
|
|
88
|
-
|
84
|
+
if compared.index(&:nil?)
|
85
|
+
notnili = compared.index {|c| !c.nil? }
|
89
86
|
|
90
|
-
|
91
|
-
puts "#{
|
92
|
-
|
93
|
-
_print_cel.call cb
|
87
|
+
print date(d)
|
88
|
+
puts " only in #{names[notnili]}:"
|
89
|
+
puts celebration(compared[notnili])
|
94
90
|
puts
|
91
|
+
next
|
95
92
|
end
|
93
|
+
|
94
|
+
differences = %i(rank colour symbol).select do |property|
|
95
|
+
ca.public_send(property) != cb.public_send(property)
|
96
|
+
end
|
97
|
+
|
98
|
+
next if differences.empty?
|
99
|
+
print date(d)
|
100
|
+
puts " differs in #{differences.join(', ')}"
|
101
|
+
puts celebration(ca)
|
102
|
+
puts celebration(cb)
|
103
|
+
puts
|
96
104
|
end
|
97
105
|
end
|
98
106
|
end
|
107
|
+
|
108
|
+
desc 'version', 'print version information'
|
109
|
+
def version
|
110
|
+
puts 'calendarium-romanum CLI'
|
111
|
+
puts "calendarium-romanum: version #{CalendariumRomanum::VERSION}, released #{CalendariumRomanum::RELEASE_DATE}"
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def date(d)
|
117
|
+
"#{d.month}/#{d.day}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def celebration(c)
|
121
|
+
"#{c.rank.priority} #{c.colour.symbol} | #{c.title}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def die!(message, code = 1)
|
125
|
+
STDERR.puts message
|
126
|
+
exit code
|
127
|
+
end
|
128
|
+
|
129
|
+
def print_single_date(calendar, date)
|
130
|
+
day = calendar.day date
|
131
|
+
|
132
|
+
puts date
|
133
|
+
puts "season: #{day.season.name}"
|
134
|
+
puts
|
135
|
+
|
136
|
+
rank_length = day.celebrations.collect {|c| c.rank.short_desc.nil? ? 0 : c.rank.short_desc.size }.max
|
137
|
+
day.celebrations.each do |c|
|
138
|
+
if [Ranks::PRIMARY, Ranks::TRIDUUM].include? c.rank
|
139
|
+
puts c.title
|
140
|
+
elsif !c.rank.short_desc.nil?
|
141
|
+
print c.rank.short_desc.rjust(rank_length)
|
142
|
+
print ' : '
|
143
|
+
puts c.title
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
99
148
|
end
|
100
149
|
end
|