citeproc 1.0.0.pre5 → 1.0.0.pre6
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.
- data/citeproc.gemspec +1 -1
- data/lib/citeproc/citation_data.rb +1 -1
- data/lib/citeproc/date.rb +34 -34
- data/lib/citeproc/item.rb +53 -40
- data/lib/citeproc/names.rb +91 -84
- data/lib/citeproc/variable.rb +13 -4
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/names_spec.rb +1 -1
- metadata +40 -15
data/citeproc.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.license = 'AGPL'
|
23
23
|
s.date = Time.now.strftime('%Y-%m-%d')
|
24
24
|
|
25
|
-
s.add_runtime_dependency('multi_json', '~>1.
|
25
|
+
s.add_runtime_dependency('multi_json', '~>1.5')
|
26
26
|
s.add_runtime_dependency('namae', '~>0.3')
|
27
27
|
|
28
28
|
s.add_development_dependency 'cucumber', '~>1.2'
|
@@ -47,7 +47,7 @@ module CiteProc
|
|
47
47
|
# @!attribute suffix
|
48
48
|
# @return [String] a string to print after cites produced for this item
|
49
49
|
|
50
|
-
attr_predicates :id, :locator, :label, :'suppress-author',
|
50
|
+
attr_predicates :id, :locator, :page, :label, :'suppress-author',
|
51
51
|
:'author-only', :prefix, :suffix
|
52
52
|
|
53
53
|
# Attributes added by processor
|
data/lib/citeproc/date.rb
CHANGED
@@ -74,7 +74,7 @@ module CiteProc
|
|
74
74
|
# be used in an external context.
|
75
75
|
class DateParts < Struct.new(:year, :month, :day)
|
76
76
|
include Comparable
|
77
|
-
|
77
|
+
|
78
78
|
def initialize(*arguments)
|
79
79
|
if arguments.length == 1 && arguments[0].is_a?(::Date)
|
80
80
|
d = arguments[0]
|
@@ -83,11 +83,11 @@ module CiteProc
|
|
83
83
|
super(*arguments.map(&:to_i))
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def initialize_copy(other)
|
88
88
|
update(other)
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
# Update the date parts with the passed-in values.
|
92
92
|
# @param parts [Array, #each_pair] an ordered list of date parts (year,
|
93
93
|
# month, day) or a Hash containing the mapping
|
@@ -96,14 +96,14 @@ module CiteProc
|
|
96
96
|
unless parts.respond_to?(:each_pair)
|
97
97
|
parts = Hash[DateParts.members.zip(parts)]
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
parts.each_pair do |part, value|
|
101
101
|
self[part] = value.nil? ? nil : value.to_i
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
self
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# @return [Boolean] whether or not the date parts are unset
|
108
108
|
def empty?
|
109
109
|
to_citeproc.empty?
|
@@ -135,7 +135,7 @@ module CiteProc
|
|
135
135
|
# parts are not a valid date.
|
136
136
|
def strftime(format = '%F')
|
137
137
|
d = to_date
|
138
|
-
|
138
|
+
|
139
139
|
if d.nil?
|
140
140
|
nil
|
141
141
|
else
|
@@ -156,14 +156,14 @@ module CiteProc
|
|
156
156
|
nil
|
157
157
|
end
|
158
158
|
end
|
159
|
-
|
159
|
+
|
160
160
|
# Convert the date parts into a proper Ruby date object; if the date
|
161
161
|
# parts are empty, contain zero or are otherwise invalid, nil will
|
162
162
|
# be returned instead.
|
163
163
|
# @return [::Date,nil] the date parts as a Ruby date object
|
164
164
|
def to_date
|
165
165
|
parts = to_citeproc
|
166
|
-
|
166
|
+
|
167
167
|
if parts.empty? || parts.include?(0)
|
168
168
|
nil
|
169
169
|
else
|
@@ -175,14 +175,14 @@ module CiteProc
|
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
alias to_ruby to_date
|
180
|
-
|
180
|
+
|
181
181
|
# @return [Array<Fixnum>] the list of date parts
|
182
182
|
def to_citeproc
|
183
183
|
take_while { |p| !p.nil? }
|
184
184
|
end
|
185
|
-
|
185
|
+
|
186
186
|
# @return [String] the date parts as a string
|
187
187
|
def to_s
|
188
188
|
to_citeproc.inspect
|
@@ -193,19 +193,19 @@ module CiteProc
|
|
193
193
|
"#<DateParts #{to_s}>"
|
194
194
|
end
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
|
198
198
|
include Attributes
|
199
199
|
|
200
200
|
alias attributes value
|
201
201
|
protected :value, :attributes
|
202
|
-
|
202
|
+
|
203
203
|
undef_method :value=
|
204
|
-
|
204
|
+
|
205
205
|
|
206
206
|
# List of date parsers (must respond to #parse)
|
207
207
|
@parsers = []
|
208
|
-
|
208
|
+
|
209
209
|
[%w{ edtf EDTF }, %w{ chronic Chronic }].each do |date_parser, module_id|
|
210
210
|
begin
|
211
211
|
require date_parser
|
@@ -216,8 +216,8 @@ module CiteProc
|
|
216
216
|
end
|
217
217
|
|
218
218
|
@parsers << ::Date
|
219
|
-
|
220
|
-
|
219
|
+
|
220
|
+
|
221
221
|
class << self
|
222
222
|
|
223
223
|
# @!attribute [r] parsers
|
@@ -246,19 +246,19 @@ module CiteProc
|
|
246
246
|
rescue ParseError
|
247
247
|
nil
|
248
248
|
end
|
249
|
-
|
249
|
+
|
250
250
|
# Like #parse but raises a ParseError if the input failed to be parsed.
|
251
251
|
#
|
252
252
|
# @param date_string [String] the date to be parsed
|
253
253
|
# @return [CiteProc::Date] the parsed date
|
254
254
|
#
|
255
|
-
# @raise [ParseError] when the string cannot be parsed
|
255
|
+
# @raise [ParseError] when the string cannot be parsed
|
256
256
|
def parse!(date_string)
|
257
257
|
@parsers.each do |p|
|
258
258
|
date = p.parse(date_string) rescue nil
|
259
259
|
return new(date) unless date.nil?
|
260
260
|
end
|
261
|
-
|
261
|
+
|
262
262
|
# Subtle: if we get here it means all parsers failed to create a date
|
263
263
|
raise ParseError, "failed to parse #{date_string.inspect}"
|
264
264
|
end
|
@@ -269,7 +269,7 @@ module CiteProc
|
|
269
269
|
end
|
270
270
|
|
271
271
|
alias now today
|
272
|
-
|
272
|
+
|
273
273
|
end
|
274
274
|
|
275
275
|
|
@@ -293,7 +293,7 @@ module CiteProc
|
|
293
293
|
super
|
294
294
|
convert_parts!
|
295
295
|
end
|
296
|
-
|
296
|
+
|
297
297
|
# Replaces the date's value. Typically called by the constructor, this
|
298
298
|
# method intelligently converts various input values.
|
299
299
|
def replace(value)
|
@@ -317,7 +317,7 @@ module CiteProc
|
|
317
317
|
@value = attributes.deep_copy
|
318
318
|
end
|
319
319
|
convert_parts!
|
320
|
-
|
320
|
+
|
321
321
|
when value.is_a?(Array)
|
322
322
|
@value = { :'date-parts' => value[0].is_a?(Array) ? value : [value] }
|
323
323
|
convert_parts!
|
@@ -336,7 +336,7 @@ module CiteProc
|
|
336
336
|
|
337
337
|
self
|
338
338
|
end
|
339
|
-
|
339
|
+
|
340
340
|
# @return [Array<DateParts>]
|
341
341
|
def date_parts
|
342
342
|
@value[:'date-parts'] ||= []
|
@@ -361,24 +361,24 @@ module CiteProc
|
|
361
361
|
# @return [Fixnum] the day (of the start date for ranges)
|
362
362
|
[:year, :month, :day].each do |reader|
|
363
363
|
writer = "#{reader}="
|
364
|
-
|
364
|
+
|
365
365
|
define_method(reader) do
|
366
366
|
d = parts[0] and d.send(reader)
|
367
367
|
end
|
368
|
-
|
368
|
+
|
369
369
|
define_method(writer) do |v|
|
370
370
|
parts[0] ||= DateParts.new
|
371
371
|
parts[0].send(writer, v.to_i)
|
372
372
|
end
|
373
373
|
end
|
374
|
-
|
374
|
+
|
375
375
|
# @return [Date] a copy of the date with an inverted year
|
376
376
|
def -@
|
377
377
|
d = dup
|
378
378
|
d.year = -1 * year
|
379
379
|
d
|
380
380
|
end
|
381
|
-
|
381
|
+
|
382
382
|
# @return [::Date,nil] the date (start date if this instance is a range); or nil
|
383
383
|
def start_date
|
384
384
|
d = parts[0] and d.to_date
|
@@ -412,8 +412,8 @@ module CiteProc
|
|
412
412
|
parts[1] && !parts[1].empty?
|
413
413
|
end
|
414
414
|
|
415
|
-
# Returns true if this date is a range
|
416
415
|
alias range? has_end_date?
|
416
|
+
alias plural? has_end_date?
|
417
417
|
|
418
418
|
# @return [Boolean] whether or not this date is an open range
|
419
419
|
def open_range?
|
@@ -460,7 +460,7 @@ module CiteProc
|
|
460
460
|
def bc?
|
461
461
|
date = parts[0] and date.bc?
|
462
462
|
end
|
463
|
-
|
463
|
+
|
464
464
|
# A date is said to be AD when it is in the first millennium, i.e.,
|
465
465
|
# between 1 and 1000 AD
|
466
466
|
# @return [Boolean, nil] whether or not the date is AD; nil if there is
|
@@ -472,17 +472,17 @@ module CiteProc
|
|
472
472
|
# @return [Hash] a hash representation of the date.
|
473
473
|
def to_citeproc
|
474
474
|
cp = @value.stringify_keys
|
475
|
-
|
475
|
+
|
476
476
|
# Convert (or suppress empty) date-parts
|
477
477
|
if parts.all?(&:empty?)
|
478
478
|
cp.delete('date-parts')
|
479
479
|
else
|
480
480
|
cp['date-parts'] = cp['date-parts'].map(&:to_citeproc)
|
481
481
|
end
|
482
|
-
|
482
|
+
|
483
483
|
cp
|
484
484
|
end
|
485
|
-
|
485
|
+
|
486
486
|
# @return [String] the date as a string
|
487
487
|
def to_s
|
488
488
|
case
|
data/lib/citeproc/item.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module CiteProc
|
2
|
-
|
2
|
+
|
3
3
|
# Items are similar to a Ruby Hash but pose a number of constraints on their
|
4
4
|
# contents: keys are always (implicitly converted to) symbols and values
|
5
5
|
# are strictly {Variable Variables}. When Items are constructed
|
@@ -24,7 +24,7 @@ module CiteProc
|
|
24
24
|
# Items can be converted to the CiteProc JSON format via {#to_citeproc}
|
25
25
|
# and {#to_json}.
|
26
26
|
class Item
|
27
|
-
|
27
|
+
|
28
28
|
@types = [
|
29
29
|
:article, :'article-journal', :'article-magazine', :'article-newspaper',
|
30
30
|
:bill, :book, :broadcast, :chapter, :entry, :'entry-dictionary',
|
@@ -33,7 +33,7 @@ module CiteProc
|
|
33
33
|
:pamphlet, :'paper-conference', :patent, :personal_communication, :post,
|
34
34
|
:'post-weblog', :report, :review, :'review-book', :song, :speech,
|
35
35
|
:thesis, :treaty, :webpage].freeze
|
36
|
-
|
36
|
+
|
37
37
|
@bibtex_types = Hash.new { |h,k| :misc }.merge(Hash[*%w{
|
38
38
|
pamphlet booklet
|
39
39
|
paper-conference conference
|
@@ -49,13 +49,13 @@ module CiteProc
|
|
49
49
|
article-journal article
|
50
50
|
article-magazine article
|
51
51
|
}.map(&:intern)]).freeze
|
52
|
-
|
52
|
+
|
53
53
|
class << self
|
54
54
|
attr_reader :types, :bibtex_types
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
extend Forwardable
|
58
|
-
|
58
|
+
|
59
59
|
include Attributes
|
60
60
|
include Enumerable
|
61
61
|
include Comparable
|
@@ -66,38 +66,51 @@ module CiteProc
|
|
66
66
|
*Variable.fields[:all]
|
67
67
|
|
68
68
|
def_delegators :attributes, :values_at, :keys, :values
|
69
|
-
|
69
|
+
|
70
70
|
alias fields keys
|
71
|
-
|
72
|
-
# Hide attributes reader
|
71
|
+
|
72
|
+
# Hide attributes reader:
|
73
|
+
# All access should go through (read|write)_attribute
|
73
74
|
protected :attributes
|
74
|
-
|
75
|
-
|
75
|
+
|
76
|
+
|
76
77
|
def initialize(attributes = nil)
|
77
78
|
merge(attributes)
|
78
79
|
yield self if block_given?
|
79
80
|
end
|
80
|
-
|
81
|
+
|
81
82
|
def initialize_copy(other)
|
82
83
|
@attributes = other.attributes.deep_copy
|
83
84
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
85
|
+
|
86
|
+
|
87
|
+
def observable_read_attribute(key)
|
88
|
+
value = original_read_attribute(key)
|
89
|
+
ensure
|
90
|
+
changed
|
91
|
+
notify_observers :read, key, value
|
92
|
+
end
|
93
|
+
|
94
|
+
alias original_read_attribute read_attribute
|
95
|
+
alias read_attribute observable_read_attribute
|
96
|
+
|
97
|
+
|
98
|
+
# @param name [Symbol] the name of the variable
|
99
|
+
#
|
100
|
+
# @param options [Hash]
|
101
|
+
# @option options [:short] :form (nil) when given, the variable's
|
102
|
+
# short form will be returned if available.
|
103
|
+
#
|
104
|
+
# @return [Variable, nil] the matching variable
|
105
|
+
def variable(name, options = {})
|
106
|
+
if options.key?(:form) && options[:form].to_sym == :short
|
107
|
+
var = read_attribute "#{name}-short"
|
108
|
+
return var unless var.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
read_attribute name
|
112
|
+
end
|
113
|
+
|
101
114
|
# Calls a block once for each field in the item, passing the field's
|
102
115
|
# name-value pair as parameters.
|
103
116
|
#
|
@@ -120,7 +133,7 @@ module CiteProc
|
|
120
133
|
to_enum
|
121
134
|
end
|
122
135
|
end
|
123
|
-
|
136
|
+
|
124
137
|
alias each_pair each
|
125
138
|
|
126
139
|
# Calls a block once for each field in the item, passing the field's
|
@@ -144,7 +157,7 @@ module CiteProc
|
|
144
157
|
enum_for :each_value
|
145
158
|
end
|
146
159
|
end
|
147
|
-
|
160
|
+
|
148
161
|
def <=>(other)
|
149
162
|
return nil unless other.is_a?(Attributes)
|
150
163
|
eql?(other) ? 0 : length <=> other.length
|
@@ -154,26 +167,26 @@ module CiteProc
|
|
154
167
|
# installed; otherwise returns a BibTeX string.
|
155
168
|
def to_bibtex
|
156
169
|
# hash = to_hash
|
157
|
-
#
|
170
|
+
#
|
158
171
|
# hash[:type] = Item.bibtex_types[hash[:type]]
|
159
|
-
#
|
172
|
+
#
|
160
173
|
# if hash.has_key?(:issued)
|
161
174
|
# date = hash.delete(:issued)
|
162
175
|
# hash[:year] = date.year
|
163
176
|
# hash[:month] = date.month
|
164
177
|
# end
|
165
|
-
#
|
178
|
+
#
|
166
179
|
# Variable.fields[:date].each do |field|
|
167
180
|
# hash[field] = hash[field].to_s if hash.has_key?(field)
|
168
181
|
# end
|
169
|
-
#
|
182
|
+
#
|
170
183
|
# Variable.fields[:names].each do |field|
|
171
184
|
# hash[field] = hash[field].to_bibtex
|
172
185
|
# end
|
173
|
-
|
186
|
+
|
174
187
|
raise 'not implemented yet'
|
175
188
|
end
|
176
|
-
|
189
|
+
|
177
190
|
# @return [Symbol,nil] the item's id
|
178
191
|
def to_sym
|
179
192
|
if id?
|
@@ -182,13 +195,13 @@ module CiteProc
|
|
182
195
|
nil
|
183
196
|
end
|
184
197
|
end
|
185
|
-
|
198
|
+
|
186
199
|
# @return [String] a string containing a human-readable
|
187
200
|
# representation of the item
|
188
201
|
def inspect
|
189
202
|
"#<CiteProc::Item id=#{id.to_s.inspect} attributes={#{attributes.length}}>"
|
190
203
|
end
|
191
|
-
|
204
|
+
|
192
205
|
private
|
193
206
|
|
194
207
|
# @private
|
@@ -196,5 +209,5 @@ module CiteProc
|
|
196
209
|
Variable.create!(value, key)
|
197
210
|
end
|
198
211
|
end
|
199
|
-
|
212
|
+
|
200
213
|
end
|
data/lib/citeproc/names.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
module CiteProc
|
3
|
-
|
3
|
+
|
4
4
|
# Names consist of several dependent parts of strings. Simple personal names
|
5
5
|
# are composed of family and given elements, containing respectively the
|
6
6
|
# family and given name of the individual.
|
@@ -32,13 +32,13 @@ module CiteProc
|
|
32
32
|
#
|
33
33
|
# Name.new(:family => 'Murakami', :given => 'Haruki').to_s
|
34
34
|
# #-> "Haruki Murakami"
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# Name.new(:family => 'Murakami', :given => 'Haruki').static_order!.to_s
|
37
37
|
# #-> "Murakami Haruki"
|
38
38
|
class Name
|
39
|
-
|
39
|
+
|
40
40
|
extend Forwardable
|
41
|
-
|
41
|
+
|
42
42
|
include Attributes
|
43
43
|
include Comparable
|
44
44
|
|
@@ -59,24 +59,24 @@ module CiteProc
|
|
59
59
|
:'sort-separator' => ', ',
|
60
60
|
:'initialize-with' => nil
|
61
61
|
}.freeze
|
62
|
-
|
62
|
+
|
63
63
|
@parts = [:family, :given,:literal, :suffix, :'dropping-particle',
|
64
64
|
:'non-dropping-particle'].freeze
|
65
|
-
|
65
|
+
|
66
66
|
class << self
|
67
67
|
attr_reader :defaults, :parts, :romanesque
|
68
68
|
end
|
69
69
|
|
70
|
-
|
70
|
+
|
71
71
|
|
72
72
|
# Method generators
|
73
|
-
|
73
|
+
|
74
74
|
# @!attribute [r] options
|
75
75
|
# @return the name's formatting options
|
76
76
|
attr_reader :options
|
77
|
-
|
77
|
+
|
78
78
|
attr_predicates :'comma-suffix', :'static-ordering', :multi, *@parts
|
79
|
-
|
79
|
+
|
80
80
|
# Aliases
|
81
81
|
[[:particle, :'non_dropping_particle']].each do |a, m|
|
82
82
|
alias_method(a, m) if method_defined?(m)
|
@@ -90,11 +90,11 @@ module CiteProc
|
|
90
90
|
pa, pm = "has_#{a}?", "has_#{m}?"
|
91
91
|
alias_method(pa, pm) if method_defined?(pm)
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# Names quack sorta like a String
|
95
95
|
def_delegators :to_s, :=~, :===,
|
96
96
|
*String.instance_methods(false).reject { |m| m =~ /^\W|!$|to_s|replace|first|last/ }
|
97
|
-
|
97
|
+
|
98
98
|
# Delegate bang! methods to each field's value
|
99
99
|
String.instance_methods(false).each do |m|
|
100
100
|
if m.to_s.end_with?('!')
|
@@ -107,30 +107,30 @@ module CiteProc
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
111
|
-
|
110
|
+
|
111
|
+
|
112
112
|
# Instance methods
|
113
|
-
|
113
|
+
|
114
114
|
def initialize(attributes = {}, options = {})
|
115
115
|
@options = Name.defaults.merge(options)
|
116
116
|
@sort_prefix = (/^(the|an?|der|die|das|eine?|l[ae])\s+|^l\W/i).freeze
|
117
|
-
|
117
|
+
|
118
118
|
merge(attributes)
|
119
|
-
|
119
|
+
|
120
120
|
yield self if block_given?
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
def initialize_copy(other)
|
124
124
|
@attributes = other.attributes.deep_copy
|
125
125
|
@options = other.options.dup
|
126
126
|
end
|
127
|
-
|
128
|
-
|
127
|
+
|
128
|
+
|
129
129
|
# @return [Boolean] whether or not the Name looks like it belongs to a person
|
130
130
|
def personal?
|
131
131
|
!empty? && !literal?
|
132
132
|
end
|
133
|
-
|
133
|
+
|
134
134
|
|
135
135
|
# A name is `romanesque' if it contains only romanesque characters. This
|
136
136
|
# should be the case for the majority of names written in latin- or
|
@@ -141,9 +141,9 @@ module CiteProc
|
|
141
141
|
def romanesque?
|
142
142
|
!!([given, family].join.gsub(Variable.markup, '') =~ Name.romanesque)
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
alias byzantine? romanesque?
|
146
|
-
|
146
|
+
|
147
147
|
# @return [Boolean] whether or not the name should be printed in static order
|
148
148
|
def static_order?
|
149
149
|
static_ordering? || !romanesque?
|
@@ -166,32 +166,32 @@ module CiteProc
|
|
166
166
|
def sort_order?
|
167
167
|
!!(options[:'name-as-sort-order'].to_s =~ /^(y(es)?|always|t(rue)?)$/i)
|
168
168
|
end
|
169
|
-
|
169
|
+
|
170
170
|
def display_order?
|
171
171
|
!sort_order?
|
172
172
|
end
|
173
|
-
|
173
|
+
|
174
174
|
# Sets the name to use sort-order. The reverse of {#display_order!}.
|
175
175
|
# @return [self]
|
176
176
|
def sort_order!
|
177
177
|
options[:'name-as-sort-order'] = true
|
178
178
|
self
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
# Sets the name to use display-order. The reverse of {#sort_order!}.
|
182
182
|
# @return [self]
|
183
183
|
def display_order!
|
184
184
|
options[:'name-as-sort-order'] = false
|
185
185
|
self
|
186
186
|
end
|
187
|
-
|
187
|
+
|
188
188
|
# @return [String] the current sort separator
|
189
189
|
def sort_separator
|
190
190
|
options[:'sort-separator']
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
alias comma sort_separator
|
194
|
-
|
194
|
+
|
195
195
|
# @return [Boolean] whether or not the short form will be used for printing
|
196
196
|
def short_form?
|
197
197
|
options[:form].to_s =~ /short/i
|
@@ -215,19 +215,19 @@ module CiteProc
|
|
215
215
|
options[:form] = :long
|
216
216
|
self
|
217
217
|
end
|
218
|
-
|
218
|
+
|
219
219
|
# @return [Boolean] whether or not initials will be used for printing
|
220
220
|
def initials?
|
221
221
|
!!options[:'initialize-with'] && personal? && romanesque?
|
222
222
|
end
|
223
|
-
|
223
|
+
|
224
224
|
def demote_non_dropping_particle?
|
225
225
|
always_demote_non_dropping_particle? ||
|
226
226
|
!!(sort_order? && options[:'demote-non-dropping-particle'] =~ /^sort(-only)?$/i)
|
227
227
|
end
|
228
228
|
|
229
229
|
alias demote_particle? demote_non_dropping_particle?
|
230
|
-
|
230
|
+
|
231
231
|
def never_demote_non_dropping_particle?
|
232
232
|
!!(options[:'demote-non-dropping-particle'] =~ /^never$/i)
|
233
233
|
end
|
@@ -265,7 +265,7 @@ module CiteProc
|
|
265
265
|
return nil unless other.respond_to?(:sort_order_downcase)
|
266
266
|
sort_order_downcase <=> other.sort_order_downcase
|
267
267
|
end
|
268
|
-
|
268
|
+
|
269
269
|
# @return [String] the name formatted according to the current options
|
270
270
|
def to_s
|
271
271
|
case
|
@@ -286,12 +286,12 @@ module CiteProc
|
|
286
286
|
else
|
287
287
|
[family, [given, dropping_particle, particle].compact_join(' '),
|
288
288
|
suffix].compact_join(comma)
|
289
|
-
end
|
289
|
+
end
|
290
290
|
else
|
291
291
|
[particle, family].compact_join(' ')
|
292
292
|
end
|
293
293
|
end
|
294
|
-
|
294
|
+
|
295
295
|
# @return [Array<String>] an ordered array of formatted name parts to be used for sorting
|
296
296
|
def sort_order
|
297
297
|
case
|
@@ -303,41 +303,41 @@ module CiteProc
|
|
303
303
|
[family, [particle, dropping_particle].compact_join(' '), given, suffix].map(&:to_s)
|
304
304
|
end
|
305
305
|
end
|
306
|
-
|
306
|
+
|
307
307
|
# @return [String] the name as a string stripped off all markup
|
308
308
|
def strip_markup
|
309
309
|
gsub(Variable.markup, '')
|
310
310
|
end
|
311
|
-
|
311
|
+
|
312
312
|
# @return [self] the name with all parts stripped off markup
|
313
313
|
def strip_markup!
|
314
314
|
gsub!(Variable.markup, '')
|
315
315
|
end
|
316
|
-
|
316
|
+
|
317
317
|
# @return [Array<String>] the sort order array stripped off markup and downcased
|
318
318
|
def sort_order_downcase
|
319
319
|
sort_order.map { |s| s.downcase.gsub(Variable.markup, '') }
|
320
320
|
end
|
321
|
-
|
321
|
+
|
322
322
|
# @return [String] a human-readable representation of the name object
|
323
323
|
def inspect
|
324
324
|
"#<CiteProc::Name #{to_s.inspect}>"
|
325
325
|
end
|
326
|
-
|
326
|
+
|
327
327
|
private
|
328
|
-
|
328
|
+
|
329
329
|
attr_reader :sort_prefix
|
330
|
-
|
330
|
+
|
331
331
|
end
|
332
|
-
|
333
|
-
|
334
|
-
|
332
|
+
|
333
|
+
|
334
|
+
|
335
335
|
|
336
336
|
# Represents a {Variable} containing an ordered list of {Name}
|
337
337
|
# objects. The names can be formatted using CSL formatting options (see
|
338
338
|
# {Names.defaults} for details).
|
339
339
|
class Names < Variable
|
340
|
-
|
340
|
+
|
341
341
|
@defaults = {
|
342
342
|
:and => ' & ',
|
343
343
|
:delimiter => ', ',
|
@@ -348,7 +348,7 @@ module CiteProc
|
|
348
348
|
:'et-al-subsequent-min' => 5,
|
349
349
|
:'et-al-subsequent-use-first' => 3
|
350
350
|
}.freeze
|
351
|
-
|
351
|
+
|
352
352
|
class << self
|
353
353
|
|
354
354
|
# @!attribute [r] defaults
|
@@ -388,9 +388,9 @@ module CiteProc
|
|
388
388
|
# # referencing earlier cited items)
|
389
389
|
# }
|
390
390
|
#
|
391
|
-
# @return [Hash] the Names' default formatting options
|
391
|
+
# @return [Hash] the Names' default formatting options
|
392
392
|
attr_reader :defaults
|
393
|
-
|
393
|
+
|
394
394
|
# Parses the passed-in string and returns a Names object. Behaves like
|
395
395
|
# parse but returns nil for bad input without raising an error.
|
396
396
|
#
|
@@ -403,7 +403,7 @@ module CiteProc
|
|
403
403
|
rescue ParseError
|
404
404
|
nil
|
405
405
|
end
|
406
|
-
|
406
|
+
|
407
407
|
# Parses the passed-in string and returns a Names object.
|
408
408
|
#
|
409
409
|
# @param names [String] the name or names to be parsed
|
@@ -417,19 +417,19 @@ module CiteProc
|
|
417
417
|
end
|
418
418
|
|
419
419
|
end
|
420
|
-
|
420
|
+
|
421
421
|
include Enumerable
|
422
422
|
|
423
423
|
# @!attribute [r] options
|
424
424
|
# @return [Hash] the current formatting options
|
425
425
|
|
426
426
|
attr_reader :options
|
427
|
-
|
427
|
+
|
428
428
|
alias names value
|
429
|
-
|
429
|
+
|
430
430
|
# Don't expose value/names writer
|
431
431
|
undef_method :value=
|
432
|
-
|
432
|
+
|
433
433
|
# Delegate bang! methods to each name
|
434
434
|
Name.instance_methods(false).each do |m|
|
435
435
|
if m.to_s.end_with?('!')
|
@@ -441,11 +441,11 @@ module CiteProc
|
|
441
441
|
end
|
442
442
|
end
|
443
443
|
end
|
444
|
-
|
444
|
+
|
445
445
|
# Names quack sorta like an Array
|
446
446
|
def_delegators :names, :length, :empty?, :[], :join
|
447
447
|
|
448
|
-
|
448
|
+
|
449
449
|
# Some delegators should return self
|
450
450
|
|
451
451
|
# @!method push(name)
|
@@ -455,26 +455,26 @@ module CiteProc
|
|
455
455
|
# @!method unshift(name)
|
456
456
|
# Inserts the given name at the beginning of the list of names.
|
457
457
|
# @param name [Name] a name
|
458
|
-
# @return [self]
|
458
|
+
# @return [self]
|
459
459
|
[:<<, :push, :unshift].each do |m|
|
460
460
|
define_method(m) do |*arguments, &block|
|
461
461
|
names.send(m, *arguments, &block)
|
462
462
|
self
|
463
463
|
end
|
464
464
|
end
|
465
|
-
|
465
|
+
|
466
466
|
def initialize(*arguments)
|
467
467
|
@options = Names.defaults.dup
|
468
468
|
super(arguments.flatten(1))
|
469
469
|
end
|
470
|
-
|
470
|
+
|
471
471
|
def initialize_copy(other)
|
472
472
|
@options, @value = other.options.dup, other.value.map(&:dup)
|
473
473
|
end
|
474
|
-
|
474
|
+
|
475
475
|
def replace(values)
|
476
476
|
@value = []
|
477
|
-
|
477
|
+
|
478
478
|
[*values].each do |value|
|
479
479
|
case
|
480
480
|
when value.is_a?(Name)
|
@@ -488,34 +488,34 @@ module CiteProc
|
|
488
488
|
raise TypeError, $!.message
|
489
489
|
end
|
490
490
|
else
|
491
|
-
raise TypeError, "failed to create names from #{value.inspect}"
|
491
|
+
raise TypeError, "failed to create names from #{value.inspect}"
|
492
492
|
end
|
493
493
|
end
|
494
|
-
|
494
|
+
|
495
495
|
self
|
496
496
|
end
|
497
|
-
|
497
|
+
|
498
498
|
# @return [Fixnum] the maximum number of names that should be printed
|
499
499
|
def max_names
|
500
500
|
[length, options[:'et-al-use-first'].to_i.abs].min
|
501
501
|
end
|
502
|
-
|
502
|
+
|
503
503
|
# @return [Boolean] whether or not the Names should be truncate
|
504
504
|
def truncate?
|
505
505
|
length >= options[:'et-al-min'].to_i.abs
|
506
506
|
end
|
507
|
-
|
507
|
+
|
508
508
|
# @return [Boolean] whether ot not the Names, if printed on subsequent
|
509
509
|
# cites, should be truncated
|
510
510
|
def truncate_subsequent?
|
511
511
|
length >= options[:'et-al-subsequent-min'].to_i
|
512
512
|
end
|
513
|
-
|
513
|
+
|
514
514
|
# @return [String] the delimiter between names
|
515
515
|
def delimiter
|
516
516
|
options[:delimiter]
|
517
517
|
end
|
518
|
-
|
518
|
+
|
519
519
|
# @return [String] the delimiter between the penultimate and last name
|
520
520
|
# @see #connector
|
521
521
|
# @see #delimiter_precedes_last?
|
@@ -526,26 +526,26 @@ module CiteProc
|
|
526
526
|
connector
|
527
527
|
end
|
528
528
|
end
|
529
|
-
|
529
|
+
|
530
530
|
# @return [String] the delimiter between the last name printed name and
|
531
531
|
# the 'and others' term
|
532
532
|
def truncated_delimiter
|
533
533
|
max_names > 1 ? delimiter : ' '
|
534
534
|
end
|
535
|
-
|
535
|
+
|
536
536
|
# @return [Boolean] whether or not the delimiter will be inserted between
|
537
537
|
# the penultimate and the last name
|
538
538
|
def delimiter_precedes_last?
|
539
539
|
case
|
540
540
|
when delimiter_never_precedes_last?
|
541
|
-
false
|
541
|
+
false
|
542
542
|
when delimiter_always_precedes_last?
|
543
543
|
true
|
544
544
|
else
|
545
545
|
length > 2
|
546
546
|
end
|
547
547
|
end
|
548
|
-
|
548
|
+
|
549
549
|
# @return [Boolean] whether or not the should always be inserted between
|
550
550
|
# the penultimate and the last name
|
551
551
|
def delimiter_always_precedes_last?
|
@@ -561,7 +561,7 @@ module CiteProc
|
|
561
561
|
|
562
562
|
alias delimiter_precedes_last! delimiter_always_precedes_last!
|
563
563
|
|
564
|
-
|
564
|
+
|
565
565
|
# @return [Boolean] whether or not the should never be inserted between
|
566
566
|
# the penultimate and the last name
|
567
567
|
def delimiter_never_precedes_last?
|
@@ -587,22 +587,27 @@ module CiteProc
|
|
587
587
|
options[:'delimiter-precedes-last'] = :contextual
|
588
588
|
self
|
589
589
|
end
|
590
|
-
|
590
|
+
|
591
591
|
# @return [String] the connector between the penultimate and the last name
|
592
592
|
def connector
|
593
593
|
options[:and]
|
594
594
|
end
|
595
|
-
|
595
|
+
|
596
596
|
# @return [false] Names are non-numeric Variables
|
597
597
|
def numeric?
|
598
598
|
false
|
599
599
|
end
|
600
600
|
|
601
|
+
# @return [Boolean] whether or not the variable holds more than one Name
|
602
|
+
def plural?
|
603
|
+
length > 1
|
604
|
+
end
|
605
|
+
|
601
606
|
# Calls a block once for each name. If no block is given, an enumerator
|
602
607
|
# is returned instead.
|
603
608
|
#
|
604
609
|
# @yieldparam name [Name] a name in the list
|
605
|
-
# @return [self,Enumerator] self or an enumerator if no block is given
|
610
|
+
# @return [self,Enumerator] self or an enumerator if no block is given
|
606
611
|
def each
|
607
612
|
if block_given?
|
608
613
|
names.each(&Proc.new)
|
@@ -611,7 +616,7 @@ module CiteProc
|
|
611
616
|
to_enum
|
612
617
|
end
|
613
618
|
end
|
614
|
-
|
619
|
+
|
615
620
|
# Compares two lists of Names.
|
616
621
|
# @param other [(Name)] a list of names
|
617
622
|
# @return [Fixnum,nil] -1, 0, or 1 depending on the result of the
|
@@ -620,13 +625,15 @@ module CiteProc
|
|
620
625
|
return nil unless other.respond_to?(:to_a)
|
621
626
|
to_a <=> other.to_a
|
622
627
|
end
|
623
|
-
|
628
|
+
|
629
|
+
alias to_i length
|
630
|
+
|
624
631
|
# Converts the list of names into a formatted string depending on the
|
625
632
|
# current formatting options.
|
626
633
|
# @return [String] the formatted list of names
|
627
634
|
def to_s
|
628
635
|
case
|
629
|
-
when truncate?
|
636
|
+
when truncate?
|
630
637
|
[names[0...max_names].join(delimiter), options[:'et-al']].join(truncated_delimiter)
|
631
638
|
when length < 2
|
632
639
|
names.join(last_delimiter)
|
@@ -634,22 +641,22 @@ module CiteProc
|
|
634
641
|
[names[0...-1].join(delimiter), names[-1]].join(last_delimiter)
|
635
642
|
end
|
636
643
|
end
|
637
|
-
|
644
|
+
|
638
645
|
# @return [String] the names in a BibTeX-compatible format
|
639
646
|
def to_bibtex
|
640
647
|
map { |n| n.dup.sort_order! }.join(' and ')
|
641
648
|
end
|
642
|
-
|
649
|
+
|
643
650
|
# @return [Array<Hash>] the list of names converted to hash objects
|
644
651
|
def to_citeproc
|
645
652
|
map(&:to_citeproc)
|
646
653
|
end
|
647
|
-
|
654
|
+
|
648
655
|
# @return [String] a human-readable representation of the Names object
|
649
656
|
def inspect
|
650
657
|
"#<CiteProc::Names #{to_s.inspect}>"
|
651
658
|
end
|
652
|
-
|
659
|
+
|
653
660
|
end
|
654
|
-
|
661
|
+
|
655
662
|
end
|
data/lib/citeproc/variable.rb
CHANGED
@@ -34,8 +34,8 @@ module CiteProc
|
|
34
34
|
first-reference-note-number genre ISBN ISSN jurisdiction keyword
|
35
35
|
locator medium note original-publisher original-publisher-place
|
36
36
|
original-title page page-first PMID PMCID publisher publisher-place
|
37
|
-
references section source status
|
38
|
-
year-suffix
|
37
|
+
references reviewed-author reviewed-title scale section source status
|
38
|
+
title title-short URL version year-suffix
|
39
39
|
}
|
40
40
|
})
|
41
41
|
|
@@ -167,6 +167,15 @@ module CiteProc
|
|
167
167
|
@type ||= self.class.name.split(/::/)[-1].downcase.to_sym
|
168
168
|
end
|
169
169
|
|
170
|
+
# @return [Boolean] whether or not the variable holds a plural value
|
171
|
+
def plural?
|
172
|
+
if numeric?
|
173
|
+
!!match(/\S\s*[,&-]\s*\S|\df/)
|
174
|
+
else
|
175
|
+
false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
170
179
|
# Tests whether the variable contains numeric content. Content is
|
171
180
|
# considered numeric if it solely consists of numbers. Numbers may have
|
172
181
|
# prefixes and suffixes ("D2", "2b", "L2d"), and may be separated by a
|
@@ -176,9 +185,9 @@ module CiteProc
|
|
176
185
|
#
|
177
186
|
# @return [Boolean] whether or not the variable's value is numeric
|
178
187
|
def numeric?
|
179
|
-
!!match(
|
188
|
+
!!match(/^[\w\.:;]*\d+[\w\.:;]*(\s*[,&-]\s*[\w\.:;]*\d+[\w\.:;]*)*$/i)
|
180
189
|
end
|
181
|
-
|
190
|
+
|
182
191
|
# @return [Fixnum] the first (!) numeric data contained in the variable's
|
183
192
|
# value; zero if no numeric data is present
|
184
193
|
def to_i
|
data/lib/citeproc/version.rb
CHANGED
data/spec/citeproc/names_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: citeproc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre6
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: '1.5'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.5'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: namae
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ~>
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0.3'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.3'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: cucumber
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '1.2'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.2'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rspec
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ~>
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '2.7'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.7'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: rake
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ~>
|
@@ -65,7 +85,12 @@ dependencies:
|
|
65
85
|
version: '0.9'
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.9'
|
69
94
|
description: ! "\n A cite processor interface for Citation Style Language (CSL)
|
70
95
|
styles.\n "
|
71
96
|
email:
|
@@ -136,7 +161,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
161
|
version: '0'
|
137
162
|
segments:
|
138
163
|
- 0
|
139
|
-
hash:
|
164
|
+
hash: 91495025789271723
|
140
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
166
|
none: false
|
142
167
|
requirements:
|
@@ -145,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
170
|
version: 1.3.1
|
146
171
|
requirements: []
|
147
172
|
rubyforge_project:
|
148
|
-
rubygems_version: 1.8.
|
173
|
+
rubygems_version: 1.8.24
|
149
174
|
signing_key:
|
150
175
|
specification_version: 3
|
151
176
|
summary: A cite processor interface.
|