citeproc 0.0.8 → 0.0.9
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/.document +5 -0
- data/.gitignore +5 -0
- data/.travis.yml +13 -0
- data/.yardopts +2 -0
- data/AGPL +662 -0
- data/{LICENSE → BSDL} +2 -1
- data/Gemfile +13 -2
- data/README.md +32 -1
- data/Rakefile +39 -0
- data/citeproc.gemspec +18 -11
- data/lib/citeproc.rb +13 -11
- data/lib/citeproc/abbreviate.rb +1 -4
- data/lib/citeproc/assets.rb +11 -4
- data/lib/citeproc/attributes.rb +102 -95
- data/lib/citeproc/bibliography.rb +66 -42
- data/lib/citeproc/citation_data.rb +57 -46
- data/lib/citeproc/compatibility.rb +161 -4
- data/lib/citeproc/date.rb +517 -225
- data/lib/citeproc/engine.rb +0 -2
- data/lib/citeproc/errors.rb +4 -4
- data/lib/citeproc/extensions.rb +6 -5
- data/lib/citeproc/item.rb +85 -22
- data/lib/citeproc/names.rb +642 -543
- data/lib/citeproc/variable.rb +149 -70
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/assets_spec.rb +10 -4
- data/spec/citeproc/date_spec.rb +274 -8
- data/spec/citeproc/item_spec.rb +23 -4
- data/spec/citeproc/names_spec.rb +601 -486
- data/spec/citeproc/variable_spec.rb +4 -12
- data/spec/spec_helper.rb +13 -0
- metadata +64 -31
data/spec/citeproc/item_spec.rb
CHANGED
@@ -3,11 +3,10 @@ require 'spec_helper'
|
|
3
3
|
module CiteProc
|
4
4
|
describe Item do
|
5
5
|
|
6
|
-
it { should_not be nil }
|
7
|
-
it { should be_empty }
|
8
6
|
|
9
7
|
describe '.new' do
|
10
|
-
|
8
|
+
it { should_not be nil }
|
9
|
+
|
11
10
|
it 'creates number variables for number fields' do
|
12
11
|
Item.new(:edition => 23).edition.should be_a(Number)
|
13
12
|
end
|
@@ -22,6 +21,7 @@ module CiteProc
|
|
22
21
|
|
23
22
|
it 'creates names variables for name fields' do
|
24
23
|
Item.new(:editor => { :given => 'Jane' }).editor.should be_a(Names)
|
24
|
+
Item.new(:editor => 'Plato and Socrates').editor.should have(2).names
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'creates text variables for unknown fields' do
|
@@ -29,7 +29,26 @@ module CiteProc
|
|
29
29
|
v.should be_a(Variable)
|
30
30
|
v.should == '42'
|
31
31
|
end
|
32
|
-
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#empty' do
|
35
|
+
it { should be_empty }
|
36
|
+
|
37
|
+
it 'returns false when there is at least one variable in the item' do
|
38
|
+
Item.new(:title => 'foo').should_not be_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#each' do
|
43
|
+
it 'yields each variable to the given block' do
|
44
|
+
Item.new(:title => 'foo', :edition => 2).each.map {|kv| kv.join('-') }.sort.should == %w{edition-2 title-foo}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#each_value' do
|
49
|
+
it "yields each variable's value to the given block" do
|
50
|
+
Item.new(:title => 'foo', :edition => 2).each_value.map(&:to_s).sort.should == %w{2 foo}
|
51
|
+
end
|
33
52
|
end
|
34
53
|
|
35
54
|
describe '#to_citeproc' do
|
data/spec/citeproc/names_spec.rb
CHANGED
@@ -3,490 +3,605 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
module CiteProc
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
6
|
+
|
7
|
+
describe 'CiteProc Names' do
|
8
|
+
|
9
|
+
let(:poe) { Name.new(:family => 'Poe', :given => 'Edgar Allen') }
|
10
|
+
let(:joe) { Name.new(:given => 'Joe') }
|
11
|
+
let(:plato) { Name.new(:given => 'Plato') }
|
12
|
+
let(:aristotle) { Name.new(:given => 'Ἀριστοτέλης') }
|
13
|
+
let(:dostoyevksy) { Name.new(:given => 'Фёдор Михайлович', :family => 'Достоевский') }
|
14
|
+
|
15
|
+
let(:utf) { Name.new(
|
16
|
+
:given => 'Gérard',
|
17
|
+
:'dropping-particle' => 'de',
|
18
|
+
:'non-dropping-particle' => 'la',
|
19
|
+
:family => 'Martinière',
|
20
|
+
:suffix => 'III')
|
21
|
+
}
|
22
|
+
|
23
|
+
let(:markup) { Name.new(
|
24
|
+
:given => '<b>Gérard</b>',
|
25
|
+
:'dropping-particle' => 'd<i>e</i>',
|
26
|
+
:'non-dropping-particle' => 'la',
|
27
|
+
:family => 'Mar<strong>tinière</strong>',
|
28
|
+
:suffix => 'III')
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
let(:japanese) { Name.new(
|
33
|
+
"family" => "穂積",
|
34
|
+
"given" => "陳重")
|
35
|
+
}
|
36
|
+
|
37
|
+
let(:saunders) { Name.new("family" => "Saunders", "given" => "John Bertrand de Cusance Morant") }
|
38
|
+
|
39
|
+
let(:humboldt) { Name.new(
|
40
|
+
"family" => "Humboldt",
|
41
|
+
"given" => "Alexander",
|
42
|
+
"dropping-particle" => "von")
|
43
|
+
}
|
44
|
+
|
45
|
+
let(:van_gogh) { Name.new(
|
46
|
+
"family" => "Gogh",
|
47
|
+
"given" => "Vincent",
|
48
|
+
"non-dropping-particle" => "van")
|
49
|
+
}
|
50
|
+
|
51
|
+
let(:jr) { Name.new(
|
52
|
+
"family" => "Stephens",
|
53
|
+
"given" => "James",
|
54
|
+
"suffix" => "Jr.")
|
55
|
+
}
|
56
|
+
|
57
|
+
let(:frank) { Name.new(
|
58
|
+
"family" => "Bennett",
|
59
|
+
"given" => "Frank G.",
|
60
|
+
"suffix" => "Jr.",
|
61
|
+
"comma-suffix" => "true")
|
62
|
+
}
|
63
|
+
|
64
|
+
let(:ramses) { Name.new(
|
65
|
+
:family => 'Ramses',
|
66
|
+
:given => 'Horatio',
|
67
|
+
:suffix => 'III')
|
68
|
+
}
|
69
|
+
|
70
|
+
describe Name do
|
71
|
+
|
72
|
+
|
73
|
+
it { should_not be_nil }
|
74
|
+
|
75
|
+
describe 'formatting options' do
|
76
|
+
|
77
|
+
it 'does not always demote particle by default' do
|
78
|
+
Name.new.always_demote_particle?.should be false
|
79
|
+
Name.new.always_demote_non_dropping_particle?.should be false
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'does not demote particle by default' do
|
83
|
+
Name.new.demote_particle?.should be false
|
84
|
+
Name.new.demote_non_dropping_particle?.should be false
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'does not demote particle in sort order by default' do
|
88
|
+
Name.new.sort_order!.demote_particle?.should be false
|
89
|
+
Name.new.sort_order!.demote_non_dropping_particle?.should be false
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'always demotes particle if option is set' do
|
93
|
+
Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').always_demote_particle?.should be true
|
94
|
+
Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').always_demote_non_dropping_particle?.should be true
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'demotes particle in sort order if option is set to sort-only' do
|
98
|
+
Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').sort_order!.demote_particle?.should be true
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'never demotes particle by default' do
|
102
|
+
Name.new.never_demote_particle?.should be true
|
103
|
+
Name.new.never_demote_non_dropping_particle?.should be true
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'is not in sort order by default' do
|
107
|
+
Name.new.sort_order?.should be false
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'uses the long form by default' do
|
111
|
+
Name.new.should be_long_form
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'does not use short form by default' do
|
115
|
+
Name.new.should_not be_short_form
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'constructing' do
|
121
|
+
|
122
|
+
describe '.new' do
|
123
|
+
|
124
|
+
it 'accepts a symbolized hash' do
|
125
|
+
Name.new(:family => 'Doe').to_s.should == 'Doe'
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'accepts a stringified hash' do
|
129
|
+
Name.new('family' => 'Doe').to_s.should == 'Doe'
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#dup' do
|
138
|
+
|
139
|
+
it 'returns a new name copied by value' do
|
140
|
+
poe.dup.upcase!.to_s.should_not == poe.to_s
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'script awareness' do
|
146
|
+
|
147
|
+
it 'english names are romanesque' do
|
148
|
+
frank.should be_romanesque
|
149
|
+
end
|
150
|
+
|
151
|
+
if CiteProc.oniguruma?
|
152
|
+
it 'ancient greek names are romanesque' do
|
153
|
+
aristotle.should be_romanesque
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'russian names are romanesque' do
|
157
|
+
dostoyevksy.should be_romanesque
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'japanese names are not romanesque' do
|
162
|
+
japanese.should_not be_romanesque
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'german names are romanesque' do
|
166
|
+
Name.new(:given => 'Firedrich', :family => 'Hölderlin').should be_romanesque
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'french names are romanesque' do
|
170
|
+
utf.should be_romanesque
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'markup does not interfere with romanesque test' do
|
174
|
+
markup.should be_romanesque
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'literals' do
|
180
|
+
|
181
|
+
it 'is a literal if the literal attribute is set' do
|
182
|
+
Name.new(:literal => 'GNU/Linux').should be_literal
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'is not literal by default' do
|
186
|
+
Name.new.should_not be_literal
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'is literal even if other name parts are set' do
|
190
|
+
Name.new(:family => 'Tux', :literal => 'GNU/Linux').should be_literal
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'in-place manipulation (bang! methods)' do
|
196
|
+
|
197
|
+
it 'delegates to string for family name' do
|
198
|
+
plato.swapcase!.to_s.should == 'pLATO'
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'delegates to string for given name' do
|
202
|
+
humboldt.gsub!(/^Alex\w*/, 'Wilhelm').to_s.should == 'Wilhelm von Humboldt'
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'delegates to string for dropping particle' do
|
206
|
+
humboldt.upcase!.dropping_particle.should == 'VON'
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'delegates to string for non dropping particle' do
|
210
|
+
van_gogh.upcase!.non_dropping_particle.should == 'VAN'
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'delegates to string for suffix' do
|
214
|
+
frank.sub!(/jr./i, 'Sr.').to_s.should == 'Frank G. Bennett, Sr.'
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'returns the name object' do
|
218
|
+
poe.upcase!.should be_a(Name)
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
describe '#to_s' do
|
225
|
+
|
226
|
+
it 'returns an empty string by default' do
|
227
|
+
Name.new.to_s.should be_empty
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'returns the last name if only last name is set' do
|
231
|
+
Name.new(:family => 'Doe').to_s.should == 'Doe'
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'returns the first name if only the first name is set' do
|
235
|
+
Name.new(:given => 'John').to_s.should == 'John'
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'prints japanese names using static ordering' do
|
239
|
+
japanese.to_s.should == '穂積 陳重'
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'returns the literal if the name is a literal' do
|
243
|
+
Name.new(:literal => 'GNU/Linux').to_s == 'GNU/Linux'
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'returns the name in display order by default' do
|
247
|
+
Name.new(:family => 'Doe', :given => 'John').to_s.should == 'John Doe'
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'returns the name in sort order if the sort order option is active' do
|
251
|
+
Name.new(:family => 'Doe', :given => 'John').sort_order!.to_s.should == 'Doe, John'
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'returns the full given name' do
|
255
|
+
saunders.to_s.should == 'John Bertrand de Cusance Morant Saunders'
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'includes dropping particles' do
|
259
|
+
humboldt.to_s.should == 'Alexander von Humboldt'
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'includes non dropping particles' do
|
263
|
+
van_gogh.to_s.should == 'Vincent van Gogh'
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'includes suffices' do
|
267
|
+
jr.to_s.should == 'James Stephens Jr.'
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'uses the comma suffix option' do
|
271
|
+
frank.to_s.should == 'Frank G. Bennett, Jr.'
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'prints unicode characters' do
|
275
|
+
utf.to_s.should == "Gérard de la Martinière III"
|
276
|
+
end
|
277
|
+
|
278
|
+
if CiteProc.oniguruma?
|
279
|
+
it 'prints russian names normally' do
|
280
|
+
dostoyevksy.to_s.should == 'Фёдор Михайлович Достоевский'
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe 'when static ordering is active' do
|
285
|
+
|
286
|
+
it 'always prints the family name first' do
|
287
|
+
poe.static_order!.to_s.should == 'Poe Edgar Allen'
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
describe 'when the sort order option is active' do
|
293
|
+
|
294
|
+
it 'returns an empty string by default' do
|
295
|
+
Name.new.sort_order!.to_s.should be_empty
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'returns the last name if only last name is set' do
|
299
|
+
Name.new({:family => 'Doe'}, { :'name-as-sort-order' => true }).to_s.should == 'Doe'
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'returns the first name if only the first name is set' do
|
303
|
+
Name.new(:given => 'John').sort_order!.to_s.should == 'John'
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'prints japanese names using static ordering' do
|
307
|
+
japanese.sort_order!.to_s.should == '穂積 陳重'
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'returns the literal if the name is a literal' do
|
311
|
+
Name.new(:literal => 'GNU/Linux').sort_order!.to_s == 'GNU/Linux'
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'uses comma for suffix if comma suffix is set' do
|
315
|
+
frank.sort_order!.to_s.should == 'Bennett, Frank G., Jr.'
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'also uses comma for suffix if comma suffix is *not* set' do
|
319
|
+
jr.sort_order!.to_s.should == 'Stephens, James, Jr.'
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'for normal names it prints them as "family, given"' do
|
323
|
+
poe.sort_order!.to_s.should == 'Poe, Edgar Allen'
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'particles come after given name by default' do
|
327
|
+
van_gogh.sort_order!.to_s.should == 'van Gogh, Vincent'
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'particles come after given name if demote option is active' do
|
331
|
+
van_gogh.sort_order!.demote_particle!.to_s.should == 'Gogh, Vincent van'
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'dropping particles come after given name' do
|
335
|
+
humboldt.sort_order!.to_s.should == 'Humboldt, Alexander von'
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'by default if all parts are set they are returned as "particle family, first dropping-particle, suffix"' do
|
339
|
+
utf.sort_order!.to_s.should == 'la Martinière, Gérard de, III'
|
340
|
+
end
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
|
346
|
+
describe '#sort_order' do
|
347
|
+
|
348
|
+
it 'returns only a single token for literal names' do
|
349
|
+
Name.new(:literal => 'ACME Corp.').sort_order.should have(1).element
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'strips leading "the" off literal names' do
|
353
|
+
Name.new(:literal => 'The ACME Corp.').sort_order[0].should == 'ACME Corp.'
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'strips leading "a" off literal names' do
|
357
|
+
Name.new(:literal => 'A Company').sort_order[0].should == 'Company'
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'strips leading "an" off literal names' do
|
361
|
+
Name.new(:literal => 'an ACME Corp.').sort_order[0].should == 'ACME Corp.'
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'strips leading "l\'" off literal names' do
|
365
|
+
Name.new(:literal => "L'Augustine").sort_order[0].should == 'Augustine'
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'always returns four tokens for non literal names' do
|
369
|
+
poe.sort_order.should have(4).elements
|
370
|
+
joe.sort_order.should have(4).elements
|
371
|
+
aristotle.sort_order.should have(4).elements
|
372
|
+
utf.sort_order.should have(4).elements
|
373
|
+
frank.sort_order.should have(4).elements
|
374
|
+
japanese.sort_order.should have(4).elements
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'demotes non dropping particles if option is set' do
|
378
|
+
van_gogh.demote_particle!.sort_order.should == ['Gogh', 'van', 'Vincent', '']
|
379
|
+
end
|
380
|
+
|
381
|
+
it 'does not demote non dropping particles by default' do
|
382
|
+
van_gogh.sort_order.should == ['van Gogh', '', 'Vincent', '']
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'does not demote non dropping particles by default but dropping particles are demoted' do
|
386
|
+
utf.sort_order.should == ['la Martinière', 'de', 'Gérard', 'III']
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'demotes dropping particles' do
|
390
|
+
humboldt.sort_order.should == ['Humboldt', 'von', 'Alexander', '']
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'combines non dropping particles with family name if option demote-non-dropping-particles is not active' do
|
394
|
+
van_gogh.never_demote_particle!.sort_order.should == ['van Gogh', '', 'Vincent', '']
|
395
|
+
end
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
describe 'sorting' do
|
400
|
+
|
401
|
+
it 'sorts by sort order by default' do
|
402
|
+
[poe, utf, joe, plato].sort.should == [joe, plato, utf, poe]
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
describe Names do
|
411
|
+
|
412
|
+
let(:gang_of_four) {
|
413
|
+
Names.parse!('Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides')
|
414
|
+
}
|
415
|
+
|
416
|
+
it { should_not be nil }
|
417
|
+
it { should_not be_numeric }
|
418
|
+
|
419
|
+
describe 'constructing' do
|
420
|
+
|
421
|
+
it 'accepts a single name' do
|
422
|
+
lambda { Names.new(joe) }.should_not raise_error
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'accepts a single name as hash' do
|
426
|
+
Names.new(:given => 'Jim').should have(1).names
|
427
|
+
end
|
428
|
+
|
429
|
+
it 'accepts two names' do
|
430
|
+
Names.new(joe, poe).should have(2).names
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'accepts two names as hash' do
|
434
|
+
Names.new({:given => 'Jim'}, {:family => 'Jameson'}).should have(2).names
|
435
|
+
end
|
436
|
+
|
437
|
+
it 'accepts an array of names' do
|
438
|
+
Names.new([joe, poe]).should have(2).names
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
|
443
|
+
describe 'parsing' do
|
444
|
+
it 'accepts a single name as a string' do
|
445
|
+
Names.parse('Edgar A. Poe').should have(1).names
|
446
|
+
end
|
447
|
+
|
448
|
+
it 'accepts multiple names as a string' do
|
449
|
+
Names.parse('Edgar A. Poe and Hawthorne, Nathaniel and Herman Melville').should have(3).names
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'parses the passed-in family names' do
|
453
|
+
Names.parse('Edgar A. Poe and Hawthorne, Nathaniel and Herman Melville').map { |n|
|
454
|
+
n.values_at(:family) }.flatten.should == %w{ Poe Hawthorne Melville }
|
455
|
+
end
|
456
|
+
|
457
|
+
it '#parse returns nil on error' do
|
458
|
+
Names.parse(23).should be_nil
|
459
|
+
end
|
460
|
+
|
461
|
+
it '#parse! raises an error on bad input' do
|
462
|
+
expect { Names.parse!('A,B,C,D,E') }.to raise_error(ParseError)
|
463
|
+
end
|
464
|
+
|
465
|
+
end
|
466
|
+
|
467
|
+
describe '#strip_markup' do
|
468
|
+
|
469
|
+
it 'strips markup off string representation' do
|
470
|
+
Names.new(markup).strip_markup.should == utf.to_s
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'when using the bang! version, strips markup off each name part' do
|
474
|
+
Names.new(markup).strip_markup![0].should == utf
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
end
|
479
|
+
|
480
|
+
describe 'bang! methods' do
|
481
|
+
it 'delegate to the individual names and return self' do
|
482
|
+
Names.new(poe, plato, joe).upcase!.map(&:given).should == ['EDGAR ALLEN', 'PLATO', 'JOE']
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
[:never, :always, :contextually].each do |setting|
|
487
|
+
setter = "delimiter_#{setting}_precedes_last!"
|
488
|
+
predicate = "delimiter_#{setting}_precedes_last?"
|
489
|
+
|
490
|
+
describe "##{setter}" do
|
491
|
+
it 'sets the delimiter precedes last option accordingly' do
|
492
|
+
Names.new.send(setter).send(predicate).should == true
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
describe '#delimiter_precedes_last' do
|
498
|
+
it 'returns false by default' do
|
499
|
+
Names.new(joe).should_not be_delimiter_precedes_last
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'returns false by default for a single name' do
|
503
|
+
Names.new(joe).should_not be_delimiter_precedes_last
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'returns false by default for two names' do
|
507
|
+
Names.new(joe, poe).should_not be_delimiter_precedes_last
|
508
|
+
end
|
509
|
+
|
510
|
+
it 'returns true for two names when option set to always' do
|
511
|
+
Names.new(joe, poe).delimiter_always_precedes_last!.should be_delimiter_precedes_last
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'returns true by default for three names' do
|
515
|
+
Names.new(joe, poe, plato).should be_delimiter_precedes_last
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'returns false for three names when option set to :never' do
|
519
|
+
Names.new(joe, poe, plato).delimiter_never_precedes_last!.should_not be_delimiter_precedes_last
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
describe '#to_bibtex' do
|
524
|
+
|
525
|
+
describe 'when there is only a single name' do
|
526
|
+
it 'prints the name in sort order' do
|
527
|
+
Names.new(poe).to_bibtex.should == 'Poe, Edgar Allen'
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
describe 'when there are two or more names' do
|
532
|
+
it 'prints the names in sort order connected with the word "and"' do
|
533
|
+
Names.new(poe, plato, humboldt).to_bibtex.should == 'Poe, Edgar Allen and Plato and Humboldt, Alexander von'
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
end
|
538
|
+
|
539
|
+
describe '#to_s' do
|
540
|
+
|
541
|
+
describe 'when the number of names exceeds the et-al-min option' do
|
542
|
+
before do
|
543
|
+
gang_of_four.options[:'et-al-min'] = 3
|
544
|
+
gang_of_four.options[:'et-al-use-first'] = 2
|
545
|
+
gang_of_four.options[:'et-al'] = 'FOO'
|
546
|
+
end
|
547
|
+
|
548
|
+
it 'prints only the et-al-use-first names' do
|
549
|
+
gang_of_four.to_s.should match(/gamma.+helm/i)
|
550
|
+
gang_of_four.to_s.should_not match(/johnson|vlissides/i)
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'adds et-al at the end' do
|
554
|
+
gang_of_four.to_s.should end_with('FOO')
|
555
|
+
end
|
556
|
+
|
557
|
+
it 'adds the delimiter before et-al when multiple names are printed' do
|
558
|
+
gang_of_four.to_s.should end_with(', FOO')
|
559
|
+
end
|
560
|
+
|
561
|
+
it 'does not add the delimiter before et-al when only one name is printed' do
|
562
|
+
gang_of_four.options[:'et-al-use-first'] = 1
|
563
|
+
gang_of_four.to_s.should_not end_with(', FOO')
|
564
|
+
end
|
565
|
+
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'squeezes multiple whitespace between delimiter and connector' do
|
569
|
+
Names.new(poe, humboldt, van_gogh, joe).to_s.should_not match(/\s{2}/)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
describe '#each' do
|
574
|
+
it 'returns an enumerator when no block given' do
|
575
|
+
gang_of_four.each.should respond_to(:each)
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
describe '#to_citeproc' do
|
580
|
+
it 'returns a list of hashes' do
|
581
|
+
gang_of_four.to_citeproc.map(&:class).uniq.should == [Hash]
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
describe 'sorting' do
|
586
|
+
it 'accepts other Names instance' do
|
587
|
+
(Names.new(poe, plato) <=> Names.new(plato)).should equal(1)
|
588
|
+
(Names.new(plato) <=> Names.new(poe, plato)).should equal(-1)
|
589
|
+
end
|
590
|
+
|
591
|
+
it 'accepts other list of names' do
|
592
|
+
(Names.new(poe, plato) <=> [plato]).should equal(1)
|
593
|
+
(Names.new(plato) <=> [poe, plato]).should equal(-1)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
describe '#inspect' do
|
598
|
+
it 'returns a string' do
|
599
|
+
gang_of_four.inspect.should be_a(String)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
end
|
604
|
+
|
605
|
+
end
|
606
|
+
|
492
607
|
end
|