citeproc 1.2.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 +4 -4
- data/README.md +3 -4
- data/lib/citeproc/attributes.rb +2 -2
- data/lib/citeproc/bibliography.rb +1 -1
- data/lib/citeproc/citation_data.rb +89 -5
- data/lib/citeproc/date.rb +89 -49
- data/lib/citeproc/names.rb +36 -45
- data/lib/citeproc/number.rb +7 -1
- data/lib/citeproc/selector.rb +5 -4
- data/lib/citeproc/utilities.rb +11 -0
- data/lib/citeproc/variable.rb +23 -6
- data/lib/citeproc/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8708658d44ed66deb17744c846697187edbcd1f6dc308c4bf3bc69933ede3e7e
|
|
4
|
+
data.tar.gz: 1d1af4037b6dae14f20adffdbb7e51b35ecd02728586f95932348416788347c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4dc2d276583d4071cf17459265a3c706f8eb4091c59527a80506241e8f5187de4eba9f6cb140e560327fde38f8e8225348818dfeda0e1b2b98ef53acb67c5064
|
|
7
|
+
data.tar.gz: 33de631e29bd0e3484a0509e4f61bfb4e2b59fe87aeb8e7cbd25c1d9065ce20588637725f00d9f88ab2e19bcee765d3a19bc71d25adced9135d6a74627018279
|
data/README.md
CHANGED
|
@@ -86,10 +86,9 @@ You can speed up the XML parsing by installing
|
|
|
86
86
|
[Nokogiri](https://rubygems.org/gems/nokogiri);
|
|
87
87
|
otherwise the REXML from the Ruby standard library will be used.
|
|
88
88
|
|
|
89
|
-
Similarly, you can install
|
|
90
|
-
[EDTF](https://rubygems.org/gems/edtf)
|
|
91
|
-
|
|
92
|
-
to support a wide range of 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.
|
|
93
92
|
|
|
94
93
|
CSL Styles and Locales
|
|
95
94
|
----------------------
|
data/lib/citeproc/attributes.rb
CHANGED
|
@@ -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|
|
|
@@ -11,12 +11,72 @@ module CiteProc
|
|
|
11
11
|
include Comparable
|
|
12
12
|
|
|
13
13
|
@labels = [
|
|
14
|
-
:
|
|
15
|
-
:
|
|
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
|
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
|
|
11
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
233
|
-
#
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
401
|
-
|
|
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
|
-
|
|
456
|
+
parts[0].to_date..parts[1].to_date
|
|
418
457
|
else
|
|
419
|
-
|
|
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
|
|
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
|
-
|
|
520
|
-
|
|
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
|
data/lib/citeproc/names.rb
CHANGED
|
@@ -92,20 +92,19 @@ module CiteProc
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
# Names quack sorta like a String
|
|
95
|
-
def_delegators :to_s,
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
def_delegators :to_s,
|
|
96
|
+
:to_str,
|
|
97
|
+
:=~, :===, :match, :match?, :start_with?, :end_with?, :include?,
|
|
98
|
+
:upcase, :downcase, :capitalize, :sub, :gsub, :split, :strip
|
|
98
99
|
|
|
99
|
-
# Delegate
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
p.send(m, *arguments, &block) if p.respond_to?(m)
|
|
106
|
-
end
|
|
107
|
-
self
|
|
100
|
+
# Delegate in-place transformations to each field's value
|
|
101
|
+
[:gsub!, :sub!, :upcase!, :downcase!, :capitalize!, :strip!].each do |m|
|
|
102
|
+
define_method(m) do |*arguments, &block|
|
|
103
|
+
Name.parts.each do |part|
|
|
104
|
+
p = attributes[part]
|
|
105
|
+
p.send(m, *arguments, &block) if p.respond_to?(m)
|
|
108
106
|
end
|
|
107
|
+
self
|
|
109
108
|
end
|
|
110
109
|
end
|
|
111
110
|
|
|
@@ -236,7 +235,7 @@ module CiteProc
|
|
|
236
235
|
|
|
237
236
|
# @return [Boolean] whether or not initials will be used for printing
|
|
238
237
|
def initials?
|
|
239
|
-
!!options[:'initialize-with'] && personal? && romanesque?
|
|
238
|
+
!!options[:'initialize-with'] && personal? && family? && romanesque?
|
|
240
239
|
end
|
|
241
240
|
|
|
242
241
|
def initialize_with
|
|
@@ -244,7 +243,7 @@ module CiteProc
|
|
|
244
243
|
end
|
|
245
244
|
|
|
246
245
|
def initialize_existing_only?
|
|
247
|
-
options[:initialize]
|
|
246
|
+
!CiteProc.boolean(options[:initialize], true)
|
|
248
247
|
end
|
|
249
248
|
|
|
250
249
|
def initialize_without_hyphen?
|
|
@@ -259,8 +258,6 @@ module CiteProc
|
|
|
259
258
|
case
|
|
260
259
|
when !initials?
|
|
261
260
|
given
|
|
262
|
-
when initialize_existing_only?
|
|
263
|
-
existing_initials_of given
|
|
264
261
|
else
|
|
265
262
|
initials_of given
|
|
266
263
|
end
|
|
@@ -321,7 +318,7 @@ module CiteProc
|
|
|
321
318
|
when literal?
|
|
322
319
|
literal.to_s
|
|
323
320
|
when static_order?
|
|
324
|
-
[family, initials].compact.join(' ')
|
|
321
|
+
[family, initials].compact.join(romanesque? ? ' ' : '')
|
|
325
322
|
when !short_form?
|
|
326
323
|
case
|
|
327
324
|
when !sort_order?
|
|
@@ -356,7 +353,7 @@ module CiteProc
|
|
|
356
353
|
|
|
357
354
|
# @return [String] the name as a string stripped off all markup
|
|
358
355
|
def strip_markup
|
|
359
|
-
gsub(Variable.markup, '')
|
|
356
|
+
to_s.gsub(Variable.markup, '')
|
|
360
357
|
end
|
|
361
358
|
|
|
362
359
|
# @return [self] the name with all parts stripped off markup
|
|
@@ -384,36 +381,30 @@ module CiteProc
|
|
|
384
381
|
|
|
385
382
|
def initials_of(string)
|
|
386
383
|
return unless string
|
|
387
|
-
string = string.dup
|
|
388
|
-
|
|
389
|
-
string.gsub!(/([[:upper:]])[^[:upper:]\s-]*\s*/, "\\1#{initialize_with}")
|
|
390
384
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
string.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
385
|
+
# Split abbreviations like "M.E" into "M. E"
|
|
386
|
+
string = string.gsub(/\.(?=[[:alpha:]])/, '. ')
|
|
387
|
+
string = string.tr('-', ' ') if initialize_without_hyphen?
|
|
388
|
+
|
|
389
|
+
string.scan(/([^\s-]+)\s*(-)?\s*/).map { |part, hyphen|
|
|
390
|
+
part = initial_of(part) || " #{part} "
|
|
391
|
+
hyphen ? "#{part.rstrip}-" : part
|
|
392
|
+
}.join.gsub(/-\s+/, '-').squeeze(' ').strip
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# @return [String, nil] the initial for the given part of a name
|
|
396
|
+
# or nil if the part should not be initialized
|
|
397
|
+
def initial_of(part)
|
|
398
|
+
case part
|
|
399
|
+
when /\A([[:upper:]])\z/, /\A(.+)\.\z/
|
|
400
|
+
"#{$1}#{initialize_with}"
|
|
401
|
+
when /\A[[:upper:]]{2}[[:lower:]]/
|
|
402
|
+
# Two letter initials like "Ts" for "TSerendorjiin"
|
|
403
|
+
"#{part[0, 2].capitalize}#{initialize_with}" unless initialize_existing_only?
|
|
404
|
+
when /\A[[:upper:]]/
|
|
405
|
+
"#{part[0]}#{initialize_with}" unless initialize_existing_only?
|
|
402
406
|
end
|
|
403
407
|
end
|
|
404
|
-
|
|
405
|
-
def existing_initials_of(string)
|
|
406
|
-
return unless string
|
|
407
|
-
string = string.dup
|
|
408
|
-
|
|
409
|
-
string.gsub!(/([[:upper:]])([[:upper:]])/, '\1 \2')
|
|
410
|
-
string.gsub!(/\b([[:upper:]])\b[^[:alpha:]-]*/, "\\1#{initialize_with}")
|
|
411
|
-
|
|
412
|
-
initialize_hyphen!(string)
|
|
413
|
-
|
|
414
|
-
string.strip!
|
|
415
|
-
string
|
|
416
|
-
end
|
|
417
408
|
end
|
|
418
409
|
|
|
419
410
|
|
data/lib/citeproc/number.rb
CHANGED
|
@@ -13,9 +13,15 @@ module CiteProc
|
|
|
13
13
|
['i', 1]
|
|
14
14
|
].freeze
|
|
15
15
|
|
|
16
|
+
# Numbers (with optional prefixes and suffixes) or roman numerals
|
|
17
|
+
RANGE_BOUND = /(?:[[:alnum:]]*\d[[:alnum:]]*|[ivxlcdm]+)/i
|
|
18
|
+
|
|
19
|
+
# Ranges between numbers; escaped hyphens are not range delimiters
|
|
20
|
+
RANGE = /(?<![[:alnum:]])#{RANGE_BOUND}\s*[–-]\s*#{RANGE_BOUND}(?![[:alnum:]])/
|
|
21
|
+
|
|
16
22
|
class << self
|
|
17
23
|
def pluralize?(string)
|
|
18
|
-
/\S[\s
|
|
24
|
+
/\S[\s,&]\S|\df/.match?(string) || RANGE.match?(string)
|
|
19
25
|
end
|
|
20
26
|
|
|
21
27
|
# @param number [#to_i] the number to convert
|
data/lib/citeproc/selector.rb
CHANGED
|
@@ -19,11 +19,12 @@ module CiteProc
|
|
|
19
19
|
|
|
20
20
|
attr_reader :type, :conditions, :skip_conditions, :custom_matcher
|
|
21
21
|
|
|
22
|
-
def initialize(attributes = nil)
|
|
22
|
+
def initialize(attributes = nil, &block)
|
|
23
23
|
@conditions, @skip_conditions = {}, {}
|
|
24
24
|
|
|
25
25
|
if block_given?
|
|
26
26
|
@type = :ruby
|
|
27
|
+
@custom_matcher = block
|
|
27
28
|
|
|
28
29
|
else
|
|
29
30
|
unless attributes.nil? || attributes.empty?
|
|
@@ -54,12 +55,12 @@ module CiteProc
|
|
|
54
55
|
@type = other.type
|
|
55
56
|
@conditions = other.conditions.deep_copy
|
|
56
57
|
@skip_conditions = other.skip_conditions.deep_copy
|
|
57
|
-
@custom_matcher = other
|
|
58
|
+
@custom_matcher = other.custom_matcher
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def type=(type)
|
|
61
62
|
raise TypeError, "failed to set selector type to #{type.inspect}" unless
|
|
62
|
-
type.respond_to(:to_sym) && Selector.types.include?(type.to_sym)
|
|
63
|
+
type.respond_to?(:to_sym) && Selector.types.include?(type.to_sym)
|
|
63
64
|
|
|
64
65
|
@type = type.to_sym
|
|
65
66
|
end
|
|
@@ -69,7 +70,7 @@ module CiteProc
|
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
def custom_matcher?
|
|
72
|
-
|
|
73
|
+
!custom_matcher.nil?
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
alias ruby? custom_matcher?
|
data/lib/citeproc/utilities.rb
CHANGED
|
@@ -15,6 +15,17 @@ module CiteProc
|
|
|
15
15
|
process(:bibliography, items, options)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
# @param value [String, Boolean, nil] an xsd:boolean value
|
|
19
|
+
# @param default [Boolean] the value if the value is not set
|
|
20
|
+
# @return [Boolean] the boolean value
|
|
21
|
+
def boolean(value, default = false)
|
|
22
|
+
case value.to_s
|
|
23
|
+
when 'true', '1' then true
|
|
24
|
+
when 'false', '0' then false
|
|
25
|
+
else default
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
18
29
|
end
|
|
19
30
|
|
|
20
31
|
end
|
data/lib/citeproc/variable.rb
CHANGED
|
@@ -131,12 +131,15 @@ module CiteProc
|
|
|
131
131
|
# @return [Object] the value wrapped by this variable
|
|
132
132
|
attr_accessor :value
|
|
133
133
|
|
|
134
|
+
# In-place transformations of the value
|
|
134
135
|
def_delegators :@value, :to_s,
|
|
135
|
-
|
|
136
|
+
:gsub!, :sub!, :upcase!, :downcase!, :capitalize!, :strip!
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
# Variables quack sorta like a String
|
|
139
|
+
def_delegators :to_s,
|
|
140
|
+
:to_str, :empty?,
|
|
141
|
+
:=~, :===, :match, :match?, :start_with?, :end_with?, :include?,
|
|
142
|
+
:upcase, :downcase, :capitalize, :sub, :gsub, :split, :strip
|
|
140
143
|
|
|
141
144
|
|
|
142
145
|
# Creates new Variable for the passed-in value
|
|
@@ -226,7 +229,7 @@ module CiteProc
|
|
|
226
229
|
#
|
|
227
230
|
# @return [Boolean] whether or not the variable's value is numeric
|
|
228
231
|
def numeric?
|
|
229
|
-
!!match(/^[\w\.:;]*\d+[\w\.:;]*(\s*[,&-]\s*[\w\.:;]*\d+[\w\.:;]*)*$/i)
|
|
232
|
+
!!to_s.match(/^[\w\.:;]*\d+[\w\.:;]*(\s*[,&-]\s*[\w\.:;]*\d+[\w\.:;]*)*$/i)
|
|
230
233
|
end
|
|
231
234
|
|
|
232
235
|
def date?
|
|
@@ -247,7 +250,7 @@ module CiteProc
|
|
|
247
250
|
|
|
248
251
|
# @return [String] the variable's value stripped of markup
|
|
249
252
|
def strip_markup
|
|
250
|
-
gsub(Variable.markup, '')
|
|
253
|
+
to_s.gsub(Variable.markup, '')
|
|
251
254
|
end
|
|
252
255
|
|
|
253
256
|
# Strips markup off the variable's value.
|
|
@@ -274,6 +277,20 @@ module CiteProc
|
|
|
274
277
|
end
|
|
275
278
|
end
|
|
276
279
|
|
|
280
|
+
# Variables are equal (in the sense of eql?) if they are of
|
|
281
|
+
# the same type and have the same value.
|
|
282
|
+
#
|
|
283
|
+
# @param other [Object] the object used for comparison
|
|
284
|
+
# @return [Boolean]
|
|
285
|
+
def eql?(other)
|
|
286
|
+
other.instance_of?(self.class) && value.eql?(other.value)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# @return [Integer] a hash value based on the type and value
|
|
290
|
+
def hash
|
|
291
|
+
[self.class, value].hash
|
|
292
|
+
end
|
|
293
|
+
|
|
277
294
|
# @!method to_s
|
|
278
295
|
# @return [String] the variable's value as a string
|
|
279
296
|
alias to_citeproc to_s
|
data/lib/citeproc/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: citeproc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sylvester Keil
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: namae
|