calendarium-romanum 0.3.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +47 -0
  5. data/.travis.yml +20 -0
  6. data/.yardopts +3 -0
  7. data/CHANGELOG.md +340 -0
  8. data/Gemfile +25 -0
  9. data/Gemfile.lock +86 -0
  10. data/README.md +515 -0
  11. data/Rakefile +9 -0
  12. data/bin/calendariumrom +4 -1
  13. data/calendarium-romanum.gemspec +26 -0
  14. data/config/locales/cs.yml +17 -1
  15. data/config/locales/en.yml +28 -14
  16. data/config/locales/es.yml +90 -0
  17. data/config/locales/fr.yml +90 -0
  18. data/config/locales/it.yml +18 -2
  19. data/config/locales/la.yml +17 -1
  20. data/data/README.md +43 -1
  21. data/data/czech-brno-cs.txt +4 -6
  22. data/data/czech-budejovice-cs.txt +4 -6
  23. data/data/czech-cechy-cs.txt +4 -5
  24. data/data/czech-cs.txt +237 -234
  25. data/data/czech-hradec-cs.txt +3 -5
  26. data/data/czech-litomerice-cs.txt +5 -7
  27. data/data/czech-morava-cs.txt +4 -5
  28. data/data/czech-olomouc-cs.txt +2 -4
  29. data/data/czech-ostrava-cs.txt +3 -5
  30. data/data/czech-plzen-cs.txt +3 -5
  31. data/data/czech-praha-cs.txt +3 -4
  32. data/data/universal-en.txt +214 -211
  33. data/data/universal-es.txt +243 -0
  34. data/data/universal-fr.txt +243 -0
  35. data/data/universal-it.txt +214 -211
  36. data/data/universal-la.txt +214 -210
  37. data/doc/data_readme.md +2 -0
  38. data/doc/images/class_diagram.png +0 -0
  39. data/doc/images/class_diagram.puml +44 -0
  40. data/doc/yard_readme.rdoc +76 -0
  41. data/lib/calendarium-romanum.rb +30 -21
  42. data/lib/calendarium-romanum/abstract_date.rb +12 -0
  43. data/lib/calendarium-romanum/calendar.rb +207 -52
  44. data/lib/calendarium-romanum/cli.rb +101 -52
  45. data/lib/calendarium-romanum/cr.rb +16 -0
  46. data/lib/calendarium-romanum/data.rb +46 -18
  47. data/lib/calendarium-romanum/day.rb +202 -20
  48. data/lib/calendarium-romanum/enum.rb +24 -5
  49. data/lib/calendarium-romanum/enums.rb +102 -36
  50. data/lib/calendarium-romanum/errors.rb +4 -0
  51. data/lib/calendarium-romanum/ordinalizer.rb +30 -6
  52. data/lib/calendarium-romanum/perpetual_calendar.rb +97 -0
  53. data/lib/calendarium-romanum/rank.rb +43 -6
  54. data/lib/calendarium-romanum/sanctorale.rb +170 -24
  55. data/lib/calendarium-romanum/sanctorale_factory.rb +74 -3
  56. data/lib/calendarium-romanum/sanctorale_loader.rb +176 -0
  57. data/lib/calendarium-romanum/temporale.rb +251 -119
  58. data/lib/calendarium-romanum/temporale/celebration_factory.rb +106 -0
  59. data/lib/calendarium-romanum/temporale/dates.rb +117 -36
  60. data/lib/calendarium-romanum/temporale/extensions/christ_eternal_priest.rb +18 -6
  61. data/lib/calendarium-romanum/transfers.rb +20 -1
  62. data/lib/calendarium-romanum/util.rb +36 -3
  63. data/lib/calendarium-romanum/version.rb +5 -1
  64. metadata +29 -21
  65. data/lib/calendarium-romanum/sanctoraleloader.rb +0 -115
  66. data/spec/abstract_date_spec.rb +0 -62
  67. data/spec/calendar_spec.rb +0 -352
  68. data/spec/cli_spec.rb +0 -26
  69. data/spec/data_spec.rb +0 -23
  70. data/spec/date_spec.rb +0 -61
  71. data/spec/dates_spec.rb +0 -45
  72. data/spec/enum_spec.rb +0 -51
  73. data/spec/i18n_spec.rb +0 -59
  74. data/spec/rank_spec.rb +0 -42
  75. data/spec/readme_spec.rb +0 -52
  76. data/spec/sanctorale_factory_spec.rb +0 -42
  77. data/spec/sanctorale_spec.rb +0 -167
  78. data/spec/sanctoraleloader_spec.rb +0 -171
  79. data/spec/spec_helper.rb +0 -35
  80. data/spec/temporale_spec.rb +0 -500
@@ -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
- data_file = Data[options[:calendar]]
15
- if data_file.nil?
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
- calendar = Calendar.for_day(date, sanctorale)
33
- day = calendar.day date
30
+ sanctorale = data_file.load
31
+ end
34
32
 
35
- puts date
36
- puts "season: #{day.season}"
37
- puts
33
+ pcal = PerpetualCalendar.new sanctorale: sanctorale
38
34
 
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
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
- loader.load_from_file path, s
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
- sanctorales = []
65
-
66
- [a, b].each do |source|
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
- celebs = sanctorales.collect {|s| s.get d.month, d.day }
76
- if celebs.find {|cc| cc.nil? }
77
- next
78
- end
77
+ a, b = sanctoralia.collect {|s| s.get(d) }
79
78
 
80
- celebs[0].each_index do |i|
81
- if i >= celebs[1].size
82
- break
83
- end
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
- _print_cel = Proc.new {|c| puts "#{c.rank.priority} #{c.colour} | #{c.title}" }
84
+ if compared.index(&:nil?)
85
+ notnili = compared.index {|c| !c.nil? }
89
86
 
90
- if ca.rank != cb.rank || ca.colour != cb.colour
91
- puts "#{d.month}/#{d.day}"
92
- _print_cel.call ca
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
@@ -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
@@ -1,8 +1,16 @@
1
1
  module CalendariumRomanum
2
- # allows easy access to bundled data files
2
+ # Allows easy access to bundled data files
3
+ #
4
+ # @example
5
+ # sanctorale = CalendariumRomanum::Data::GENERAL_ROMAN_LATIN.load
3
6
  class Data < Enum
4
7
 
5
8
  class SanctoraleFile
9
+ # This class is not intended to be initialized by client code -
10
+ # it's sole purpose is to provide functionality for easy
11
+ # loading of the bundled sanctorale data files.
12
+ #
13
+ # @api private
6
14
  def initialize(base_name)
7
15
  @siglum = base_name.sub(/\.txt$/, '')
8
16
  @path = File.expand_path('../../data/' + base_name, File.dirname(__FILE__))
@@ -10,32 +18,52 @@ module CalendariumRomanum
10
18
 
11
19
  attr_reader :siglum, :path
12
20
 
21
+ # Load the data file
22
+ #
23
+ # @return [Sanctorale]
13
24
  def load
14
- SanctoraleLoader.new.load_from_file(@path)
25
+ SanctoraleLoader.new.load_from_file(path)
26
+ end
27
+
28
+ # Load the data file and all it's parents
29
+ #
30
+ # @return [Sanctorale]
31
+ # @since 0.7.0
32
+ def load_with_parents
33
+ SanctoraleFactory.load_with_parents(path)
15
34
  end
16
35
  end
17
36
 
37
+ GENERAL_ROMAN_LATIN = SanctoraleFile.new('universal-la.txt')
38
+ GENERAL_ROMAN_ENGLISH = SanctoraleFile.new('universal-en.txt')
39
+ GENERAL_ROMAN_FRENCH = SanctoraleFile.new('universal-fr.txt')
40
+ GENERAL_ROMAN_ITALIAN = SanctoraleFile.new('universal-it.txt')
41
+ GENERAL_ROMAN_SPANISH = SanctoraleFile.new('universal-es.txt')
42
+ CZECH = SanctoraleFile.new('czech-cs.txt')
43
+
18
44
  values(index_by: :siglum) do
19
45
  # only calendars of broader interest have constants defined
20
46
  [
21
- GENERAL_ROMAN_LATIN = SanctoraleFile.new('universal-la.txt'),
22
- GENERAL_ROMAN_ENGLISH = SanctoraleFile.new('universal-en.txt'),
23
- GENERAL_ROMAN_ITALIAN = SanctoraleFile.new('universal-it.txt'),
24
- CZECH = SanctoraleFile.new('czech-cs.txt')
47
+ GENERAL_ROMAN_LATIN,
48
+ GENERAL_ROMAN_ENGLISH,
49
+ GENERAL_ROMAN_FRENCH,
50
+ GENERAL_ROMAN_ITALIAN,
51
+ GENERAL_ROMAN_SPANISH,
52
+ CZECH,
25
53
  ] \
26
54
  +
27
- %w(
28
- czech-brno-cs.txt
29
- czech-budejovice-cs.txt
30
- czech-cechy-cs.txt
31
- czech-hradec-cs.txt
32
- czech-litomerice-cs.txt
33
- czech-morava-cs.txt
34
- czech-olomouc-cs.txt
35
- czech-ostrava-cs.txt
36
- czech-plzen-cs.txt
37
- czech-praha-cs.txt
38
- ).collect {|basename| SanctoraleFile.new(basename) }
55
+ %w(
56
+ czech-brno-cs.txt
57
+ czech-budejovice-cs.txt
58
+ czech-cechy-cs.txt
59
+ czech-hradec-cs.txt
60
+ czech-litomerice-cs.txt
61
+ czech-morava-cs.txt
62
+ czech-olomouc-cs.txt
63
+ czech-ostrava-cs.txt
64
+ czech-plzen-cs.txt
65
+ czech-praha-cs.txt
66
+ ).collect {|basename| SanctoraleFile.new(basename) }
39
67
  end
40
68
  end
41
69
  end
@@ -2,52 +2,156 @@ require 'forwardable'
2
2
 
3
3
  module CalendariumRomanum
4
4
 
5
- # information on one particular day of the liturgical year
5
+ # Information on one particular day of the liturgical year
6
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
7
+ # Note: despite of all constructor arguments being nullable,
8
+ # instances returned by {Calendar} always have all of them set,
9
+ # the only exception being +vespers+.
10
+ #
11
+ # @param date [Date, nil]
12
+ # @param season [Season, nil]
13
+ # @param season_week [Fixnum, nil]
14
+ # @param celebrations [Array<Celebration>, nil]
15
+ # @param vespers [Celebration, nil]
16
+ def initialize(date: nil, season: nil, season_week: nil, celebrations: nil, vespers: nil)
17
+ @date = date
18
+ @season = season
19
+ @season_week = season_week
20
+ @celebrations = celebrations ? celebrations.dup : []
21
+ @vespers = vespers
17
22
  end
18
23
 
24
+ # @return [Date]
19
25
  attr_reader :date
20
26
 
27
+ # Weekday as integer (Sunday is 0)
28
+ #
29
+ # @return [Fixnum]
21
30
  def weekday
22
31
  date.wday
23
32
  end
24
33
 
25
- # one of the Seasons (Symbol)
34
+ # Weekday as internationalized string
35
+ #
36
+ # @return [String]
37
+ # @since 0.7.0
38
+ def weekday_name
39
+ I18n.t(date.wday, scope: 'weekday')
40
+ end
41
+
42
+ # @return [Season]
26
43
  attr_reader :season
27
44
 
28
- # week of the season (Integer)
45
+ # Week of the season
46
+ #
47
+ # @return [Fixnum]
29
48
  attr_reader :season_week
30
49
 
31
- # an Array of Celebrations, possibly empty
50
+ # List of celebrations for the given day.
51
+ #
52
+ # In tests and other "less-standard" situations the array
53
+ # may be empty, but it's never empty for instances
54
+ # returned by {Calendar}.
55
+ #
56
+ # @return [Array<Celebration>]
32
57
  attr_reader :celebrations
58
+
59
+ # {Celebration} whose first Vespers are celebrated
60
+ # in place of Vespers of the day's {Celebration}(s).
61
+ # Please note that {Calendar} by default _doesn't_ populate
62
+ # Vespers, - it's an opt-in feature
63
+ # (see {Calendar#initialize}, {Calendar#populates_vespers?},
64
+ # {Calendar#day}).
65
+ #
66
+ # @return [Celebration, nil]
67
+ # @since 0.5.0
68
+ attr_reader :vespers
69
+
70
+ def ==(other)
71
+ self.class == other.class &&
72
+ date == other.date &&
73
+ season == other.season &&
74
+ season_week == other.season_week &&
75
+ celebrations == other.celebrations &&
76
+ vespers == other.vespers
77
+ end
78
+
79
+ # Are the day's Vespers suppressed in favour of first Vespers
80
+ # of a Sunday or solemnity?
81
+ #
82
+ # @return [Boolean]
83
+ def vespers_from_following?
84
+ !vespers.nil?
85
+ end
86
+
87
+ # String representation of the instance listing it's contents.
88
+ # Intended mostly for debugging purposes.
89
+ #
90
+ # @return [String]
91
+ # @since 0.7.0
92
+ def to_s
93
+ celebrations_string = '['
94
+ celebrations.each do |c|
95
+ celebrations_string << c.to_s + ', '
96
+ end
97
+ celebrations_string = celebrations_string.chomp(', ') << ']'
98
+ "#<#{self.class.name} @date=#{date} @season=#{season} @season_week=#{season_week} celebrations=#{celebrations_string} vespers=#{vespers.inspect}>"
99
+ end
33
100
  end
34
101
 
35
- # information on one particular celebration of the liturgical year
102
+ # One particular celebration of the liturgical year
36
103
  # (like a Sunday, feast or memorial);
37
- # some days have no (ferial office is used), some have one,
38
- # some have more among which one may and may not be chosen
104
+ # some days have one,
105
+ # some have more among which one is to be chosen
39
106
  class Celebration
40
107
  extend Forwardable
41
108
 
42
- def initialize(title='', rank=Ranks::FERIAL, colour=Colours::GREEN)
109
+ # @param title [String|Proc]
110
+ # Celebration title/name.
111
+ # If a +Proc+ is passed, it is expected not to receive
112
+ # arguments and to return a +String+.
113
+ # (Used for celebration titles which have to be
114
+ # internationalizable - the +Proc+ is called whenever
115
+ # {#title} is invoked, which allows the value to vary
116
+ # depending e.g. on state of the +Proc+ or some
117
+ # global setting - like +I18n.locale+ - it may access.)
118
+ # @param rank [Rank] Celebration rank
119
+ # @param colour [Colour] Liturgical colour
120
+ # @param symbol [Symbol, nil]
121
+ # Unique machine-readable identifier of the celebration
122
+ # @param date [AbstractDate, nil]
123
+ # Normal fixed date of the celebration
124
+ # @param cycle [:sanctorale, :temporale]
125
+ # Cycle the celebration belongs to
126
+ def initialize(title = '', rank = Ranks::FERIAL, colour = Colours::GREEN, symbol = nil, date = nil, cycle = :sanctorale)
43
127
  @title = title
44
128
  @rank = rank
45
129
  @colour = colour
130
+ @symbol = symbol
131
+ @date = date
132
+ @cycle = cycle
46
133
  end
47
134
 
135
+ # @return [Rank]
48
136
  attr_reader :rank
49
- def_delegators :@rank, :solemnity?, :feast?, :memorial?
50
137
 
138
+ # @!method solemnity?
139
+ # @return [Boolean]
140
+ # @!method feast?
141
+ # @return [Boolean]
142
+ # @!method memorial?
143
+ # @return [Boolean]
144
+ # @!method sunday?
145
+ # @return [Boolean]
146
+ # @since 0.6.0
147
+ # @!method ferial?
148
+ # @return [Boolean]
149
+ # @since 0.6.0
150
+ def_delegators :@rank, :solemnity?, :feast?, :memorial?, :sunday?, :ferial?
151
+
152
+ # Feast title/name
153
+ #
154
+ # @return [String]
51
155
  def title
52
156
  if @title.respond_to? :call
53
157
  @title.call
@@ -56,7 +160,85 @@ module CalendariumRomanum
56
160
  end
57
161
  end
58
162
 
163
+ # Liturgical colour
164
+ #
165
+ # @return [Colour]
59
166
  attr_reader :colour
60
- alias_method :color, :colour
167
+ alias color colour
168
+
169
+ # Symbol uniquely identifying the celebration
170
+ #
171
+ # @return [Symbol, nil]
172
+ # @since 0.5.0
173
+ attr_reader :symbol
174
+
175
+ # Usual date of the celebration.
176
+ #
177
+ # Only set for celebrations with fixed date.
178
+ # (Only) In case of solemnities it may happen that
179
+ # {Celebration#date} differs from {Day#date} due to
180
+ # transfer of an impeded solemnity.
181
+ #
182
+ # @return [AbstractDate, nil]
183
+ # @since 0.6.0
184
+ attr_reader :date
185
+
186
+ # Describes the celebration as belonging either to the
187
+ # temporale or sanctorale cycle
188
+ #
189
+ # @return [:sanctorale, :temporale]
190
+ # @since 0.6.0
191
+ attr_reader :cycle
192
+
193
+ def ==(b)
194
+ self.class == b.class &&
195
+ title == b.title &&
196
+ rank == b.rank &&
197
+ colour == b.colour &&
198
+ symbol == b.symbol &&
199
+ date == b.date &&
200
+ cycle == b.cycle
201
+ end
202
+
203
+ # Does the celebration belong to the temporale cycle?
204
+ #
205
+ # @return [Boolean]
206
+ # @since 0.6.0
207
+ def temporale?
208
+ cycle == :temporale
209
+ end
210
+
211
+ # Does the celebration belong to the sanctorale cycle?
212
+ #
213
+ # @return [Boolean]
214
+ # @since 0.6.0
215
+ def sanctorale?
216
+ cycle == :sanctorale
217
+ end
218
+
219
+ # Build a new instance using the receiver's attributes
220
+ # for all properties for which (a non-nil) value was not passed.
221
+ #
222
+ # @return [Celebration]
223
+ # @since 0.5.0
224
+ def change(title: nil, rank: nil, colour: nil, color: nil, symbol: nil, date: nil, cycle: nil)
225
+ self.class.new(
226
+ title || self.title,
227
+ rank || self.rank,
228
+ colour || color || self.colour,
229
+ symbol || self.symbol,
230
+ date || self.date,
231
+ cycle || self.cycle,
232
+ )
233
+ end
234
+
235
+ # String representation of the object's contents
236
+ # (not very pretty, intended mostly for development inspections).
237
+ #
238
+ # @return [String]
239
+ # @since 0.7.0
240
+ def to_s
241
+ "#<#{self.class.name} @title=\"#{title}\" @rank=#{rank} @colour=#{colour} symbol=#{symbol.inspect} date=#{date.inspect} cycle=#{cycle.inspect}>"
242
+ end
61
243
  end
62
244
  end