bibtex-ruby 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bibtex-ruby might be problematic. Click here for more details.

data/lib/bibtex/entry.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
3
  # Copyright (C) 2010-2012 Sylvester Keil <sylvester.keil.or.at>
4
- #
4
+ #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
7
7
  # the Free Software Foundation, either version 3 of the License, or
8
8
  # (at your option) any later version.
9
- #
9
+ #
10
10
  # This program is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
- #
14
+ #
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  #++
@@ -21,7 +21,7 @@ module BibTeX
21
21
  # Represents a regular BibTeX entry.
22
22
  #
23
23
  class Entry < Element
24
- extend Forwardable
24
+ extend Forwardable
25
25
  include Enumerable
26
26
 
27
27
  # Defines the required fields of the standard entry types
@@ -47,11 +47,11 @@ module BibTeX
47
47
  :booktitle => :title,
48
48
  # :editor => :author
49
49
  }.freeze
50
-
51
-
50
+
51
+
52
52
  NAME_FIELDS = [:author,:editor,:translator].freeze
53
53
  DATE_FIELDS = [:year,:month].freeze
54
-
54
+
55
55
  MONTHS = [:jan,:feb,:mar,:apr,:may,:jun,:jul,:aug,:sep,:oct,:nov,:dec].freeze
56
56
 
57
57
  MONTHS_FILTER = Hash.new do |h,k|
@@ -64,7 +64,7 @@ module BibTeX
64
64
  h[k] = Value.new(k)
65
65
  end
66
66
  end
67
-
67
+
68
68
  CSL_FILTER = Hash.new {|h,k|k}.merge(Hash[*%w{
69
69
  date issued
70
70
  isbn ISBN
@@ -82,7 +82,7 @@ module BibTeX
82
82
  CSL_FIELDS = %w{ abstract annote archive archive_location archive-place
83
83
  authority call-number chapter-number citation-label citation-number
84
84
  collection-title container-title DOI edition event event-place
85
- first-reference-note-number genre ISBN issue jurisdiction keyword locator
85
+ first-reference-note-number genre ISBN issue jurisdiction keyword locator
86
86
  medium note number number-of-pages number-of-volumes original-publisher
87
87
  original-publisher-place original-title page page-first publisher
88
88
  publisher-place references section status title URL version volume
@@ -90,7 +90,7 @@ module BibTeX
90
90
  author editor translator recipient interviewer publisher composer
91
91
  original-publisher original-author container-author collection-editor
92
92
  }.map(&:intern).freeze
93
-
93
+
94
94
  CSL_TYPES = Hash.new {|h,k|k}.merge(Hash[*%w{
95
95
  booklet pamphlet
96
96
  conference paper-conference
@@ -136,33 +136,51 @@ module BibTeX
136
136
  article Article
137
137
  }.map(&:intern)]).freeze
138
138
 
139
-
139
+
140
140
  attr_reader :fields, :type
141
-
141
+
142
142
  def_delegators :@fields, :empty?
143
143
 
144
144
  # Creates a new instance. If a hash is given, the entry is populated accordingly.
145
145
  def initialize(attributes = {})
146
146
  @fields = {}
147
-
147
+
148
148
  self.type = attributes.delete(:type) if attributes.has_key?(:type)
149
149
  self.key = attributes.delete(:key) if attributes.has_key?(:key)
150
-
150
+
151
151
  add(attributes)
152
-
152
+
153
153
  yield self if block_given?
154
154
  end
155
155
 
156
- def initialize_copy (other)
156
+ def initialize_copy(other)
157
157
  @fields = {}
158
-
158
+
159
159
  self.type = other.type
160
160
  self.key = other.key
161
-
161
+
162
162
  add(other.fields)
163
163
  end
164
164
 
165
+ def merge(other, filter = field_names)
166
+ dup.merge!(other, filter)
167
+ end
168
+
169
+ def merge!(other, filter = field_names)
170
+ raise InvalidArgument, "failed to merge entries: type mismatch: #{type} #{other.type}" unless
171
+ type == other.type
165
172
 
173
+ other.each do |name, value|
174
+ if has_field?(name)
175
+ get(name).merge!(value) if filter.include?(name)
176
+ else
177
+ add name, value.dup
178
+ end
179
+ end
180
+
181
+ self
182
+ end
183
+
166
184
  # Generate Accessors for required fields (#52)
167
185
 
168
186
  REQUIRED_FIELDS.values.flatten.uniq.each do |name|
@@ -177,12 +195,12 @@ module BibTeX
177
195
  nil
178
196
  end
179
197
  end
180
-
198
+
181
199
  define_method("#{name}=") do |value|
182
200
  add name, value
183
201
  end
184
202
  end
185
-
203
+
186
204
  # call-seq:
187
205
  # entry.each { |key, value| block } -> entry
188
206
  # entry.each_pair { |key, value| block } -> entry
@@ -201,15 +219,15 @@ module BibTeX
201
219
  to_enum
202
220
  end
203
221
  end
204
-
222
+
205
223
  alias each_pair each
206
-
207
-
224
+
225
+
208
226
  # Returns the Entry's field name aliases.
209
227
  def aliases
210
228
  @aliases ||= FIELD_ALIASES.dup
211
229
  end
212
-
230
+
213
231
  # Sets the Entry's key. If the Entry is currently registered with a
214
232
  # Bibliography, re-registers the Entry with the new key; note that this
215
233
  # may change the key value if another Entry is already regsitered with
@@ -218,7 +236,7 @@ module BibTeX
218
236
  # Returns the new key.
219
237
  def key=(key)
220
238
  key = key.to_s
221
-
239
+
222
240
  if registered?
223
241
  bibliography.entries.delete(@key)
224
242
  key = register(key)
@@ -228,7 +246,7 @@ module BibTeX
228
246
  rescue => e
229
247
  raise BibTeXError, "failed to set key to #{key.inspect}: #{e.message}"
230
248
  end
231
-
249
+
232
250
  def key
233
251
  @key ||= default_key
234
252
  end
@@ -240,14 +258,14 @@ module BibTeX
240
258
  def type=(type)
241
259
  @type = type.to_sym
242
260
  end
243
-
261
+
244
262
  def has_type?(type)
245
263
  type.to_s.match(/^(?:entry|\*)$/i) || @type == type.to_sym || super
246
264
  end
247
-
265
+
248
266
  alias type? has_type?
249
-
250
-
267
+
268
+
251
269
  def has_field?(*names)
252
270
  names.flatten.any? do |name|
253
271
  name.respond_to?(:to_sym) ? fields.has_key?(name.to_sym) : false
@@ -261,7 +279,7 @@ module BibTeX
261
279
  !has_field(name) && has_parent? && parent.provides?(name)
262
280
  end
263
281
  end
264
-
282
+
265
283
  # Returns true if the Entry has a field (or alias) for any of the passed-in names.
266
284
  def provides?(*names)
267
285
  names.flatten.any? do |name|
@@ -272,20 +290,20 @@ module BibTeX
272
290
  end
273
291
  end
274
292
  end
275
-
293
+
276
294
  def provides_or_inherits?(*names)
277
295
  provides?(names) || inherits?(names)
278
296
  end
279
-
297
+
280
298
  # Returns the field value referenced by the passed-in name.
281
299
  # For example, this will return the 'title' value for 'booktitle' if a
282
300
  # corresponding alias is defined.
283
301
  def provide(name)
284
302
  return nil unless name.respond_to?(:to_sym)
285
- name = name.to_sym
303
+ name = name.to_sym
286
304
  fields[name] || fields[aliases[name]]
287
305
  end
288
-
306
+
289
307
  # If the Entry has a cross-reference, copies all referenced all inherited
290
308
  # values from the parent.
291
309
  #
@@ -294,10 +312,10 @@ module BibTeX
294
312
  inherited_fields.each do |name|
295
313
  fields[name] = parent.provide(name)
296
314
  end
297
-
315
+
298
316
  self
299
317
  end
300
-
318
+
301
319
  # Returns a sorted list of the Entry's field names. If a +filter+ is passed
302
320
  # as argument, returns all field names that are also defined by the filter.
303
321
  # If the +filter+ is empty, returns all field names.
@@ -306,15 +324,15 @@ module BibTeX
306
324
  # a cross-reference, the list will include all inherited fields.
307
325
  def field_names(filter = [], include_inherited = true)
308
326
  names = fields.keys
309
-
327
+
310
328
  if include_inherited && has_parent?
311
329
  names.concat(inherited_fields)
312
330
  end
313
-
331
+
314
332
  unless filter.empty?
315
333
  names = names & filter.map(&:to_sym)
316
334
  end
317
-
335
+
318
336
  names.sort!
319
337
  names
320
338
  end
@@ -322,21 +340,21 @@ module BibTeX
322
340
  # Returns a sorted list of all field names referenced by this Entry's cross-reference.
323
341
  def inherited_fields
324
342
  return [] unless has_parent?
325
-
343
+
326
344
  names = parent.fields.keys - fields.keys
327
345
  names.concat(parent.aliases.reject { |k,v| !parent.has_field?(v) }.keys)
328
346
  names.sort!
329
-
347
+
330
348
  names
331
349
  end
332
-
333
-
350
+
351
+
334
352
  def method_missing(name, *args, &block)
335
353
  case
336
354
  when fields.has_key?(name)
337
355
  fields[name]
338
356
  when name.to_s =~ /^(.+)=$/
339
- send(:add, $1.to_sym, args[0])
357
+ send(:add, $1.to_sym, args[0])
340
358
  when name =~ /^(?:convert|from)_([a-z]+)(!)?$/
341
359
  $2 ? convert!($1, &block) : convert($1, &block)
342
360
  when has_parent? && parent.provides?(name)
@@ -350,12 +368,12 @@ module BibTeX
350
368
  provides?(method.to_sym) || method.to_s.match(/=$/) ||
351
369
  method =~ /^(?:convert|from)_([a-z]+)(!)?$/ || (has_parent? && parent.respond_to?(method)) || super
352
370
  end
353
-
371
+
354
372
  # Returns a copy of the Entry with all the field names renamed.
355
373
  def rename(*arguments)
356
374
  dup.rename!(*arguments)
357
375
  end
358
-
376
+
359
377
  # Renames the given field names unless a field with the new name already
360
378
  # exists.
361
379
  def rename!(*arguments)
@@ -370,16 +388,16 @@ module BibTeX
370
388
 
371
389
  alias rename_fields rename
372
390
  alias rename_fields! rename!
373
-
391
+
374
392
  # Returns the value of the field with the given name. If the value is not
375
393
  # defined and the entry has cross-reference, returns the cross-referenced
376
394
  # value instead.
377
395
  def [](name)
378
396
  fields[name.to_sym] || parent && parent.provide(name)
379
397
  end
380
-
398
+
381
399
  alias get []
382
-
400
+
383
401
  def fetch(name, default = nil)
384
402
  get(name) || block_given? ? yield(name) : default
385
403
  end
@@ -395,11 +413,11 @@ module BibTeX
395
413
  define_method(contributor) do
396
414
  get(contributor)
397
415
  end
398
-
416
+
399
417
  alias_method "#{contributor}s", contributor
400
418
  end
401
-
402
-
419
+
420
+
403
421
  # call-seq:
404
422
  # add(:author, "Edgar A. Poe")
405
423
  # add(:author, "Edgar A. Poe", :title, "The Raven")
@@ -413,10 +431,10 @@ module BibTeX
413
431
  Hash[*arguments.flatten].each_pair do |name, value|
414
432
  fields[name.to_sym] = Value.create(value)
415
433
  end
416
-
434
+
417
435
  self
418
436
  end
419
-
437
+
420
438
  alias << add
421
439
 
422
440
  # Removes the field with a given name from the entry.
@@ -433,10 +451,31 @@ module BibTeX
433
451
  end
434
452
  end
435
453
 
436
- def generate_hash(filter = [])
437
- Digest::MD5.hexdigest(field_names(filter).map { |k| [k, fields[k]] }.flatten.join)
454
+ # Creates the entry's digest based on the passed-in filters.
455
+ #
456
+ # The digest contains the type and all key-value pairs based
457
+ # on the passed in filter.
458
+ #
459
+ # If a block is given, the computed digest will be passed to
460
+ # the block for post-processing (the entry itself will be passed
461
+ # as the second parameter).
462
+ #
463
+ # @see #field_names
464
+ #
465
+ # @param [<Symbol>] the field names to use
466
+ # @return [String] the digest string
467
+ def digest(filter = [])
468
+ names = field_names(filter)
469
+ digest = type.to_s
470
+
471
+ names.zip(values_at(*names)).each do |key, value|
472
+ digest << "|#{key}:#{value}"
473
+ end
474
+
475
+ digest = yield(digest, self) if block_given?
476
+ digest
438
477
  end
439
-
478
+
440
479
  def identifier
441
480
  case
442
481
  when provides?(:doi)
@@ -449,23 +488,23 @@ module BibTeX
449
488
  "urn:bibtex:#{key}"
450
489
  end
451
490
  end
452
-
491
+
453
492
  # Called when the element was added to a bibliography.
454
493
  def added_to_bibliography(bibliography)
455
494
  super
456
495
 
457
496
  @key = register(key)
458
-
497
+
459
498
  [:parse_names, :parse_months].each do |parser|
460
499
  send(parser) if bibliography.options[parser]
461
500
  end
462
-
501
+
463
502
  if bibliography.options.has_key?(:filter)
464
503
  [*bibliography.options[:filter]].each do |filter|
465
504
  convert!(filter)
466
505
  end
467
506
  end
468
-
507
+
469
508
  self
470
509
  end
471
510
 
@@ -480,7 +519,7 @@ module BibTeX
480
519
  def registered?
481
520
  !!(bibliography && bibliography.entries[key].equal?(self))
482
521
  end
483
-
522
+
484
523
  # Registers this Entry in the associated Bibliographies entries hash.
485
524
  # This method may change the Entry's key, if another entry is already
486
525
  # registered with the current key.
@@ -488,13 +527,13 @@ module BibTeX
488
527
  # Returns the key or nil if the Entry is not associated with a Bibliography.
489
528
  def register(key)
490
529
  return nil if bibliography.nil?
491
-
530
+
492
531
  k = key.dup
493
532
  k.succ! while bibliography.has_key?(k)
494
533
  bibliography.entries[k] = self
495
534
  k
496
535
  end
497
-
536
+
498
537
  def replace(*arguments)
499
538
  arguments = bibliography.q('@string') if arguments.empty?
500
539
  fields.values.each { |v| v.replace(*arguments) }
@@ -509,18 +548,18 @@ module BibTeX
509
548
  def month=(month)
510
549
  fields[:month] = MONTHS_FILTER[month]
511
550
  end
512
-
551
+
513
552
  def parse_month
514
553
  fields[:month] = MONTHS_FILTER[fields[:month]] if has_field?(:month)
515
554
  self
516
555
  end
517
-
556
+
518
557
  alias parse_months parse_month
519
-
558
+
520
559
  def date
521
560
  get(:date) || get(:year)
522
561
  end
523
-
562
+
524
563
  # Parses all name values of the entry. Tries to replace and join the
525
564
  # value prior to parsing.
526
565
  def parse_names
@@ -535,34 +574,34 @@ module BibTeX
535
574
 
536
575
  self
537
576
  end
538
-
577
+
539
578
  # Returns a list of all names (authors, editors, translators).
540
579
  def names
541
580
  NAME_FIELDS.map { |k| has_field?(k) ? @fields[k].tokens : nil }.flatten.compact
542
581
  end
543
-
544
-
582
+
583
+
545
584
  # Returns true if the Entry has a valid cross-reference in the Bibliography.
546
585
  def has_parent?
547
586
  !parent.nil?
548
587
  end
549
588
 
550
- alias has_cross_reference? has_parent?
589
+ alias has_cross_reference? has_parent?
551
590
 
552
591
  # Returns true if the Entry cross-references an Entry which is not
553
592
  # registered in the current Bibliography.
554
593
  def parent_missing?
555
594
  has_field?(:crossref) && !has_parent?
556
595
  end
557
-
596
+
558
597
  alias cross_reference_missing? parent_missing?
559
-
598
+
560
599
  # Returns the cross-referenced Entry from the Bibliography or nil if this
561
600
  # Entry does define a cross-reference.
562
601
  def parent
563
602
  bibliography && bibliography[fields[:crossref]]
564
603
  end
565
-
604
+
566
605
  alias cross_reference parent
567
606
 
568
607
 
@@ -571,9 +610,9 @@ module BibTeX
571
610
  def has_children?
572
611
  !children.empty?
573
612
  end
574
-
613
+
575
614
  alias cross_referenced? has_children?
576
-
615
+
577
616
  # Returns a list of all entries in the Bibliography containing a
578
617
  # cross-reference to this entry or [] if there are no references to this
579
618
  # entry.
@@ -582,11 +621,11 @@ module BibTeX
582
621
  end
583
622
 
584
623
  alias cross_referenced_by children
585
-
624
+
586
625
  def container_title
587
626
  get(:booktitle) || get(:journal) || get(:container)
588
627
  end
589
-
628
+
590
629
  def pages_from
591
630
  fetch(:pages, '').split(/\D+/)[0]
592
631
  end
@@ -594,13 +633,19 @@ module BibTeX
594
633
  def pages_to
595
634
  fetch(:pages, '').split(/\D+/)[-1]
596
635
  end
597
-
636
+
598
637
  # Returns true if this entry is published inside a book, collection or journal
599
638
  def contained?
600
639
  has_field?(:booktitle, :container, :journal)
601
640
  end
602
-
603
-
641
+
642
+ # Returns an array containing the values associated with the given keys.
643
+ def values_at(*arguments)
644
+ arguments.map do |key|
645
+ get key
646
+ end
647
+ end
648
+
604
649
  # Returns a duplicate entry with all values converted using the filter.
605
650
  # If an optional block is given, only those values will be converted where
606
651
  # the block returns true (the block will be called with each key-value pair).
@@ -609,18 +654,18 @@ module BibTeX
609
654
  def convert(filter)
610
655
  block_given? ? dup.convert!(filter, &Proc.new) : dup.convert!(filter)
611
656
  end
612
-
657
+
613
658
  # In-place variant of @see #convert
614
659
  def convert!(filter)
615
660
  fields.each_pair { |k,v| !block_given? || yield(k,v) ? v.convert!(filter) : v }
616
661
  self
617
662
  end
618
-
663
+
619
664
  def <=>(other)
620
665
  type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s
621
666
  end
622
-
623
-
667
+
668
+
624
669
  # Returns a string of all the entry's fields.
625
670
  def content(options = {})
626
671
  fields.map { |k,v| "#{k} = #{ fields[k].to_s(options) }" }.join(",\n")
@@ -631,7 +676,7 @@ module BibTeX
631
676
  options[:quotes] ||= %w({ })
632
677
  ["@#{type}{#{key},", content(options).gsub(/^/,' '), "}\n"].join("\n")
633
678
  end
634
-
679
+
635
680
  def to_hash(options = {})
636
681
  options[:quotes] ||= %w({ })
637
682
  hash = { :key => key, :type => type }
@@ -641,32 +686,32 @@ module BibTeX
641
686
 
642
687
  def to_citeproc(options = {})
643
688
  options[:quotes] ||= []
644
-
689
+
645
690
  parse_names
646
691
  parse_month
647
-
692
+
648
693
  hash = { 'id' => key.to_s, 'type' => CSL_TYPES[type].to_s }
649
-
694
+
650
695
  each_pair do |k,v|
651
696
  hash[CSL_FILTER[k].to_s] = v.to_citeproc(options) unless DATE_FIELDS.include?(k)
652
697
  end
653
-
698
+
654
699
  hash['issued'] = citeproc_date
655
700
  hash
656
701
  end
657
-
702
+
658
703
  def issued
659
704
  m = MONTHS.find_index(fields[:month].to_s.intern) unless !has_field?(:month)
660
705
  m = m + 1 unless m.nil?
661
-
706
+
662
707
  Hash['date-parts', [[fields[:year],m].compact.map(&:to_i)]]
663
708
  end
664
-
709
+
665
710
  alias citeproc_date issued
666
-
711
+
667
712
  def to_xml(options = {})
668
713
  require 'rexml/document'
669
-
714
+
670
715
  xml = REXML::Element.new('bibtex:entry')
671
716
  xml.attributes['id'] = key
672
717
 
@@ -674,54 +719,54 @@ module BibTeX
674
719
 
675
720
  fields.each do |key, value|
676
721
  field = REXML::Element.new("bibtex:#{key}")
677
-
722
+
678
723
  if options[:extended] && value.name?
679
724
  value.each { |n| entry.add_element(n.to_xml) }
680
725
  else
681
726
  field.text = value.to_s(options)
682
727
  end
683
-
728
+
684
729
  entry.add_element(field)
685
730
  end
686
731
 
687
732
  xml.add_element(entry)
688
733
  xml
689
734
  end
690
-
735
+
691
736
  # Returns a RDF::Graph representation of the entry using the BIBO ontology.
692
737
  # TODO: improve level of detail captured by export
693
738
  def to_rdf(options = {})
694
739
  require 'rdf'
695
-
740
+
696
741
  bibo = RDF::Vocabulary.new('http://purl.org/ontology/bibo/')
697
-
742
+
698
743
  graph = RDF::Graph.new
699
744
  entry = RDF::URI.new(identifier)
700
745
 
701
746
  graph << [entry, RDF.type, bibo[BIBO_TYPES[type]]]
702
-
703
- [:title, :language].each do |key|
747
+
748
+ [:title, :language].each do |key|
704
749
  graph << [entry, RDF::DC[key], get(key).to_s] if field?(key)
705
750
  end
706
751
 
707
752
  graph << [entry, RDF::DC.date, get(:year).to_s] if field?(:year)
708
-
753
+
709
754
  if field?(:publisher)
710
755
  address = RDF::Vocabulary.new('http://schemas.talis.com/2005/address/schema#')
711
756
  pub = RDF::Node.new
712
757
 
713
758
  graph << [pub, RDF.type, RDF::FOAF[:Organization]]
714
759
  graph << [pub, RDF::FOAF.name, get(:publisher)]
715
-
760
+
716
761
  graph << [pub, address[:localityName], get(:address)] if field?(:address)
717
-
762
+
718
763
  graph << [entry, RDF::DC.published, pub]
719
764
  end
720
765
 
721
- [:doi, :edition, :volume].each do |key|
766
+ [:doi, :edition, :volume].each do |key|
722
767
  graph << [entry, bibo[key], get(key).to_s] if field?(key)
723
768
  end
724
-
769
+
725
770
  if has_field?(:pages)
726
771
  if get(:pages).to_s =~ /^\s*(\d+)\s*-+\s*(\d+)\s*$/
727
772
  graph << [entry, bibo[:pageStart], $1]
@@ -736,13 +781,13 @@ module BibTeX
736
781
 
737
782
  graph << [seq, RDF.type, RDF[:Seq]]
738
783
  graph << [entry, bibo[:authorList], seq]
739
-
784
+
740
785
  authors.each do |author|
741
786
  a = RDF::Node.new
742
-
787
+
743
788
  graph << [a, RDF.type, RDF::FOAF[:Person]]
744
-
745
- if author.is_a?(Name)
789
+
790
+ if author.is_a?(Name)
746
791
  [:given, :family, :prefix, :suffix].each do |part|
747
792
  graph << [a, bibo["#{part}Name"], author.send(part).to_s]
748
793
  end
@@ -778,30 +823,30 @@ module BibTeX
778
823
  graph << [seq, RDF.li, e]
779
824
  end
780
825
  end
781
-
826
+
782
827
  graph
783
828
  rescue LoadError
784
829
  BibTeX.log.error "Please gem install rdf for RDF support."
785
830
  end
786
-
831
+
787
832
  alias to_bibo to_rdf
788
-
789
-
833
+
834
+
790
835
 
791
836
 
792
837
  private
793
-
838
+
794
839
  # Returns a default key for this entry.
795
840
  def default_key
796
841
  k = names[0]
797
842
  k = k.respond_to?(:family) ? k.family : k.to_s
798
843
  k = k[/[A-Za-z]+/] || 'unknown'
799
844
  k << (has_field?(:year) ? year : '-')
800
- k << 'a'
845
+ k << 'a'
801
846
  k.downcase!
802
847
  k
803
848
  end
804
-
805
-
849
+
850
+
806
851
  end
807
852
  end