citeproc 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,36 +3,49 @@ require 'spec_helper'
3
3
  module CiteProc
4
4
  describe Attributes do
5
5
 
6
- before(:each) { Object.instance_eval { include Attributes } }
6
+ before(:all) do
7
+ A = Class.new { include Attributes }
8
+ end
7
9
 
8
- let(:instance) { o = Object.new }
9
- let(:other) { o = Object.new; o.attributes[:foo] = 'bar'; o }
10
+ let(:instance) do
11
+ o = A.new
12
+ o[:bar] = 'foo'
13
+ o
14
+ end
15
+
16
+ let(:other) do
17
+ o = A.new
18
+ o[:foo] = 'bar'
19
+ o
20
+ end
10
21
 
11
22
  it { should_not be_nil }
12
23
 
13
24
  describe '.attr_fields' do
14
25
 
15
- # before(:all) { class Object; attr_fields :value, %w[ is-numeric punctuation-mode ]; end }
26
+ # before(:all) do
27
+ # A.instance_eval { attr_fields :value, %w[ is-numeric punctuation-mode ] }
28
+ # end
16
29
 
17
30
  it 'generates setters for attr_field values' do
18
31
  # pending
19
- # lambda { Object.new.is_numeric }.should_not raise_error
32
+ # lambda { A.new.is_numeric }.should_not raise_error
20
33
  end
21
34
 
22
35
  it 'generates no other setters' do
23
- lambda { Object.new.some_other_value }.should raise_error
36
+ lambda { A.new.some_other_value }.should raise_error
24
37
  end
25
38
  end
26
39
 
27
40
  describe '#merge' do
28
41
 
29
42
  it 'merges non-existent values from other object' do
30
- Object.new.merge(other).attributes[:foo].should == 'bar'
43
+ A.new.merge(other)[:foo].should == 'bar'
31
44
  end
32
45
 
33
- # it 'does not overwrite existing values when merging other object' do
34
- # instance.merge(other)['foo'].should == 'bar'
35
- # end
46
+ it 'does not overwrite existing values when merging other object' do
47
+ instance.merge(other)[:bar].should == 'foo'
48
+ end
36
49
 
37
50
  end
38
51
 
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ module CiteProc
4
+
5
+ describe Bibliography do
6
+
7
+ it { should be_empty }
8
+ it { should_not have_errors }
9
+
10
+ describe '#to_citeproc conversion' do
11
+
12
+ it 'returns an array' do
13
+ subject.to_citeproc.should be_a(Array)
14
+ end
15
+
16
+ it 'returns exactly two elements' do
17
+ subject.to_citeproc.should have(2).elements
18
+ end
19
+
20
+ it 'returns formatting options as the first element' do
21
+ subject.to_citeproc.first.should be_a(Hash)
22
+ end
23
+
24
+ describe 'the formatting options' do
25
+ let(:options) { subject.to_citeproc[0] }
26
+
27
+ it 'contains a the error list' do
28
+ options.should have_key('bibliography_errors')
29
+ options['bibliography_errors'].should be_empty
30
+ end
31
+
32
+ end
33
+
34
+ it 'returns the list of references as the second element' do
35
+ subject.to_citeproc.last.should be_a(Array)
36
+ end
37
+
38
+ end
39
+
40
+ describe '.parse (citeproc parser)' do
41
+ let(:js) { <<-JS_END }
42
+ [
43
+ {
44
+ "maxoffset": 0,
45
+ "entryspacing": 0,
46
+ "linespacing": 0,
47
+ "hangingindent": 0,
48
+ "second-field-align": true,
49
+ "bibstart": "<div class=\\"csl-bib-body\\">\\n",
50
+ "bibend": "</div>",
51
+ "bibliography_errors": []
52
+ },
53
+ [
54
+ "<div class=\\"csl-entry\\">Book A</div>",
55
+ "<div class=\\"csl-entry\\">Book C</div>"
56
+ ]
57
+ ]
58
+ JS_END
59
+
60
+ it 'parses citeproc/json strings' do
61
+ b = Bibliography.parse(js)
62
+ b.should be_a(Bibliography)
63
+ b.should have(2).references
64
+ b.should_not have_errors
65
+ b.options[:align].should be true
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ module CiteProc
4
+
5
+ describe 'citation input' do
6
+
7
+ let(:hash) {{
8
+ "citationItems" => [
9
+ {
10
+ "id" => "ITEM-1"
11
+ }
12
+ ],
13
+ "properties" => {
14
+ "noteIndex" => 1
15
+ }
16
+ }}
17
+
18
+ let(:json) { MultiJson.encode(hash) }
19
+
20
+
21
+
22
+ describe CitationData do
23
+
24
+ it { should_not be nil }
25
+ it { should be_empty }
26
+
27
+ it 'has not been processed by default' do
28
+ CitationData.new.should_not be_processed
29
+ end
30
+
31
+ describe '.new' do
32
+
33
+ it 'accepts a citeproc hash' do
34
+ d = CitationData.new(hash)
35
+ d.should be_footnote
36
+ d.should_not be_empty
37
+ d[0].should be_a(CitationItem)
38
+ d.index.should == 1
39
+ end
40
+
41
+ it 'accepts an array of items' do
42
+ CitationData.new([CitationItem.new(:id => 'id')]).should have(1).items
43
+ end
44
+
45
+ it 'accepts an array of hashes' do
46
+ CitationData.new([{:id => 'id'}])[0].should be_a(CitationItem)
47
+ end
48
+
49
+ end
50
+
51
+ describe '#to_citeproc' do
52
+
53
+ it 'returns empty an empty/default citation data element by default' do
54
+ CitationData.new.to_citeproc.should == { 'citationItems' => [], 'properties' => { 'noteIndex' => 0}}
55
+ end
56
+
57
+
58
+ end
59
+
60
+ end
61
+
62
+ describe CitationItem do
63
+
64
+ it { should_not be nil }
65
+ it { should be_empty }
66
+
67
+ describe '.new' do
68
+
69
+ it 'accepts a hash as input' do
70
+ CitationItem.new(:label => 'chapter').should have_label
71
+ end
72
+
73
+ end
74
+
75
+ describe '#to_citeproc' do
76
+
77
+ it 'returns empty citation data by default' do
78
+ CitationItem.new.to_citeproc.should == {}
79
+ end
80
+
81
+ it 'returns a hash with stringified keys' do
82
+ CitationItem.new(:type => :article).to_citeproc.should have_key('type')
83
+ end
84
+
85
+ it 'returns a hash with stringified values' do
86
+ CitationItem.new(:type => :article).to_citeproc.should have_value('article')
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+ end
@@ -3,6 +3,15 @@ require 'spec_helper'
3
3
  module CiteProc
4
4
  describe Date do
5
5
 
6
+ let(:ad2k) { Date.create('date-parts' => [[2000]])}
7
+ let(:may) { Date.create('date-parts' => [[2000, 5]])}
8
+ let(:first_of_may) { Date.create('date-parts' => [[2000, 5, 1]])}
9
+
10
+ let(:bc100) { Date.create('date-parts' => [[-100]]) }
11
+ let(:bc50) { Date.create('date-parts' => [[-50]]) }
12
+ let(:ad50) { Date.create('date-parts' => [[50]]) }
13
+ let(:ad100) { Date.create('date-parts' => [[100]]) }
14
+
6
15
  it { should_not be nil }
7
16
 
8
17
  it { should_not be_numeric }
@@ -11,6 +20,18 @@ module CiteProc
11
20
 
12
21
  end
13
22
 
23
+ describe '.parse' do
24
+
25
+ it 'returns nil by default' do
26
+ Date.parse('').should be nil
27
+ Date.parse(nil).should be nil
28
+ end
29
+
30
+ it 'parses date strings' do
31
+ Date.parse('2004-10-26').year.should == 2004
32
+ end
33
+ end
34
+
14
35
  describe '.create' do
15
36
  it 'should accept parameters and return a new instance' do
16
37
  Date.create('date-parts' => [[2001, 1]]).year.should == 2001
@@ -40,15 +61,6 @@ module CiteProc
40
61
 
41
62
  describe 'sorting' do
42
63
 
43
- let(:ad2k) { Date.create('date-parts' => [[2000]])}
44
- let(:may) { Date.create('date-parts' => [[2000, 5]])}
45
- let(:first_of_may) { Date.create('date-parts' => [[2000, 5, 1]])}
46
-
47
- let(:bc100) { Date.create('date-parts' => [[-100]]) }
48
- let(:bc50) { Date.create('date-parts' => [[-50]]) }
49
- let(:ad50) { Date.create('date-parts' => [[50]]) }
50
- let(:ad100) { Date.create('date-parts' => [[100]]) }
51
-
52
64
  it 'dates with more date-parts will come after those with fewer parts' do
53
65
  (ad2k < may && may < first_of_may).should be true
54
66
  end
@@ -65,6 +77,50 @@ module CiteProc
65
77
  end
66
78
  end
67
79
 
80
+ describe 'b.c. and a.d.' do
81
+
82
+ it 'the year 993 is a.d.' do
83
+ Date.new(993).should be_ad
84
+ end
85
+
86
+ it 'the year 1000 is not a.d.' do
87
+ Date.new(1000).should_not be_ad
88
+ end
89
+
90
+ it 'the year 993 is not b.c.' do
91
+ Date.new(993).should_not be_bc
92
+ end
93
+
94
+ it 'the year 0 is a.d.' do
95
+ Date.new(0).should be_ad
96
+ end
97
+
98
+ it 'the year 0 is not b.c.' do
99
+ Date.new(0).should_not be_bc
100
+ end
101
+
102
+ it 'the year -33 is not a.d.' do
103
+ Date.new(-33).should_not be_ad
104
+ end
105
+
106
+ it 'the year -33 is b.c.' do
107
+ Date.new(-33).should be_bc
108
+ end
109
+
110
+ it 'today is not a.d.' do
111
+ Date.today.should_not be_ad
112
+ end
113
+
114
+ it 'today is not b.c.' do
115
+ Date.today.should_not be_bc
116
+ end
117
+
118
+ it 'the year 2000 is not a.d.' do
119
+ ad2k.should_not be_ad
120
+ end
121
+
122
+ end
123
+
68
124
  describe '#to_json' do
69
125
  it 'supports simple parts' do
70
126
  Date.new(%w{2000 1 15}).to_json.should == '{"date-parts":[[2000,1,15]]}'
@@ -53,4 +53,37 @@ describe Hash do
53
53
  end
54
54
 
55
55
  end
56
+
57
+ end
58
+
59
+ describe Array do
60
+
61
+ describe '#compact_join' do
62
+
63
+ it 'is equivalent to #join when there are no blank elements' do
64
+ [1,2,3].compact_join(' ').should == [1,2,3].join(' ')
65
+ end
66
+
67
+ it 'is equivalent to #compact and #join when there are no empty elements' do
68
+ [1,2,3,nil,nil,4].compact_join(' ').should == [1,2,3,nil,nil,4].compact.join(' ')
69
+ end
70
+
71
+ it 'returns an empty string if the array is empty' do
72
+ [].compact_join(' ').should == ''
73
+ end
74
+
75
+ it 'returns an empty string if there are only nil elements' do
76
+ [nil,nil,nil].compact_join(' ').should == ''
77
+ end
78
+
79
+ it 'returns an empty string if there are only empty elements' do
80
+ ['','',''].compact_join(' ').should == ''
81
+ end
82
+
83
+ it 'returns an empty string if there are only blank elements' do
84
+ ['','',nil,'',nil].compact_join(' ').should == ''
85
+ end
86
+
87
+ end
88
+
56
89
  end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ module CiteProc
4
+ describe Item do
5
+
6
+ it { should_not be nil }
7
+ it { should be_empty }
8
+
9
+ describe '.new' do
10
+
11
+ it 'creates number variables for number fields' do
12
+ Item.new(:edition => 23).edition.should be_a(Number)
13
+ end
14
+
15
+ it 'creates text variable for text fields' do
16
+ Item.new(:ISBN => 23).isbn.should be_a(Text)
17
+ end
18
+
19
+ it 'creates date variables for date fields' do
20
+ Item.new(:accessed => Time.now).accessed.should be_a(CiteProc::Date)
21
+ end
22
+
23
+ it 'creates names variables for name fields' do
24
+ Item.new(:editor => { :given => 'Jane' }).editor.should be_a(Names)
25
+ end
26
+
27
+ it 'creates text variables for unknown fields' do
28
+ v = Item.new(:unknown => 42)[:unknown]
29
+ v.should be_a(Variable)
30
+ v.should == '42'
31
+ end
32
+
33
+ end
34
+
35
+ describe '#to_citeproc' do
36
+
37
+ it 'returns an empty hash by default' do
38
+ Item.new.to_citeproc.should == {}
39
+ end
40
+
41
+ it 'returns a hash with stringified keys' do
42
+ Item.new(:issue => 42).to_citeproc.should have_key('issue')
43
+ end
44
+
45
+ it 'returns a hash with stringified values' do
46
+ Item.new(:issue => 42).to_citeproc.values[0].should == '42'
47
+ end
48
+
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,492 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ module CiteProc
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
+
71
+ describe Name do
72
+
73
+
74
+ it { should_not be_nil }
75
+
76
+ describe 'formatting options' do
77
+
78
+ it 'does not always demote particle by default' do
79
+ Name.new.always_demote_particle?.should be false
80
+ Name.new.always_demote_non_dropping_particle?.should be false
81
+ end
82
+
83
+ it 'does not demote particle by default' do
84
+ Name.new.demote_particle?.should be false
85
+ Name.new.demote_non_dropping_particle?.should be false
86
+ end
87
+
88
+ it 'does not demote particle in sort order by default' do
89
+ Name.new.sort_order!.demote_particle?.should be false
90
+ Name.new.sort_order!.demote_non_dropping_particle?.should be false
91
+ end
92
+
93
+ it 'always demotes particle if option is set' do
94
+ Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').always_demote_particle?.should be true
95
+ Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').always_demote_non_dropping_particle?.should be true
96
+ end
97
+
98
+ it 'demotes particle in sort order if option is set to sort-only' do
99
+ Name.new({}, :'demote-non-dropping-particle' => 'display-and-sort').sort_order!.demote_particle?.should be true
100
+ end
101
+
102
+ it 'never demotes particle by default' do
103
+ Name.new.never_demote_particle?.should be true
104
+ Name.new.never_demote_non_dropping_particle?.should be true
105
+ end
106
+
107
+ it 'is not in sort order by default' do
108
+ Name.new.sort_order?.should be false
109
+ end
110
+
111
+ it 'uses the long form by default' do
112
+ Name.new.should be_long_form
113
+ end
114
+
115
+ it 'does not use short form by default' do
116
+ Name.new.should_not be_short_form
117
+ end
118
+
119
+ end
120
+
121
+ describe 'constructing' do
122
+
123
+ describe '.new' do
124
+
125
+ it 'accepts a symbolized hash' do
126
+ Name.new(:family => 'Doe').to_s.should == 'Doe'
127
+ end
128
+
129
+ it 'accepts a stringified hash' do
130
+ Name.new('family' => 'Doe').to_s.should == 'Doe'
131
+ end
132
+
133
+
134
+ end
135
+
136
+ end
137
+
138
+ describe '#dup' do
139
+
140
+ it 'returns a new name copied by value' do
141
+ poe.dup.upcase!.to_s.should_not == poe.to_s
142
+ end
143
+
144
+ end
145
+
146
+ describe 'script awareness' do
147
+
148
+ it 'english names are romanesque' do
149
+ frank.should be_romanesque
150
+ end
151
+
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
+
160
+ it 'japanese names are not romanesque' do
161
+ japanese.should_not be_romanesque
162
+ end
163
+
164
+ it 'german names are romanesque' do
165
+ Name.new(:given => 'Firedrich', :family => 'Hölderlin').should be_romanesque
166
+ end
167
+
168
+ it 'french names are romanesque' do
169
+ utf.should be_romanesque
170
+ end
171
+
172
+ it 'markup does not interfere with romanesque test' do
173
+ markup.should be_romanesque
174
+ end
175
+
176
+ end
177
+
178
+ describe 'literals' do
179
+
180
+ it 'is a literal if the literal attribute is set' do
181
+ Name.new(:literal => 'GNU/Linux').should be_literal
182
+ end
183
+
184
+ it 'is not literal by default' do
185
+ Name.new.should_not be_literal
186
+ end
187
+
188
+ it 'is literal even if other name parts are set' do
189
+ Name.new(:family => 'Tux', :literal => 'GNU/Linux').should be_literal
190
+ end
191
+
192
+ end
193
+
194
+ describe 'in-place manipulation (bang! methods)' do
195
+
196
+ it 'delegates to string for family name' do
197
+ plato.swapcase!.to_s.should == 'pLATO'
198
+ end
199
+
200
+ it 'delegates to string for given name' do
201
+ humboldt.gsub!(/^Alex\w*/, 'Wilhelm').to_s.should == 'Wilhelm von Humboldt'
202
+ end
203
+
204
+ it 'delegates to string for dropping particle' do
205
+ humboldt.upcase!.dropping_particle.should == 'VON'
206
+ end
207
+
208
+ it 'delegates to string for non dropping particle' do
209
+ van_gogh.upcase!.non_dropping_particle.should == 'VAN'
210
+ end
211
+
212
+ it 'delegates to string for suffix' do
213
+ frank.sub!(/jr./i, 'Sr.').to_s.should == 'Frank G. Bennett, Sr.'
214
+ end
215
+
216
+ it 'returns the name object' do
217
+ poe.upcase!.should be_a(Name)
218
+ end
219
+
220
+ end
221
+
222
+
223
+ describe '#to_s' do
224
+
225
+ it 'returns an empty string by default' do
226
+ Name.new.to_s.should be_empty
227
+ end
228
+
229
+ it 'returns the last name if only last name is set' do
230
+ Name.new(:family => 'Doe').to_s.should == 'Doe'
231
+ end
232
+
233
+ it 'returns the first name if only the first name is set' do
234
+ Name.new(:given => 'John').to_s.should == 'John'
235
+ end
236
+
237
+ it 'prints japanese names using static ordering' do
238
+ japanese.to_s.should == '穂積 陳重'
239
+ end
240
+
241
+ it 'returns the literal if the name is a literal' do
242
+ Name.new(:literal => 'GNU/Linux').to_s == 'GNU/Linux'
243
+ end
244
+
245
+ it 'returns the name in display order by default' do
246
+ Name.new(:family => 'Doe', :given => 'John').to_s.should == 'John Doe'
247
+ end
248
+
249
+ it 'returns the name in sort order if the sort order option is active' do
250
+ Name.new(:family => 'Doe', :given => 'John').sort_order!.to_s.should == 'Doe, John'
251
+ end
252
+
253
+ it 'returns the full given name' do
254
+ saunders.to_s.should == 'John Bertrand de Cusance Morant Saunders'
255
+ end
256
+
257
+ it 'includes dropping particles' do
258
+ humboldt.to_s.should == 'Alexander von Humboldt'
259
+ end
260
+
261
+ it 'includes non dropping particles' do
262
+ van_gogh.to_s.should == 'Vincent van Gogh'
263
+ end
264
+
265
+ it 'includes suffices' do
266
+ jr.to_s.should == 'James Stephens Jr.'
267
+ end
268
+
269
+ it 'uses the comma suffix option' do
270
+ frank.to_s.should == 'Frank G. Bennett, Jr.'
271
+ end
272
+
273
+ it 'prints unicode characters' do
274
+ utf.to_s.should == "Gérard de la Martinière III"
275
+ end
276
+
277
+ it 'prints russian names normally' do
278
+ dostoyevksy.to_s.should == 'Фёдор Михайлович Достоевский'
279
+ end
280
+
281
+ describe 'when static ordering is active' do
282
+
283
+ it 'always prints the family name first' do
284
+ poe.static_order!.to_s.should == 'Poe Edgar Allen'
285
+ end
286
+
287
+ end
288
+
289
+ describe 'when the sort order option is active' do
290
+
291
+ it 'returns an empty string by default' do
292
+ Name.new.sort_order!.to_s.should be_empty
293
+ end
294
+
295
+ it 'returns the last name if only last name is set' do
296
+ Name.new({:family => 'Doe'}, { :'name-as-sort-order' => true }).to_s.should == 'Doe'
297
+ end
298
+
299
+ it 'returns the first name if only the first name is set' do
300
+ Name.new(:given => 'John').sort_order!.to_s.should == 'John'
301
+ end
302
+
303
+ it 'prints japanese names using static ordering' do
304
+ japanese.sort_order!.to_s.should == '穂積 陳重'
305
+ end
306
+
307
+ it 'returns the literal if the name is a literal' do
308
+ Name.new(:literal => 'GNU/Linux').sort_order!.to_s == 'GNU/Linux'
309
+ end
310
+
311
+ it 'uses comma for suffix if comma suffix is set' do
312
+ frank.sort_order!.to_s.should == 'Bennett, Frank G., Jr.'
313
+ end
314
+
315
+ it 'also uses comma for suffix if comma suffix is *not* set' do
316
+ jr.sort_order!.to_s.should == 'Stephens, James, Jr.'
317
+ end
318
+
319
+ it 'for normal names it prints them as "family, given"' do
320
+ poe.sort_order!.to_s.should == 'Poe, Edgar Allen'
321
+ end
322
+
323
+ it 'particles come after given name by default' do
324
+ van_gogh.sort_order!.to_s.should == 'van Gogh, Vincent'
325
+ end
326
+
327
+ it 'particles come after given name if demote option is active' do
328
+ van_gogh.sort_order!.demote_particle!.to_s.should == 'Gogh, Vincent van'
329
+ end
330
+
331
+ it 'dropping particles come after given name' do
332
+ humboldt.sort_order!.to_s.should == 'Humboldt, Alexander von'
333
+ end
334
+
335
+ it 'by default if all parts are set they are returned as "particle family, first dropping-particle, suffix"' do
336
+ utf.sort_order!.to_s.should == 'la Martinière, Gérard de, III'
337
+ end
338
+
339
+ end
340
+
341
+ end
342
+
343
+ describe '#sort_order' do
344
+
345
+ it 'returns only a single token for literal names' do
346
+ Name.new(:literal => 'ACME Corp.').sort_order.should have(1).element
347
+ end
348
+
349
+ it 'strips leading "the" off literal names' do
350
+ Name.new(:literal => 'The ACME Corp.').sort_order[0].should == 'ACME Corp.'
351
+ end
352
+
353
+ it 'strips leading "a" off literal names' do
354
+ Name.new(:literal => 'A Company').sort_order[0].should == 'Company'
355
+ end
356
+
357
+ it 'strips leading "an" off literal names' do
358
+ Name.new(:literal => 'an ACME Corp.').sort_order[0].should == 'ACME Corp.'
359
+ end
360
+
361
+ it 'strips leading "l\'" off literal names' do
362
+ Name.new(:literal => "L'Augustine").sort_order[0].should == 'Augustine'
363
+ end
364
+
365
+ it 'always returns four tokens for non literal names' do
366
+ poe.sort_order.should have(4).elements
367
+ joe.sort_order.should have(4).elements
368
+ aristotle.sort_order.should have(4).elements
369
+ utf.sort_order.should have(4).elements
370
+ frank.sort_order.should have(4).elements
371
+ japanese.sort_order.should have(4).elements
372
+ end
373
+
374
+ it 'demotes non dropping particles if option is set' do
375
+ van_gogh.demote_particle!.sort_order.should == ['Gogh', 'van', 'Vincent', '']
376
+ end
377
+
378
+ it 'does not demote non dropping particles by default' do
379
+ van_gogh.sort_order.should == ['van Gogh', '', 'Vincent', '']
380
+ end
381
+
382
+ it 'does not demote non dropping particles by default but dropping particles are demoted' do
383
+ utf.sort_order.should == ['la Martinière', 'de', 'Gérard', 'III']
384
+ end
385
+
386
+ it 'demotes dropping particles' do
387
+ humboldt.sort_order.should == ['Humboldt', 'von', 'Alexander', '']
388
+ end
389
+
390
+ it 'combines non dropping particles with family name if option demote-non-dropping-particles is not active' do
391
+ van_gogh.never_demote_particle!.sort_order.should == ['van Gogh', '', 'Vincent', '']
392
+ end
393
+
394
+ end
395
+
396
+ describe 'sorting' do
397
+
398
+ it 'sorts by sort order by default' do
399
+ [poe, utf, joe, plato].sort.should == [joe, plato, utf, poe]
400
+ end
401
+
402
+ end
403
+
404
+
405
+ end
406
+
407
+ describe Names do
408
+
409
+ it { should_not be nil }
410
+ it { should_not be_numeric }
411
+
412
+ describe 'constructing' do
413
+
414
+ it 'accepts a single name' do
415
+ lambda { Names.new(joe) }.should_not raise_error
416
+ end
417
+
418
+ it 'accepts a single name as hash' do
419
+ Names.new(:given => 'Jim').should have(1).name
420
+ end
421
+
422
+ it 'accepts two names' do
423
+ Names.new(joe, poe).should have(2).names
424
+ end
425
+
426
+ it 'accepts two names as hash' do
427
+ Names.new({:given => 'Jim'}, {:family => 'Jameson'}).should have(2).names
428
+ end
429
+
430
+ it 'accepts an array of names' do
431
+ Names.new([joe, poe]).should have(2).names
432
+ end
433
+
434
+ end
435
+
436
+ describe '#strip_markup' do
437
+
438
+ it 'strips markup off string representation' do
439
+ Names.new(markup).strip_markup.should == utf.to_s
440
+ end
441
+
442
+ it 'when using the bang! version, strips markup off each name part' do
443
+ Names.new(markup).strip_markup![0].should == utf
444
+ end
445
+
446
+
447
+ end
448
+
449
+ describe 'bang! methods' do
450
+
451
+ it 'delegate to the individual names and return self' do
452
+ Names.new(poe, plato, joe).upcase!.map(&:given).should == ['EDGAR ALLEN', 'PLATO', 'JOE']
453
+ end
454
+
455
+ end
456
+
457
+ describe '#to_bibtex' do
458
+
459
+ describe 'when there is only a single name' do
460
+ it 'prints the name in sort order' do
461
+ Names.new(poe).to_bibtex.should == 'Poe, Edgar Allen'
462
+ end
463
+ end
464
+
465
+ describe 'when there are two or more names' do
466
+ it 'prints the names in sort order connected with the word "and"' do
467
+ Names.new(poe, plato, humboldt).to_bibtex.should == 'Poe, Edgar Allen and Plato and Humboldt, Alexander von'
468
+ end
469
+ end
470
+
471
+ end
472
+
473
+ describe '#to_s' do
474
+
475
+ describe 'when the number of names exceeds the et-al-min option' do
476
+
477
+ it 'prints only the et-al-use-first names'
478
+ it 'adds et-al at the end'
479
+ it 'adds the delimiter before et-al only in the right circumstances'
480
+
481
+ end
482
+
483
+ end
484
+
485
+ describe 'sorting' do
486
+ end
487
+
488
+ end
489
+
490
+ end
491
+
492
+ end