citeproc 1.0.0.pre5 → 1.0.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|