bibtex-ruby 2.0.7 → 2.0.8

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/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
1
  source :rubygems
2
2
  gemspec
3
3
 
4
+ # RDF Export
5
+ gem 'rdf', '~>0.3'
6
+
4
7
  group :debug do
5
8
  gem 'debugger', :platforms => [:mri_19]
6
9
  gem 'ruby-debug', :platforms => [:mri_18]
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bibtex-ruby (2.0.6)
4
+ bibtex-ruby (2.0.8)
5
5
  latex-decode (>= 0.0.6)
6
6
  multi_json (~> 1.3)
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
+ addressable (2.2.7)
11
12
  autowatchr (0.1.5)
12
13
  watchr
13
14
  builder (3.0.0)
@@ -39,7 +40,7 @@ GEM
39
40
  linecache (0.46)
40
41
  rbx-require-relative (> 0.0.4)
41
42
  minitest (2.11.3)
42
- multi_json (1.3.2)
43
+ multi_json (1.3.4)
43
44
  mynyml-redgreen (0.7.1)
44
45
  term-ansicolor (>= 1.0.4)
45
46
  racc (1.4.8)
@@ -52,6 +53,8 @@ GEM
52
53
  columnize
53
54
  rbx-linecache (~> 1.3)
54
55
  rbx-require-relative (>= 0.0.4)
56
+ rdf (0.3.5.2)
57
+ addressable (>= 2.2.6)
55
58
  rdoc (3.12)
56
59
  json (~> 1.4)
57
60
  ruby-debug (0.10.4)
@@ -79,6 +82,7 @@ DEPENDENCIES
79
82
  racc (~> 1.4)
80
83
  rake (~> 0.9)
81
84
  rbx-trepanning
85
+ rdf (~> 0.3)
82
86
  rdoc (~> 3.9)
83
87
  ruby-debug
84
88
  ruby-prof (~> 0.10)
@@ -1,3 +1,9 @@
1
+ 2.0.8 / 2012-05-11
2
+ ==================
3
+
4
+ * Added extend_initials feature for names
5
+ * Added experimental RDF export (using BIBO ontology)
6
+
1
7
  2.0.7 / 2012-04-30
2
8
  ==================
3
9
 
data/README.md CHANGED
@@ -35,7 +35,7 @@ Select a BibTeX entry and access individual fields:
35
35
  b[:pickaxe].author.length
36
36
  #=> 3
37
37
  b[:pickaxe].author.to_s
38
- #=> "Thomas, Dave and Fowler, Chad and Hunt, Andy"
38
+ #=> "Thomas, D. and Fowler, Chad and Hunt, Andy"
39
39
  b[:pickaxe].author[2].first
40
40
  #=> "Andy"
41
41
 
@@ -48,6 +48,12 @@ Query a bibliography:
48
48
  b['@book[year=2009]'].length
49
49
  #=> 1 - the number of books published in 2009
50
50
 
51
+ Extend first name initials throughout your bibliography:
52
+
53
+ b.extend_initials ['Dave', 'Thomas']
54
+ b[:pickaxe].author.to_s
55
+ #=> "Thomas, Dave and Fowler, Chad and Hunt, Andy"
56
+
51
57
  Render your bibliography in one of
52
58
  [many different citation styles](https://github.com/citation-style-language/styles)
53
59
  (requires the **citeproc-ruby** gem):
data/Rakefile CHANGED
@@ -80,6 +80,8 @@ end
80
80
 
81
81
  desc 'Pushes the gem file to rubygems.org'
82
82
  task :release => ['build'] do
83
+ system %Q{git tag "#{BibTeX::Version::STRING}"}
84
+ system "git push --tags"
83
85
  system "gem push bibtex-ruby-#{BibTeX::Version::STRING}.gem"
84
86
  end
85
87
 
@@ -89,8 +89,9 @@ module BibTeX
89
89
  :comment, :meta_content
90
90
 
91
91
  def_delegators :@data, :length, :size, :empty?
92
- def_delegators :@entries, :key?, :has_key?
92
+ def_delegators :@entries, :key?, :has_key?, :values_at
93
93
 
94
+ alias entries_at values_at
94
95
 
95
96
  # Creates a new bibliography.
96
97
  def initialize(options = {})
@@ -285,6 +286,17 @@ module BibTeX
285
286
  self
286
287
  end
287
288
 
289
+ # call-seq:
290
+ # b.extend_initials(['Edgar Allen', 'Poe'], ['Nathaniel', 'Hawthorne'])
291
+ # #=> Extends the initials in names like 'E.A. Poe' or 'Hawethorne, N.'
292
+ # in the bibliography.
293
+ def extend_initials(*arguments)
294
+ arguments.each do |with_first, for_last|
295
+ names.each do |name|
296
+ name.extend_initials(with_first, for_last)
297
+ end
298
+ end
299
+ end
288
300
 
289
301
  def sort(*arguments, &block)
290
302
  data.sort(*arguments, &block)
@@ -341,6 +353,22 @@ module BibTeX
341
353
  xml
342
354
  end
343
355
 
356
+ # Returns an RDF::Graph representation of the bibliography. The graph
357
+ # can be serialized using any of the RDF serializer plugins.
358
+ def to_rdf(options = {})
359
+ require 'rdf'
360
+
361
+ graph = RDF::Graph.new
362
+
363
+ q('@entry').each do |entry|
364
+ graph << entry.to_rdf(options)
365
+ end
366
+
367
+ graph
368
+ rescue LoadError
369
+ BibTeX.log.error "Please gem install rdf for RDF support."
370
+ end
371
+
344
372
  # call-seq:
345
373
  # bib.query() #=> returns all elements
346
374
  # bib.query('@book') #=> returns all books
@@ -107,6 +107,35 @@ module BibTeX
107
107
  article article-journal
108
108
  }.map(&:intern)]).freeze
109
109
 
110
+ BIBO_FIELDS = Hash[*%w{
111
+ pages pages
112
+ number issue
113
+ isbn isbn
114
+ issn issn
115
+ doi doi
116
+ edition edition
117
+ abstract abstract
118
+ volume volume
119
+ }.map(&:intern)].freeze
120
+
121
+ BIBO_TYPES = Hash.new(:Document).merge(Hash[*%w{
122
+ booklet Book
123
+ book Book
124
+ conference Conference
125
+ inbook Article
126
+ incollection Article
127
+ inproceedings Article
128
+ manual Manual
129
+ mastersthesis Thesis
130
+ phdthesis Thesis
131
+ proceedings Proceedings
132
+ techreport Report
133
+ journal Journal
134
+ periodical Periodical
135
+ unpublished Manuscript
136
+ article Article
137
+ }.map(&:intern)]).freeze
138
+
110
139
 
111
140
  attr_reader :fields, :type
112
141
 
@@ -198,20 +227,33 @@ module BibTeX
198
227
  alias type? has_type?
199
228
 
200
229
 
201
- def has_field?(name)
202
- name.respond_to?(:to_sym) ? fields.has_key?(name.to_sym) : false
230
+ def has_field?(*names)
231
+ names.flatten.any? do |name|
232
+ name.respond_to?(:to_sym) ? fields.has_key?(name.to_sym) : false
233
+ end
203
234
  end
204
235
 
205
236
  alias field? has_field?
206
237
 
207
- def inherits?(name)
208
- !has_field(name) && has_parent? && parent.provides?(name)
238
+ def inherits?(*names)
239
+ names.flatten.any? do |name|
240
+ !has_field(name) && has_parent? && parent.provides?(name)
241
+ end
209
242
  end
210
243
 
211
- # Returns true if the Entry has a field (or alias) for the passed-in name.
212
- def provides?(name)
213
- return nil unless name.respond_to?(:to_sym)
214
- has_field?(name) || has_field?(aliases[name.to_sym])
244
+ # Returns true if the Entry has a field (or alias) for any of the passed-in names.
245
+ def provides?(*names)
246
+ names.flatten.any? do |name|
247
+ if name.respond_to?(:to_sym)
248
+ has_field?(name) || has_field?(aliases[name.to_sym])
249
+ else
250
+ false
251
+ end
252
+ end
253
+ end
254
+
255
+ def provides_or_inherits?(*names)
256
+ provides?(names) || inherits?(names)
215
257
  end
216
258
 
217
259
  # Returns the field value referenced by the passed-in name.
@@ -327,6 +369,16 @@ module BibTeX
327
369
  add(name.to_sym, value)
328
370
  end
329
371
 
372
+ # Author, Editor and Translator readers
373
+ NAME_FIELDS.each do |contributor|
374
+ define_method(contributor) do
375
+ get(contributor)
376
+ end
377
+
378
+ alias_method "#{contributor}s", contributor
379
+ end
380
+
381
+
330
382
  # Adds a new field (name-value pair) or multiple fields to the entry.
331
383
  # Returns the entry for chainability.
332
384
  #
@@ -364,6 +416,19 @@ module BibTeX
364
416
  Digest::MD5.hexdigest(field_names(filter).map { |k| [k, fields[k]] }.flatten.join)
365
417
  end
366
418
 
419
+ def identifier
420
+ case
421
+ when provides?(:doi)
422
+ "info:doi/#{get(:doi)}"
423
+ when provides?(:isbn)
424
+ "urn:isbn:#{get(:isbn)}"
425
+ when provides?(:issn)
426
+ "urn:issn:#{get(:issn)}"
427
+ else
428
+ "urn:bibtex:#{key}"
429
+ end
430
+ end
431
+
367
432
  # Called when the element was added to a bibliography.
368
433
  def added_to_bibliography(bibliography)
369
434
  super
@@ -431,6 +496,9 @@ module BibTeX
431
496
 
432
497
  alias parse_months parse_month
433
498
 
499
+ def date
500
+ get(:date) || get(:year)
501
+ end
434
502
 
435
503
  # Parses all name values of the entry. Tries to replace and join the
436
504
  # value prior to parsing.
@@ -494,6 +562,43 @@ module BibTeX
494
562
 
495
563
  alias cross_referenced_by children
496
564
 
565
+ def container_title
566
+ get(:booktitle) || get(:journal) || get(:container)
567
+ end
568
+
569
+ def pages_from
570
+ fetch(:pages, '').split(/\D+/)[0]
571
+ end
572
+
573
+ def pages_to
574
+ fetch(:pages, '').split(/\D+/)[-1]
575
+ end
576
+
577
+ # Returns true if this entry is published inside a book, collection or journal
578
+ def contained?
579
+ has_field?(:booktitle, :container, :journal)
580
+ end
581
+
582
+
583
+ # Returns a duplicate entry with all values converted using the filter.
584
+ # If an optional block is given, only those values will be converted where
585
+ # the block returns true (the block will be called with each key-value pair).
586
+ #
587
+ # @see #convert!
588
+ def convert(filter)
589
+ block_given? ? dup.convert!(filter, &Proc.new) : dup.convert!(filter)
590
+ end
591
+
592
+ # In-place variant of @see #convert
593
+ def convert!(filter)
594
+ fields.each_pair { |k,v| !block_given? || yield(k,v) ? v.convert!(filter) : v }
595
+ self
596
+ end
597
+
598
+ def <=>(other)
599
+ type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s
600
+ end
601
+
497
602
 
498
603
  # Returns a string of all the entry's fields.
499
604
  def content(options = {})
@@ -562,24 +667,106 @@ module BibTeX
562
667
  xml
563
668
  end
564
669
 
565
- # Returns a duplicate entry with all values converted using the filter.
566
- # If an optional block is given, only those values will be converted where
567
- # the block returns true (the block will be called with each key-value pair).
568
- #
569
- # @see #convert!
570
- def convert(filter)
571
- block_given? ? dup.convert!(filter, &Proc.new) : dup.convert!(filter)
670
+ # Returns a RDF::Graph representation of the entry using the BIBO ontology.
671
+ # TODO: improve level of detail captured by export
672
+ def to_rdf(options = {})
673
+ require 'rdf'
674
+
675
+ bibo = RDF::Vocabulary.new('http://purl.org/ontology/bibo/')
676
+
677
+ graph = RDF::Graph.new
678
+ entry = RDF::URI.new(identifier)
679
+
680
+ graph << [entry, RDF.type, bibo[BIBO_TYPES[type]]]
681
+
682
+ [:title, :language].each do |key|
683
+ graph << [entry, RDF::DC[key], get(key).to_s] if field?(key)
684
+ end
685
+
686
+ graph << [entry, RDF::DC.date, get(:year).to_s] if field?(:year)
687
+
688
+ if field?(:publisher)
689
+ address = RDF::Vocabulary.new('http://schemas.talis.com/2005/address/schema#')
690
+ pub = RDF::Node.new
691
+
692
+ graph << [pub, RDF.type, RDF::FOAF[:Organization]]
693
+ graph << [pub, RDF::FOAF.name, get(:publisher)]
694
+
695
+ graph << [pub, address[:localityName], get(:address)] if field?(:address)
696
+
697
+ graph << [entry, RDF::DC.published, pub]
698
+ end
699
+
700
+ [:doi, :edition, :volume].each do |key|
701
+ graph << [entry, bibo[key], get(key).to_s] if field?(key)
702
+ end
703
+
704
+ if has_field?(:pages)
705
+ if get(:pages).to_s =~ /^\s*(\d+)\s*-+\s*(\d+)\s*$/
706
+ graph << [entry, bibo[:pageStart], $1]
707
+ graph << [entry, bibo[:pageEnd], $2]
708
+ else
709
+ graph << [entry, bibo[:pages], get(:pages).to_s]
710
+ end
711
+ end
712
+
713
+ if has_field?(:author)
714
+ seq = RDF::Node.new
715
+
716
+ graph << [seq, RDF.type, RDF[:Seq]]
717
+ graph << [entry, bibo[:authorList], seq]
718
+
719
+ authors.each do |author|
720
+ a = RDF::Node.new
721
+
722
+ graph << [a, RDF.type, RDF::FOAF[:Person]]
723
+
724
+ if author.is_a?(Name)
725
+ [:given, :family, :prefix, :suffix].each do |part|
726
+ graph << [a, bibo["#{part}Name"], author.send(part).to_s]
727
+ end
728
+ else
729
+ graph << [a, RDF::FOAF.name, author.to_s]
730
+ end
731
+
732
+ graph << [entry, RDF::DC.creator, a]
733
+ graph << [seq, RDF.li, a]
734
+ end
735
+ end
736
+
737
+ if has_field?(:editor)
738
+ seq = RDF::Node.new
739
+
740
+ graph << [seq, RDF.type, RDF[:Seq]]
741
+ graph << [entry, bibo[:editorList], seq]
742
+
743
+ editors.each do |editor|
744
+ e = RDF::Node.new
745
+
746
+ graph << [e, RDF.type, RDF::FOAF[:Person]]
747
+
748
+ if editor.is_a?(Name)
749
+ [:given, :family, :prefix, :suffix].each do |part|
750
+ graph << [e, bibo["#{part}Name"], editor.send(part).to_s]
751
+ end
752
+ else
753
+ graph << [e, RDF::FOAF.name, editor.to_s]
754
+ end
755
+
756
+ graph << [entry, bibo.editor, a]
757
+ graph << [seq, RDF.li, e]
758
+ end
759
+ end
760
+
761
+ graph
762
+ rescue LoadError
763
+ BibTeX.log.error "Please gem install rdf for RDF support."
572
764
  end
573
765
 
574
- # In-place variant of @see #convert
575
- def convert!(filter)
576
- fields.each_pair { |k,v| !block_given? || yield(k,v) ? v.convert!(filter) : v }
577
- self
578
- end
766
+ alias to_bibo to_rdf
579
767
 
580
- def <=>(other)
581
- type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s
582
- end
768
+
769
+
583
770
 
584
771
  private
585
772
 
@@ -594,5 +781,6 @@ module BibTeX
594
781
  k
595
782
  end
596
783
 
784
+
597
785
  end
598
786
  end
@@ -20,6 +20,7 @@ require 'forwardable'
20
20
 
21
21
  module BibTeX
22
22
 
23
+ # A BibTeX Names value is an ordered list of name values.
23
24
  class Names < Value
24
25
  include Enumerable
25
26
 
@@ -27,9 +28,9 @@ module BibTeX
27
28
 
28
29
  def self.parse(string)
29
30
  new(NameParser.new.parse(string))
30
- rescue => e
31
- BibTeX.log.info(e.message)
32
- nil
31
+ rescue => e
32
+ BibTeX.log.info(e.message)
33
+ nil
33
34
  end
34
35
 
35
36
  def initialize(*arguments)
@@ -39,12 +40,16 @@ module BibTeX
39
40
  end
40
41
  end
41
42
 
42
- def replace(*arguments); self; end
43
+ def replace(*arguments)
44
+ self
45
+ end
43
46
 
44
- def join; self; end
47
+ def join
48
+ self
49
+ end
45
50
 
46
- def value
47
- @tokens.join(' and ')
51
+ def value(options = {})
52
+ @tokens.map { |n| n.to_s(options) }.join(' and ')
48
53
  end
49
54
 
50
55
  def to_s(options = {})
@@ -53,14 +58,24 @@ module BibTeX
53
58
  [q[0], value, q[-1]].compact.join
54
59
  end
55
60
 
56
- def name?; true; end
57
- def numeric?; false; end
58
- def atomic?; true; end
61
+ def name?
62
+ true
63
+ end
64
+
65
+ def numeric?
66
+ false
67
+ end
59
68
 
60
- alias :names? :name?
61
- alias :symbol? :numeric?
69
+ def atomic?
70
+ true
71
+ end
62
72
 
63
- def to_name; self; end
73
+ alias names? name?
74
+ alias symbol? numeric?
75
+
76
+ def to_name
77
+ self
78
+ end
64
79
 
65
80
  def to_citeproc(options = {})
66
81
  map { |n| n.to_citeproc(options) }
@@ -82,13 +97,14 @@ module BibTeX
82
97
  self
83
98
  end
84
99
 
85
- alias :<< :add
86
- alias :push :add
100
+ alias << add
101
+ alias push add
87
102
 
88
- # Converts all string values according to the given filter.
89
- def convert! (filter)
90
- tokens.each { |t| t.convert!(filter) }
91
- self
103
+ [:convert!, :rename_if, :rename_unless, :extend_initials].each do |method_id|
104
+ define_method(method_id) do |*arguments|
105
+ tokens.each { |t| t.send(method_id, *arguments) }
106
+ self
107
+ end
92
108
  end
93
109
 
94
110
  def <=>(other)
@@ -97,20 +113,21 @@ module BibTeX
97
113
 
98
114
  end
99
115
 
116
+ # A Name comprises individual name parts (first, last, prefix and suffix),
117
+ # but behaves almost like an atomic string value.
100
118
  class Name < Struct.new(:first, :last, :prefix, :suffix)
101
119
  extend Forwardable
102
-
103
120
  include Comparable
104
-
121
+
105
122
  BibTeXML = {
106
- :first => :first,
107
- :last => :last,
108
- :prefix => :prelast,
109
- :suffix => :lineage
110
- }.freeze
111
-
123
+ :first => :first,
124
+ :last => :last,
125
+ :prefix => :prelast,
126
+ :suffix => :lineage
127
+ }.freeze
128
+
112
129
  def_delegators :to_s, :=~, :===,
113
- *String.instance_methods(false).reject { |m| m =~ /^\W|to_s|replace|each|first|last|!$/ }
130
+ *String.instance_methods(false).reject { |m| m =~ /^\W|to_s|replace|each|first|last|!$/ }
114
131
 
115
132
  class << self
116
133
  def parse(string)
@@ -125,53 +142,114 @@ module BibTeX
125
142
  end
126
143
 
127
144
  def initialize(attributes = {})
128
- attributes.each do |key,value|
129
- send("#{key}=", value) if respond_to?(key)
130
- end
145
+ set(attributes)
131
146
  end
132
147
 
133
148
  def initalize_copy(other)
134
- each_pair { |k,v| self[k] = v }
149
+ each_pair { |k,v| self[k] = v.dup }
150
+ end
151
+
152
+ # Set the name tokens to the values defined in the passed-in hash.
153
+ def set(attributes = {})
154
+ attributes.each do |key, value|
155
+ send("#{key}=", value) if respond_to?(key)
156
+ end
157
+
158
+ self
135
159
  end
136
160
 
137
161
  def blank?
138
162
  to_a.compact.empty?
139
163
  end
164
+
165
+ # Returns the first name (or the passed-in string) as initials.
166
+ def initials(token = first)
167
+ token.to_s.gsub(/([[:upper:]])[[:lower:]]+\s*/, '\1.')
168
+ end
140
169
 
141
- def display_order
142
- [prefix, last, first, suffix].compact.join(' ')
170
+ # Returns true if the first name consists solely of initials.
171
+ def initials?
172
+ !(first.nil? || first.empty? || first.to_s =~ /[[:alpha:]]{2,}[^\.]/)
173
+ end
174
+
175
+ # Sets the name's first name to the passed-in name if the last name equals
176
+ # for_last and the current first name has the same initials as with_first.
177
+ def extend_initials(with_first, for_last)
178
+ rename_if :first => with_first do |name|
179
+ name.last == for_last && name.initials.gsub(/\s+/, '') == initials(with_first).gsub(/\s+/, '')
180
+ end
181
+ end
182
+
183
+ # Renames the tokens according to the passed-in attributes if all of the
184
+ # conditions match or if the given block returns true.
185
+ def rename_if(attributes, conditions = {})
186
+ if block_given?
187
+ set(attributes) if yield self
188
+ else
189
+ set(attributes) if conditions.all? do |key, value|
190
+ respond_to?(key) && send(key) == value
191
+ end
192
+ end
193
+
194
+ self
195
+ end
196
+
197
+ def rename_unless(attributes, conditions = {})
198
+ if block_given?
199
+ set(attributes) unless yield self
200
+ else
201
+ set(attributes) unless conditions.all? do |key, value|
202
+ respond_to?(key) && send(key) == value
203
+ end
204
+ end
205
+
206
+ self
207
+ end
208
+
209
+ # call-seq:
210
+ # name.display_order #=> 'Edgar Allen Poe'
211
+ # name.display_order :initials => true #=> 'E.A. Poe'
212
+ #
213
+ # Returns the name as a string in display order.
214
+ def display_order(options = {})
215
+ [options[:initials] ? initials : first, prefix, last, suffix].compact.join(' ')
143
216
  end
144
217
 
145
218
  alias display display_order
146
219
 
147
- def sort_order
148
- [[prefix,last].compact.join(' '), suffix, first].compact.join(', ')
220
+ # call-seq:
221
+ # name.sort_order #=> 'Poe, Edgar Allen'
222
+ # name.sort_order :initials => true #=> 'Poe, E.A.'
223
+ #
224
+ # Returns the name as a string in sort order.
225
+ def sort_order(options = {})
226
+ [[prefix, last].compact.join(' '), suffix, options[:initials] ? initials : first].compact.join(', ')
149
227
  end
150
228
 
151
229
  alias to_s sort_order
152
-
230
+
153
231
  def <=>(other)
154
- other.is_a?(Name) ? [last, prefix, first, suffix].compact.join(' ') <=> [other.last, other.prefix, other.first, other.suffix].compact.join(' ') : super
232
+ other.is_a?(Name) ? sort_order <=> other.sort_order : super
155
233
  end
156
234
 
157
235
  def to_hash
158
236
  Hash[each_pair.to_a]
159
237
  end
160
238
 
161
- def to_xml
162
- require 'rexml/document'
163
- xml = REXML::Element.new('bibtex:person')
239
+ def to_xml
240
+ require 'rexml/document'
241
+ xml = REXML::Element.new('bibtex:person')
164
242
 
165
- each_pair do |part, text|
166
- unless text.nil?
167
- element = REXML::Element.new("bibtex:#{BibTeXML[part]}")
168
- element.text = text
169
- xml.add_element(element)
170
- end
171
- end
172
-
173
- xml
174
- end
243
+ each_pair do |part, text|
244
+ unless text.nil?
245
+ element = REXML::Element.new("bibtex:#{BibTeXML[part]}")
246
+ element.text = text
247
+ xml.add_element(element)
248
+ end
249
+ end
250
+
251
+ xml
252
+ end
175
253
 
176
254
  [:strip!, :upcase!, :downcase!, :sub!, :gsub!, :chop!, :chomp!, :rstrip!].each do |method_id|
177
255
  define_method(method_id) do |*arguments, &block|
@@ -182,20 +260,20 @@ module BibTeX
182
260
  end
183
261
  end
184
262
 
185
- def convert(filter)
186
- dup.convert!(filter)
187
- end
188
-
189
- def convert!(filter)
190
- if f = Filters.resolve(filter)
191
- each_pair { |k,v| self[k] = f.apply(v) unless v.nil? }
192
- else
193
- raise ArgumentError, "Failed to load filter #{filter.inspect}"
194
- end
263
+ def convert(filter)
264
+ dup.convert!(filter)
265
+ end
266
+
267
+ def convert!(filter)
268
+ if f = Filters.resolve(filter)
269
+ each_pair { |k,v| self[k] = f.apply(v) unless v.nil? }
270
+ else
271
+ raise ArgumentError, "Failed to load filter #{filter.inspect}"
272
+ end
195
273
 
196
- self
197
- end
198
-
274
+ self
275
+ end
276
+
199
277
  def to_citeproc(options = {})
200
278
  hash = {}
201
279
  hash['family'] = family unless family.nil?
@@ -213,6 +291,6 @@ module BibTeX
213
291
  alias jr= suffix=
214
292
  alias von prefix
215
293
  alias von= prefix=
216
-
294
+
217
295
  end
218
296
  end
@@ -18,6 +18,6 @@
18
18
 
19
19
  module BibTeX
20
20
  module Version
21
- STRING = '2.0.7'.freeze
21
+ STRING = '2.0.8'.freeze
22
22
  end
23
23
  end
@@ -71,6 +71,20 @@ module BibTeX
71
71
  END
72
72
  end
73
73
 
74
+ describe '#entries_at' do
75
+ it 'returns a list of all entries identified by the passed-in keys' do
76
+ assert_equal [@bib['segaran2007'], @bib['rails']], @bib.entries_at('segaran2007', :rails)
77
+ end
78
+ end
79
+
80
+ describe '#extend_initials' do
81
+ it 'extends the initials in matching names' do
82
+ @bib.names.map(&:to_s).wont_include 'Flanagan, Dave'
83
+ @bib.extend_initials(['Dave', 'Flanagan'])
84
+ @bib.names.map(&:to_s).must_include 'Flanagan, Dave'
85
+ end
86
+ end
87
+
74
88
  it 'supports access by index' do
75
89
  assert_equal 'ruby', @bib[1].keywords
76
90
  end
@@ -5,6 +5,10 @@ require 'helper'
5
5
  module BibTeX
6
6
  class NamesTest < MiniTest::Spec
7
7
 
8
+ before do
9
+ @poe = Name.new(:first => 'Edgar Allen', :last => 'Poe')
10
+ end
11
+
8
12
  describe 'string behaviour' do
9
13
  before do
10
14
  @name = Name.new(:first => 'Charles Louis Xavier Joseph', :prefix => 'de la', :last => 'Vallee Poussin', :suffix => 'Jr.')
@@ -18,7 +22,85 @@ module BibTeX
18
22
  it 'should implement gsub!' do
19
23
  assert_equal 'dX la VallXX PoussXn, Jr., CharlXs LouXs XavXXr JosXph', @name.gsub!(/[ei]/, 'X').to_s
20
24
  end
25
+ end
26
+
27
+ describe '#display_order' do
28
+ it 'returns the name as "first last"' do
29
+ @poe.display_order.must_be :==, 'Edgar Allen Poe'
30
+ end
31
+
32
+ it 'accepts the :initials option' do
33
+ @poe.display_order(:initials => true).must_be :==, 'E.A. Poe'
34
+ end
35
+ end
36
+
37
+ describe '#sort_order' do
38
+ it 'returns the name as "last, first"' do
39
+ @poe.sort_order.must_be :==, 'Poe, Edgar Allen'
40
+ end
41
+
42
+ it 'accepts the :initials option' do
43
+ @poe.sort_order(:initials => true).must_be :==, 'Poe, E.A.'
44
+ end
45
+ end
46
+
47
+ describe '#initials?' do
48
+ it 'returns true if the name contains a solely initials as a first name' do
49
+ @poe.initials?.must_equal false
50
+
51
+ @poe.first = 'Edgar A.'
52
+ @poe.initials?.must_equal false
53
+
54
+ @poe.first = 'E.A.'
55
+ @poe.initials?.must_equal true
56
+
57
+ @poe.first = ''
58
+ @poe.initials?.must_equal false
59
+
60
+ @poe.first = nil
61
+ @poe.initials?.must_equal false
62
+ end
63
+ end
64
+
65
+ describe '#rename_if' do
66
+ it 'renames the name to the given attributes if no condition is given' do
67
+ @poe.rename_if({ :first => 'E.A.' }).first.must_equal 'E.A.'
68
+ end
69
+
70
+ it 'renames the name to the given attributes if all conditions match' do
71
+ @poe.rename_if({ :first => 'E.A.' }, { :last => @poe.last }).first.must_equal 'E.A.'
72
+ @poe.rename_if({ :first => 'E.A.' }, { :last => @poe.last, :first => @poe.first }).first.must_equal 'E.A.'
73
+ end
74
+
75
+ it 'renames the name to the given attributes if the block returns true' do
76
+ @poe.rename_if({ :first => 'E.A.' }) {|n| true}.first.must_equal 'E.A.'
77
+ end
78
+
79
+ it 'does not rename the name to the given attributes if at least one condition does not match' do
80
+ @poe.rename_if({ :first => 'E.A.' }, { :last => 'foo' }).first.wont_equal 'E.A.'
81
+ @poe.rename_if({ :first => 'E.A.' }, { :last => 'foo', :first => @poe.first }).first.wont_equal 'E.A.'
82
+ @poe.rename_if({ :first => 'E.A.' }, { :last => @poe.last, :first => 'foo' }).first.wont_equal 'E.A.'
83
+ end
84
+
85
+ it 'does not rename the name to the given attributes if the block returns false' do
86
+ @poe.rename_if({ :first => 'E.A.' }) {|n| false}.first.wont_equal 'E.A.'
87
+ end
88
+ end
89
+
90
+ describe '#extend_initials' do
91
+ it 'extends the first name if the last name and initials match' do
92
+ Name.new(:first => 'E.A.', :last => 'Poe').extend_initials('Edgar Allen', 'Poe').first.must_equal 'Edgar Allen'
93
+ Name.new(:first => 'Edgar A.', :last => 'Poe').extend_initials('Edgar Allen', 'Poe').first.must_equal 'Edgar Allen'
94
+ Name.new(:first => 'E. A.', :last => 'Poe').extend_initials('Edgar Allen', 'Poe').first.must_equal 'Edgar Allen'
95
+ Name.new(:first => 'E. Allen', :last => 'Poe').extend_initials('Edgar Allen', 'Poe').first.must_equal 'Edgar Allen'
96
+ Name.new(:first => 'E.A.', :last => 'Poe').extend_initials('Edgar A.', 'Poe').first.must_equal 'Edgar A.'
97
+ end
21
98
 
99
+ it 'does not extend the first name if the last name or initials do not match' do
100
+ Name.new(:first => 'E.A.', :last => 'Poe').extend_initials('Edgar Allen', 'Poser').first.wont_equal 'Edgar Allen'
101
+ Name.new(:first => 'E.A.', :last => 'Poe').extend_initials('Edgar Ellen', 'Poe').first.wont_equal 'Edgar Ellen'
102
+ Name.new(:first => 'E.R.', :last => 'Poe').extend_initials('Edgar Allen', 'Poe').first.wont_equal 'Edgar Allen'
103
+ end
22
104
  end
23
105
 
24
106
  describe "conversions" do
@@ -39,8 +121,8 @@ module BibTeX
39
121
  Names.parse("S{\\o}ren Kirkegaard and Emmanuel L\\'evinas").convert(:latex).to_s.must_be :==, 'Kirkegaard, Søren and Lévinas, Emmanuel'
40
122
  end
41
123
  end
42
-
43
124
  end
44
125
 
45
126
  end
127
+
46
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bibtex-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.7
4
+ version: 2.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-30 00:00:00.000000000 Z
12
+ date: 2012-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: latex-decode
16
- requirement: &70149186709340 !ruby/object:Gem::Requirement
16
+ requirement: &70229986220740 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.0.6
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70149186709340
24
+ version_requirements: *70229986220740
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: multi_json
27
- requirement: &70149186708580 !ruby/object:Gem::Requirement
27
+ requirement: &70229986220220 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.3'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70149186708580
35
+ version_requirements: *70229986220220
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &70149186708040 !ruby/object:Gem::Requirement
38
+ requirement: &70229986219680 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0.9'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70149186708040
46
+ version_requirements: *70229986219680
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: racc
49
- requirement: &70149186707340 !ruby/object:Gem::Requirement
49
+ requirement: &70229986219200 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '1.4'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70149186707340
57
+ version_requirements: *70229986219200
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rdoc
60
- requirement: &70149186706200 !ruby/object:Gem::Requirement
60
+ requirement: &70229986218720 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '3.9'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70149186706200
68
+ version_requirements: *70229986218720
69
69
  description: ! "\t\tBibTeX-Ruby is the Rubyist's swiss-army-knife for all things BibTeX.
70
70
  It\n includes a parser for all common BibTeX objects (@string, @preamble,\n @comment
71
71
  and regular entries) and a sophisticated name parser that\n tokenizes correctly
@@ -180,12 +180,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
180
180
  - - ! '>='
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
+ segments:
184
+ - 0
185
+ hash: -4363834808819370688
183
186
  required_rubygems_version: !ruby/object:Gem::Requirement
184
187
  none: false
185
188
  requirements:
186
189
  - - ! '>='
187
190
  - !ruby/object:Gem::Version
188
191
  version: '0'
192
+ segments:
193
+ - 0
194
+ hash: -4363834808819370688
189
195
  requirements: []
190
196
  rubyforge_project:
191
197
  rubygems_version: 1.8.10