citeproc 1.1.0 → 1.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db40316ba1ffbee282afc7c803b98fc2205c4687f2ccfad319661ce8bccacbaa
4
- data.tar.gz: 0c95ef58ae66fb9101dce5e91d70b760ed93dc6aa15a1ce18356af1b38c9a2af
3
+ metadata.gz: 8708658d44ed66deb17744c846697187edbcd1f6dc308c4bf3bc69933ede3e7e
4
+ data.tar.gz: 1d1af4037b6dae14f20adffdbb7e51b35ecd02728586f95932348416788347c1
5
5
  SHA512:
6
- metadata.gz: 2db1938d6f1f5b8248f5e9f97d1c242055a695cd2dea7b26f96cfe8b7bdca30eed1e21fe9630adc96b2f22920c117cacf8255dfb18de10e034e80745c084f157
7
- data.tar.gz: 339dea1c644ca79ca5379d2094b4f08f1fa41058053f511fd0e52b072349a880a3b8721e2ed82498b50ded6f74b57eff42eebc6a77e2cb70dbd9f2643870a601
6
+ metadata.gz: 4dc2d276583d4071cf17459265a3c706f8eb4091c59527a80506241e8f5187de4eba9f6cb140e560327fde38f8e8225348818dfeda0e1b2b98ef53acb67c5064
7
+ data.tar.gz: 33de631e29bd0e3484a0509e4f61bfb4e2b59fe87aeb8e7cbd25c1d9065ce20588637725f00d9f88ab2e19bcee765d3a19bc71d25adced9135d6a74627018279
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  CiteProc
2
2
  ========
3
- CiteProc is a cite processor interface and citation data API based on the
4
- Citation Style Language (CSL) specifications. To actually process citations
5
- a dedicated processor engine is required; a pure Ruby engine is available
6
- in the [citeproc-ruby](https://rubygems.org/gems/citeproc-ruby) gem.
3
+ CiteProc is a cite processor interface and citation data API
4
+ based on the Citation Style Language (CSL) specifications.
5
+ To actually process citations a dedicated processor engine is required;
6
+ a pure Ruby engine is available in the
7
+ [citeproc-ruby](https://rubygems.org/gems/citeproc-ruby) gem.
7
8
 
8
9
  Quickstart
9
10
  ----------
@@ -12,117 +13,117 @@ Install CiteProc-Ruby and all official CSL styles (optional).
12
13
  $ [sudo] gem install citeproc-ruby
13
14
  $ [sudo] gem install csl-styles
14
15
 
15
- Start rendering you references with any CSL style!
16
+ Start rendering your references with any CSL style!
16
17
 
17
18
  require 'citeproc'
18
19
  require 'csl/styles'
20
+ require 'bibtex'
19
21
 
20
- # Create a new processor with the desired style,
21
- # format, and locale.
22
+ # Create a new processor
23
+ # with the desired style, format, and locale.
22
24
  cp = CiteProc::Processor.new style: 'apa', format: 'text'
23
25
 
24
- # To see what styles are available in your current
25
- # environment, run `CSL::Style.ls'; this also works for
26
- # locales as `CSL::Locale.ls'.
26
+ # To see what styles are available in your current environment,
27
+ # run `CSL::Style.ls';
28
+ # this also works for locales as `CSL::Locale.ls'.
27
29
 
28
- # Tell the processor where to find your references. In this
29
- # example we load them from a BibTeX bibliography using the
30
- # bibtex-ruby gem.
30
+ # Tell the processor where to find your references.
31
+ # In this example we load them from a BibTeX bibliography
32
+ # using the bibtex-ruby gem (`gem install bibtex-ruby').
31
33
  cp.import BibTeX.open('./references.bib').to_citeproc
32
34
 
33
- # Now you are ready for rendering; the processor API
34
- # provides three main rendering methods: `process',
35
- # `append', or `bibliography'.
35
+ # Now you are ready for rendering;
36
+ # the processor API provides two main rendering methods:
37
+ # `process' and `bibliography'.
36
38
 
37
- # For simple one-off renditions, you can also call
38
- # `render' in bibliography or citation mode:
39
+ # For simple one-off renditions,
40
+ # you can also call `render' in bibliography or citation mode:
39
41
  cp.render :bibliography, id: 'knuth'
40
42
 
41
43
  # This will return a rendered reference, like:
42
- #-> Knuth, D. (1968). The art of computer programming. Boston: Addison-Wesley.
43
-
44
- # CiteProc-Ruby exposes a full CSL API to you; this
45
- # makes it possible to just alter CSL styles on the
46
- # fly. For example, what if we want names not to be
47
- # initialized even though APA style is configured to
48
- # do so? We could change the CSL style itself, but
49
- # we can also make a quick adjustment at runtime:
50
- name = cp.engine.style.macros['author'] > 'names' > 'name'
51
-
52
- # What just happened? We selected the current style's
53
- # 'author' macro and then descended to the CSL name
54
- # node via its parent names node. Now we can change
55
- # this name node and the cite processor output will
56
- # pick-up the changes right away:
57
- name[:initialize] = 'false'
44
+ #-> Knuth, D. (1968). The art of computer programming (Vol. 1). Addison-Wesley.
45
+
46
+ # CiteProc-Ruby exposes a full CSL API to you;
47
+ # this makes it possible to just alter CSL styles on the fly.
48
+ # For example, what if we want names not to be initialized
49
+ # even though APA style is configured to do so?
50
+ # We could change the CSL style itself,
51
+ # but we can also make a quick adjustment at runtime:
52
+ cp.engine.style.macros['author-bib'].each_descendant do |node|
53
+ node[:initialize] = 'false' if node.nodename == 'name'
54
+ end
55
+
56
+ # What just happened?
57
+ # We selected the current style's 'author-bib' macro
58
+ # and changed all of its CSL name nodes;
59
+ # the cite processor output will pick-up the changes right away:
58
60
 
59
61
  cp.render :bibliography, id: 'knuth'
60
- #-> Knuth, Donald. (1968). The art of computer programming (Vol. 1). Boston: Addison-Wesley.
62
+ #-> Knuth, Donald. (1968). The art of computer programming (Vol. 1). Addison-Wesley.
61
63
 
62
64
  # Note that we have picked 'text' as the output format;
63
- # if we want to make us of richer output formats we
64
- # can switch to HTML instead:
65
+ # if we want to make use of richer output formats
66
+ # we can switch to HTML instead:
65
67
  cp.engine.format = 'html'
66
68
 
67
69
  cp.render :bibliography, id: 'knuth'
68
- #-> Knuth, Donald. (1968). <i>The art of computer programming</i> (Vol. 1). Boston: Addison-Wesley.
70
+ #-> Knuth, Donald. (1968). <i>The art of computer programming</i> (Vol. 1). Addison-Wesley.
69
71
 
70
72
  # You can also render citations on the fly.
71
- cp.render :citation, id: 'knuth', locator: '23'
73
+ cp.render :citation, id: 'knuth', locator: '23', label: 'page'
72
74
  #-> (Knuth, 1968, p. 23)
73
75
 
74
76
  Documentation
75
77
  -------------
76
- * [CiteProc Documentation](http://rubydoc.info/gems/citeproc/)
77
- * [CiteProc-Ruby API Documentation](http://rubydoc.info/gems/citeproc-ruby/)
78
- * [CSL-Ruby API Documentation](http://rubydoc.info/gems/csl/)
78
+ * [CiteProc Documentation](https://rubydoc.info/gems/citeproc/)
79
+ * [CiteProc-Ruby API Documentation](https://rubydoc.info/gems/citeproc-ruby/)
80
+ * [CSL-Ruby API Documentation](https://rubydoc.info/gems/csl/)
79
81
 
80
82
  Optional Dependencies
81
83
  ---------------------
82
84
  CiteProc-Ruby tries to minimize hard dependencies for increased compatibility.
83
85
  You can speed up the XML parsing by installing
84
- [Nokogiri](https://rubygems.org/gems/nokogiri); otherwise the REXML from the
85
- Ruby standard library will be used.
86
+ [Nokogiri](https://rubygems.org/gems/nokogiri);
87
+ otherwise the REXML from the Ruby standard library will be used.
86
88
 
87
- Similarly, you can install either of the gems
88
- [EDTF](https://rubygems.org/gems/edtf) or
89
- [Chronic](https://rubygems.org/gems/chronic) to support a wide range of
90
- additional inputs for date variables.
89
+ Similarly, you can install the
90
+ [EDTF](https://rubygems.org/gems/edtf)
91
+ gem to support a wide range of additional inputs for date variables.
91
92
 
92
93
  CSL Styles and Locales
93
94
  ----------------------
94
- You can load CSL styles and locales by passing a respective XML string, file
95
- name, or URL. You can also load styles and locales by name if the
96
- corresponding files are installed in your local styles and locale directories.
95
+ You can load CSL styles and locales
96
+ by passing a respective XML string, file name, or URL.
97
+ You can also load styles and locales by name
98
+ if the corresponding files are installed
99
+ in your local styles and locale directories.
97
100
  By default, CSL-Ruby looks for CSL styles and locale files in
98
101
 
99
102
  /usr/local/share/csl/styles
100
103
  /usr/local/share/csl/locales
101
104
 
102
- You can change these locations by changing the value of `CSL::Style.root` and
103
- `CSL::Locale.root` respectively.
105
+ You can change these locations
106
+ by changing the value of `CSL::Style.root` and `CSL::Locale.root` respectively.
104
107
 
105
- Alternatively, you can `gem install csl-styles` to install all official CSL
106
- styles and locales. To make the styles and locales available, simply
107
- `require 'csl/styles`.
108
-
109
- Compatibility
110
- -------------
111
- The cite processor and the CSL API libraries have been developed for MRI,
112
- Rubinius, and JRuby. Please note that we try to support only Ruby versions
113
- 1.9.3 and upwards.
108
+ Alternatively, you can `gem install csl-styles`
109
+ to install all official CSL styles and locales.
110
+ To make the styles and locales available,
111
+ simply `require 'csl/styles'`.
114
112
 
115
113
  Credits
116
114
  -------
117
115
  Thanks to Rintze M. Zelle, Sebastian Karcher, Frank G. Bennett, Jr.,
118
- and Bruce D'Arcus of CSL and citeproc-js fame for their support!
116
+ and Bruce D'Arcus of CSL and citeproc-js fame
117
+ for their support!
119
118
 
120
- Thanks to Google and the Berkman Center at Harvard University for supporting
121
- this project as part of [Google Summer of Code](https://developers.google.com/open-source/soc/).
119
+ Thanks to Google and the Berkman Center at Harvard University
120
+ for supporting this project as part of
121
+ [Google Summer of Code](https://developers.google.com/open-source/soc/).
122
122
 
123
123
  Copyright
124
124
  ---------
125
- Copyright 2009-2025 Sylvester Keil. All rights reserved.
125
+ Copyright 2009-2026 Sylvester Keil.
126
+ All rights reserved.
126
127
 
127
128
  Copyright 2012 President and Fellows of Harvard College.
128
129
 
@@ -37,7 +37,7 @@ module CiteProc
37
37
  return false if value.nil?
38
38
  return false if value.respond_to?(:empty?) && value.empty?
39
39
 
40
- value.to_s !~ /^(false|no|never)$/i
40
+ value.to_s !~ /^(false|no|never|0)$/i
41
41
  end
42
42
 
43
43
  def filter_key(key)
@@ -108,7 +108,7 @@ module CiteProc
108
108
  case
109
109
  when equal?(other)
110
110
  true
111
- when self.class != other.class, length != other.length
111
+ when self.class != other.class, attributes.length != other.attributes.length
112
112
  false
113
113
  else
114
114
  other.attributes.each_pair do |key, value|
@@ -193,7 +193,7 @@ module CiteProc
193
193
  end
194
194
 
195
195
  def hanging_indent?
196
- options[:'hanging_indent']
196
+ CiteProc.boolean(options[:'hanging-indent'])
197
197
  end
198
198
 
199
199
  def join()
@@ -11,12 +11,72 @@ module CiteProc
11
11
  include Comparable
12
12
 
13
13
  @labels = [
14
- :book, :chapter, :column, :figure, :folio, :issue, :line, :note, :opus,
15
- :page, :paragraph, :part, :section, :'sub-verbo', :verse, :volume
14
+ :act,
15
+ :appendix,
16
+ :'article-locator',
17
+ :book,
18
+ :canon,
19
+ :chapter,
20
+ :column,
21
+ :elocation,
22
+ :equation,
23
+ :figure,
24
+ :folio,
25
+ :issue,
26
+ :line,
27
+ :note,
28
+ :opus,
29
+ :page,
30
+ :paragraph,
31
+ :part,
32
+ :rule,
33
+ :scene,
34
+ :section,
35
+ :'sub-verbo',
36
+ :supplement,
37
+ :table,
38
+ :timestamp,
39
+ :'title-locator',
40
+ :verse,
41
+ :version,
42
+ :volume
16
43
  ].freeze
17
44
 
45
+ # Abbreviations of locator labels (for extraction)
46
+ @locator_abbreviations = {
47
+ 'app.' => 'appendix',
48
+ 'art.' => 'article-locator',
49
+ 'bk.' => 'book',
50
+ 'ch.' => 'chapter',
51
+ 'col.' => 'column',
52
+ 'fig.' => 'figure',
53
+ 'fol.' => 'folio',
54
+ 'l.' => 'line',
55
+ 'n.' => 'note',
56
+ 'no.' => 'issue',
57
+ 'op.' => 'opus',
58
+ 'p.' => 'page',
59
+ 'pp.' => 'page',
60
+ 'para.' => 'paragraph',
61
+ 'pt.' => 'part',
62
+ 'r.' => 'rule',
63
+ 'sec.' => 'section',
64
+ 'supp.' => 'supplement',
65
+ 'sv.' => 'sub-verbo',
66
+ 'tbl.' => 'table',
67
+ 'tit.' => 'title-locator',
68
+ 'vol.' => 'volume',
69
+ 'vrs.' => 'verse'
70
+ }.freeze
71
+
18
72
  class << self
19
- attr_reader :labels
73
+ attr_reader :labels, :locator_abbreviations
74
+
75
+ # @param abbreviations [Hash<String,String>] label abbreviations
76
+ # @return [Regexp] a pattern matching any of the abbreviations
77
+ def locator_label_pattern(abbreviations = locator_abbreviations)
78
+ Regexp.union(abbreviations.keys.sort_by { |abbr| -abbr.length })
79
+ end
20
80
  end
21
81
 
22
82
  # @!attribute id
@@ -66,6 +126,32 @@ module CiteProc
66
126
  yield self if block_given?
67
127
  end
68
128
 
129
+ # @return [String, nil] the locator label;
130
+ # defaults to "page" if there is a locator
131
+ def label
132
+ read_attribute(:label) || ('page' if locator?)
133
+ end
134
+
135
+ # Moves a label at the start of the locator into the label
136
+ # (e.g., "vol. 1" becomes "1" with the label "volume") unless
137
+ # the item has a label other than "page".
138
+ #
139
+ # @param abbreviations [Hash<String,String>] label abbreviations
140
+ # @return [self]
141
+ def parse_locator!(abbreviations = CitationItem.locator_abbreviations)
142
+ return self unless locator? && label.to_s == 'page'
143
+
144
+ pattern = CitationItem.locator_label_pattern(abbreviations)
145
+ match = /\A(#{pattern})\s+(.+)\z/m.match(locator.to_s)
146
+
147
+ unless match.nil?
148
+ self.label = abbreviations[match[1]]
149
+ self.locator = match[2]
150
+ end
151
+
152
+ self
153
+ end
154
+
69
155
  def initialize_copy(other)
70
156
  @attributes = other.attributes.deep_copy
71
157
  end
@@ -83,8 +169,6 @@ module CiteProc
83
169
  end
84
170
 
85
171
 
86
-
87
-
88
172
  class CitationData
89
173
 
90
174
  extend Forwardable
@@ -7,8 +7,6 @@
7
7
  if RUBY_PLATFORM =~ /java/i
8
8
  require 'java'
9
9
 
10
- puts java.lang.System.getProperty('file.encoding')
11
-
12
10
  module CiteProc
13
11
  def upcase(string)
14
12
  java.lang.String.new(string).to_upper_case(java.util.Locale::ENGLISH).to_s
@@ -22,39 +20,12 @@ if RUBY_PLATFORM =~ /java/i
22
20
  else
23
21
 
24
22
  module CiteProc
25
- if RUBY_VERSION >= '2.4'
26
- def upcase(string)
27
- string.upcase
28
- end
29
-
30
- def downcase(string)
31
- string.downcase
32
- end
33
- else
34
- # Ruby 2.3 and older require extra Gems
35
- begin
36
- require 'unicode_utils'
37
- def upcase(string)
38
- UnicodeUtils.upcase(string)
39
- end
40
-
41
- def downcase(string)
42
- UnicodeUtils.downcase(string)
43
- end
44
- rescue LoadError
45
- begin
46
- require 'unicode'
47
- def upcase(string)
48
- Unicode.upcase(string)
49
- end
23
+ def upcase(string)
24
+ string.upcase
25
+ end
50
26
 
51
- def downcase(string)
52
- Unicode.downcase(string)
53
- end
54
- rescue LoadError
55
- warn "CiteProc requires the `unicode_utils` or `unicode` Gem on Ruby 2.3"
56
- end
57
- end
27
+ def downcase(string)
28
+ string.downcase
58
29
  end
59
30
  end
60
31
  end
data/lib/citeproc/date.rb CHANGED
@@ -7,8 +7,8 @@ module CiteProc
7
7
  #
8
8
  # {Date Dates} can be constructed from a wide range of input values,
9
9
  # including Ruby date objects, integers, date ranges, ISO 8601 and
10
- # CiteProc JSON strings or hashes, and - provided you have the respective
11
- # gems installed - EDTF strings all strings supported by Chronic.
10
+ # CiteProc JSON strings or hashes, and - provided you have the EDTF gem
11
+ # installed - EDTF strings.
12
12
  #
13
13
  # @example Initialization
14
14
  # CiteProc::Date.new
@@ -17,9 +17,6 @@ module CiteProc
17
17
  # CiteProc::Date.today
18
18
  # #-> #<CiteProc::Date "[2012, 6, 10]">
19
19
  #
20
- # CiteProc::Date.new('Yesterday')
21
- # #-> #<CiteProc::Date "[[2012, 6, 9]]">
22
- #
23
20
  # CiteProc::Date.new(1966)
24
21
  # #-> #<CiteProc::Date "[1966]">
25
22
  #
@@ -129,6 +126,18 @@ module CiteProc
129
126
  !bc? && year < 1000
130
127
  end
131
128
 
129
+ # Seasons may be encoded as months 21 to 24 (Spring to Winter).
130
+ # @return [Integer, nil] the season (1 to 4) or nil if the
131
+ # month does not encode a season
132
+ def season
133
+ month - 20 if month && month.between?(21, 24)
134
+ end
135
+
136
+ # @return [Boolean] whether or not the month encodes a season
137
+ def season?
138
+ !season.nil?
139
+ end
140
+
132
141
  # Formats the date parts according to the passed-in format string.
133
142
  # @param format [String] a format string
134
143
  # @return [String,nil] the formatted date string; nil if the date
@@ -148,8 +157,10 @@ module CiteProc
148
157
  # @return [Fixnum,nil] the result of the comparison (-1, 0, 1 or nil)
149
158
  def <=>(other)
150
159
  case
160
+ when other.is_a?(DateParts) && season? && other.season?
161
+ [year, season] <=> [other.year, other.season]
151
162
  when other.is_a?(DateParts)
152
- to_citeproc <=> other.to_citeproc
163
+ comparable <=> other.comparable
153
164
  when other.respond_to?(:to_date)
154
165
  to_date <=> other.to_date
155
166
  else
@@ -192,6 +203,14 @@ module CiteProc
192
203
  def inspect
193
204
  "#<DateParts #{to_s}>"
194
205
  end
206
+
207
+ protected
208
+
209
+ # Seasons are compared like dates without month.
210
+ # @return [Array<Fixnum>] the date parts used for comparison
211
+ def comparable
212
+ season? ? to_citeproc.take(1) : to_citeproc
213
+ end
195
214
  end
196
215
 
197
216
  #
@@ -210,13 +229,11 @@ module CiteProc
210
229
  # List of date parsers (must respond to #parse)
211
230
  @parsers = []
212
231
 
213
- [%w{ edtf EDTF }, %w{ chronic Chronic }].each do |date_parser, module_id|
214
- begin
215
- require date_parser
216
- @parsers << ::Object.const_get(module_id)
217
- rescue LoadError
218
- # warn "failed to load `#{date_parser}' gem"
219
- end
232
+ begin
233
+ require 'edtf'
234
+ @parsers << ::EDTF
235
+ rescue LoadError
236
+ # warn "failed to load `edtf' gem"
220
237
  end
221
238
 
222
239
  @parsers << ::Date
@@ -229,9 +246,8 @@ module CiteProc
229
246
  # A list of available date parsers. Each parser must respond to a
230
247
  # #parse method that converts a date string into a Ruby date object.
231
248
  # By default, the list will include Ruby's date parser from the
232
- # standard library, as well as the parsers of the Chronic and EDTF
233
- # gems if they are available; to install the latter on your system
234
- # make sure to `gem install chronic edtf`.
249
+ # standard library, as well as the parser of the EDTF gem if it is
250
+ # available; to install it on your system run `gem install edtf`.
235
251
  #
236
252
  # @return [Array] the available date parsers
237
253
  attr_reader :parsers
@@ -276,12 +292,44 @@ module CiteProc
276
292
  end
277
293
 
278
294
 
279
- # Make Date behave like a regular Ruby Date
280
- def_delegators :to_ruby, *::Date.instance_methods(false).reject { |m|
281
- m.to_s =~ /^[\W_]|[!=_]$|^(to_s|inspect|dup|clone|change)$|^(marshal|season|year|month|day|certain|uncertain)/
282
- }
295
+ def_delegators :to_ruby, :strftime
296
+
297
+ attr_predicates :circa, :literal, :'date-parts'
298
+
299
+ # @return [Boolean] whether or not the date has a season field
300
+ def has_season?
301
+ attribute?(:season)
302
+ end
303
+
304
+ def season=(season)
305
+ write_attribute :season, season
306
+ end
307
+
308
+ # Season names recognized in the season field
309
+ SEASONS = {
310
+ 'spring' => 1, 'summer' => 2, 'autumn' => 3, 'fall' => 3, 'winter' => 4
311
+ }.freeze
312
+
313
+ # A season takes the place of the month. If the (start) date has a
314
+ # month, the season is encoded by the month (21 to 24); otherwise
315
+ # the season field is used. Season numbers (1 to 4) and names in
316
+ # the season field are converted to integers.
317
+ #
318
+ # @return [Integer, String, nil] the season (1 to 4), the season
319
+ # field as a string if it is not a season number or name, or nil
320
+ def season
321
+ return parts[0].season if month
283
322
 
284
- attr_predicates :circa, :season, :literal, :'date-parts'
323
+ value = read_attribute(:season) or return
324
+ name = value.to_s.strip.downcase
325
+
326
+ SEASONS[name] || (name.match?(/\A[1-4]\z/) ? name.to_i : value.to_s)
327
+ end
328
+
329
+ # @return [Boolean] whether or not the date has a season (see #season)
330
+ def season?
331
+ !season.nil?
332
+ end
285
333
 
286
334
  def initialize(value = {})
287
335
  super
@@ -321,11 +369,15 @@ module CiteProc
321
369
  when value.is_a?(Hash)
322
370
  attributes = value.symbolize_keys
323
371
 
324
- if attributes.has_key?(:raw)
325
- @value = Date.parse(attributes.delete(:raw)).value
372
+ if attributes.has_key?(:raw) && Array(attributes[:'date-parts']).empty?
373
+ raw = attributes.delete(:raw)
374
+ attributes.delete(:'date-parts')
375
+ date = Date.parse(raw)
376
+
377
+ @value = date.nil? ? { :literal => raw } : date.value
326
378
  @value.merge!(attributes)
327
379
  else
328
- @value = attributes.deep_copy
380
+ @value = attributes.except(:raw).deep_copy
329
381
  end
330
382
  convert_parts!
331
383
 
@@ -397,34 +449,16 @@ module CiteProc
397
449
  d
398
450
  end
399
451
 
400
- # @return [::Date,nil] the date (start date if this instance is a range); or nil
401
- def start_date
402
- d = parts[0] and d.to_date
403
- end
404
-
405
- def start_date=(date)
406
- parts[0] = DateParts.new(date.strftime('%Y-%m-%d').split(/-/))
407
- end
408
-
409
- def end_date=(date)
410
- parts[1] = DateParts.new(date.nil? ? 0 : date.strftime('%Y-%m-%d').split(/-/))
411
- end
412
-
413
- # @return [Date,Range] the date as a Ruby date object or as a Range if
414
- # this instance is closed range
452
+ # @return [::Date, Range, nil] the date as a Ruby date object or as
453
+ # a Range if this instance is closed range
415
454
  def to_ruby
416
455
  if closed_range?
417
- start_date..end_date
456
+ parts[0].to_date..parts[1].to_date
418
457
  else
419
- start_date
458
+ d = parts[0] and d.to_date
420
459
  end
421
460
  end
422
461
 
423
- # @return [::Date,nil] the range's end date; or nil
424
- def end_date
425
- d = parts[1] and d.to_date
426
- end
427
-
428
462
  # @return [Boolean] whether or not the date-parts contain an end date
429
463
  def has_end_date?
430
464
  parts[1] && !parts[1].empty?
@@ -506,7 +540,7 @@ module CiteProc
506
540
  case
507
541
  when literal?
508
542
  literal
509
- when season?
543
+ when has_season?
510
544
  season
511
545
  else
512
546
  parts.map(&:to_citeproc).inspect
@@ -516,8 +550,14 @@ module CiteProc
516
550
  def <=>(other)
517
551
  case other
518
552
  when CiteProc::Date
519
- return nil if season? || other.season?
520
- parts <=> other.parts
553
+ result = parts <=> other.parts
554
+
555
+ # Seasons are ordered among themselves only
556
+ if result == 0 && season? && other.season?
557
+ result = season.to_i <=> other.season.to_i
558
+ end
559
+
560
+ result
521
561
  when ::Date
522
562
  parts <=> [other]
523
563
  else