bibtex-ruby 2.0.1 → 2.0.2
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.
Potentially problematic release.
This version of bibtex-ruby might be problematic. Click here for more details.
- data/Gemfile.lock +2 -2
- data/History.txt +5 -0
- data/lib/bibtex.rb +12 -12
- data/lib/bibtex/bibliography.rb +98 -81
- data/lib/bibtex/elements.rb +191 -191
- data/lib/bibtex/entry.rb +470 -445
- data/lib/bibtex/lexer.rb +5 -5
- data/lib/bibtex/names.rb +2 -1
- data/lib/bibtex/value.rb +40 -43
- data/lib/bibtex/version.rb +1 -1
- data/test/bibtex/test_bibliography.rb +49 -49
- data/test/bibtex/test_entry.rb +214 -208
- data/test/bibtex/test_name_parser.rb +2 -2
- metadata +12 -12
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                bibtex-ruby (2.0. | 
| 4 | 
            +
                bibtex-ruby (2.0.1)
         | 
| 5 5 | 
             
                  latex-decode (>= 0.0.6)
         | 
| 6 6 | 
             
                  multi_json (~> 1.0)
         | 
| 7 7 |  | 
| @@ -27,7 +27,7 @@ GEM | |
| 27 27 | 
             
                gnuplot (2.3.6)
         | 
| 28 28 | 
             
                json (1.5.4)
         | 
| 29 29 | 
             
                json (1.5.4-java)
         | 
| 30 | 
            -
                latex-decode (0.0. | 
| 30 | 
            +
                latex-decode (0.0.9)
         | 
| 31 31 | 
             
                  unicode (~> 0.4)
         | 
| 32 32 | 
             
                linecache (0.46)
         | 
| 33 33 | 
             
                  rbx-require-relative (> 0.0.4)
         | 
    
        data/History.txt
    CHANGED
    
    
    
        data/lib/bibtex.rb
    CHANGED
    
    | @@ -16,22 +16,20 @@ | |
| 16 16 | 
             
            # along with this program.	If not, see <http://www.gnu.org/licenses/>.
         | 
| 17 17 | 
             
            #++
         | 
| 18 18 |  | 
| 19 | 
            -
            $:.unshift(File.dirname(__FILE__)) unless
         | 
| 20 | 
            -
              $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
         | 
| 21 | 
            -
             | 
| 22 19 | 
             
            require 'digest/md5'
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            require 'bibtex/version'
         | 
| 20 | 
            +
            require 'forwardable'
         | 
| 25 21 | 
             
            require 'logger'
         | 
| 22 | 
            +
            require 'open-uri'
         | 
| 26 23 |  | 
| 27 24 | 
             
            require 'multi_json'
         | 
| 28 25 |  | 
| 26 | 
            +
            require 'bibtex/version'
         | 
| 27 | 
            +
             | 
| 29 28 | 
             
            # = BibTeX
         | 
| 30 29 | 
             
            #
         | 
| 31 30 | 
             
            # This module encompasses a parser for BibTeX files and
         | 
| 32 | 
            -
            #  | 
| 33 | 
            -
            #  | 
| 34 | 
            -
            # +Entry+.
         | 
| 31 | 
            +
            # an API to the individual BibTeX objects: +String+,
         | 
| 32 | 
            +
            # +Preamble+, +Comment+, and +Entry+.
         | 
| 35 33 | 
             
            #
         | 
| 36 34 | 
             
            # Author:: {Sylvester Keil}[http://sylvester.keil.or.at]
         | 
| 37 35 | 
             
            # Copyright:: Copyright (c) 2010-2011 Sylvester Keil
         | 
| @@ -43,11 +41,13 @@ module BibTeX | |
| 43 41 | 
             
            	# An instance of the Ruby core class +Logger+.
         | 
| 44 42 | 
             
            	# Used for logging by BibTeX-Ruby.
         | 
| 45 43 | 
             
            	#
         | 
| 46 | 
            -
            	 | 
| 47 | 
            -
            	 | 
| 48 | 
            -
            	 | 
| 44 | 
            +
            	@log = Logger.new(STDERR)
         | 
| 45 | 
            +
            	@log.level = ENV.has_key?('DEBUG') ? Logger::DEBUG : Logger::WARN
         | 
| 46 | 
            +
            	@log.datetime_format = '%Y-%m-%d %H:%M:%S'
         | 
| 49 47 |  | 
| 50 | 
            -
               | 
| 48 | 
            +
              class << self
         | 
| 49 | 
            +
                attr_reader :log
         | 
| 50 | 
            +
              end
         | 
| 51 51 |  | 
| 52 52 | 
             
            end
         | 
| 53 53 |  | 
    
        data/lib/bibtex/bibliography.rb
    CHANGED
    
    | @@ -16,9 +16,6 @@ | |
| 16 16 | 
             
            # along with this program.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 17 17 | 
             
            #++
         | 
| 18 18 |  | 
| 19 | 
            -
            require 'forwardable'
         | 
| 20 | 
            -
            require 'open-uri'
         | 
| 21 | 
            -
             | 
| 22 19 | 
             
            module BibTeX
         | 
| 23 20 |  | 
| 24 21 | 
             
              #
         | 
| @@ -35,8 +32,8 @@ module BibTeX | |
| 35 32 |  | 
| 36 33 | 
             
                class << self    
         | 
| 37 34 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 35 | 
            +
                  attr_reader :defaults
         | 
| 36 | 
            +
                  
         | 
| 40 37 | 
             
                  # Opens and parses the `.bib' file at the given +path+. Returns
         | 
| 41 38 | 
             
                  # a new Bibliography instance corresponding to the file, or, if a block
         | 
| 42 39 | 
             
                  # is given, yields the instance to the block, ensuring that the file
         | 
| @@ -53,7 +50,7 @@ module BibTeX | |
| 53 50 | 
             
                  #
         | 
| 54 51 | 
             
                  def open(path, options = {})
         | 
| 55 52 | 
             
                    b = parse(Kernel.open(path, 'r:UTF-8').read, options)
         | 
| 56 | 
            -
             | 
| 53 | 
            +
                    b.path = path
         | 
| 57 54 | 
             
                    return b unless block_given?
         | 
| 58 55 |  | 
| 59 56 | 
             
                    begin
         | 
| @@ -65,14 +62,14 @@ module BibTeX | |
| 65 62 |  | 
| 66 63 | 
             
                  # Parses the given string and returns a corresponding Bibliography instance.
         | 
| 67 64 | 
             
                  def parse(input, options = {})
         | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 65 | 
            +
                    case input
         | 
| 66 | 
            +
                    when Array, Hash, Element
         | 
| 67 | 
            +
                      Bibliography.new(options).add(input)
         | 
| 68 | 
            +
                    when ::String
         | 
| 69 | 
            +
                      Parser.new(options).parse(input) || Bibliography.new(options)
         | 
| 70 | 
            +
                    else
         | 
| 71 | 
            +
                      raise ArgumentError, "failed to parse #{input.inspect}"
         | 
| 72 | 
            +
                    end
         | 
| 76 73 | 
             
                  end
         | 
| 77 74 |  | 
| 78 75 | 
             
                  # Defines a new accessor that selects elements by type.
         | 
| @@ -88,22 +85,30 @@ module BibTeX | |
| 88 85 |  | 
| 89 86 | 
             
                attr_reader :data, :strings, :entries, :errors, :options
         | 
| 90 87 |  | 
| 91 | 
            -
                attr_by_type :article, :book, :journal, :collection, :preamble, | 
| 92 | 
            -
             | 
| 88 | 
            +
                attr_by_type :article, :book, :journal, :collection, :preamble,
         | 
| 89 | 
            +
                  :comment, :meta_content
         | 
| 93 90 |  | 
| 94 | 
            -
                def_delegators :@data, :length, :size, : | 
| 95 | 
            -
             | 
| 91 | 
            +
                def_delegators :@data, :length, :size, :empty?
         | 
| 92 | 
            +
                def_delegators :@entries, :key?, :has_key?
         | 
| 96 93 |  | 
| 97 94 |  | 
| 98 95 | 
             
                # Creates a new bibliography.
         | 
| 99 96 | 
             
                def initialize(options = {})
         | 
| 100 97 | 
             
                  @options = Bibliography.defaults.merge(options)
         | 
| 101 | 
            -
                  @data, @strings = [], {}
         | 
| 102 | 
            -
             | 
| 98 | 
            +
                  @data, @strings, @errors = [], {}, []
         | 
| 99 | 
            +
                  @entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }
         | 
| 103 100 |  | 
| 104 101 | 
             
                  yield self if block_given?
         | 
| 105 102 | 
             
                end
         | 
| 106 103 |  | 
| 104 | 
            +
                def initialize_copy(other)
         | 
| 105 | 
            +
                  @options = other.options.dup
         | 
| 106 | 
            +
                  @errors = other.errors.dup
         | 
| 107 | 
            +
                  @data, @strings = [], {}
         | 
| 108 | 
            +
                  @entries = Hash.new { |h,k| h.fetch(k.to_s, nil) }
         | 
| 109 | 
            +
                  add(other.data)
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
                
         | 
| 107 112 | 
             
                # Adds a new element, or a list of new elements to the bibliography.
         | 
| 108 113 | 
             
                # Returns the Bibliography for chainability.
         | 
| 109 114 | 
             
                def add(*arguments)
         | 
| @@ -127,11 +132,21 @@ module BibTeX | |
| 127 132 | 
             
                  options[:quotes] ||= %w({ })
         | 
| 128 133 |  | 
| 129 134 | 
             
                  File.open(path, 'w:UTF-8') do |f|
         | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 135 | 
            +
                    f.write(to_s(options))
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
                  
         | 
| 133 138 | 
             
                  self
         | 
| 134 139 | 
             
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
             | 
| 142 | 
            +
                def each
         | 
| 143 | 
            +
                  if block_given?
         | 
| 144 | 
            +
                    data.each(&Proc.new)
         | 
| 145 | 
            +
                    self
         | 
| 146 | 
            +
                  else
         | 
| 147 | 
            +
                    to_enum
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
                end
         | 
| 135 150 |  | 
| 136 151 |  | 
| 137 152 | 
             
                def parse_names
         | 
| @@ -150,12 +165,12 @@ module BibTeX | |
| 150 165 | 
             
                # entry). @see Entry#convert!
         | 
| 151 166 | 
             
                def convert (filter)
         | 
| 152 167 | 
             
                  entries.each_value do |entry|
         | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 168 | 
            +
                    entry.convert!(filter) if !block_given? || yield(entry)
         | 
| 169 | 
            +
                  end
         | 
| 170 | 
            +
                  
         | 
| 156 171 | 
             
                  self
         | 
| 157 172 | 
             
                end
         | 
| 158 | 
            -
             | 
| 173 | 
            +
                    
         | 
| 159 174 |  | 
| 160 175 | 
             
                # Deletes an object, or a list of objects from the bibliography.
         | 
| 161 176 | 
             
                # If a list of objects is to be deleted, you can either supply the list
         | 
| @@ -173,10 +188,6 @@ module BibTeX | |
| 173 188 | 
             
                alias rm delete
         | 
| 174 189 |  | 
| 175 190 |  | 
| 176 | 
            -
                # Returns an element or a list of elements according to the given index,
         | 
| 177 | 
            -
                # range, or query. Contrary to the Bibliography#query this method does
         | 
| 178 | 
            -
                # not yield to a block for additional refinement of the query.
         | 
| 179 | 
            -
                #
         | 
| 180 191 | 
             
                # call-seq:
         | 
| 181 192 | 
             
                # >> bib[-1]
         | 
| 182 193 | 
             
                # => Returns the last element of the Bibliography or nil
         | 
| @@ -196,34 +207,35 @@ module BibTeX | |
| 196 207 | 
             
                # => Returns all objects that match 'ruby' anywhere or []
         | 
| 197 208 | 
             
                # >> bib['@book[keywords=ruby]']
         | 
| 198 209 | 
             
                # => Returns all books whose keywords attribute equals 'ruby' or []
         | 
| 210 | 
            +
                #
         | 
| 211 | 
            +
                # Returns an element or a list of elements according to the given index,
         | 
| 212 | 
            +
                # range, or query. Contrary to the Bibliography#query this method does
         | 
| 213 | 
            +
                # not yield to a block for additional refinement of the query.
         | 
| 214 | 
            +
                #
         | 
| 199 215 | 
             
                def [](*arguments)
         | 
| 200 216 | 
             
                  raise(ArgumentError, "wrong number of arguments (#{arguments.length} for 1..2)") unless arguments.length.between?(1,2)
         | 
| 201 217 |  | 
| 202 218 | 
             
                  case
         | 
| 203 219 | 
             
                  when arguments[0].is_a?(Numeric) || arguments[0].is_a?(Range)
         | 
| 204 220 | 
             
                    data[*arguments] 
         | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 221 | 
            +
                  when arguments.length == 1
         | 
| 222 | 
            +
                    case
         | 
| 223 | 
            +
                    when arguments[0].nil?
         | 
| 224 | 
            +
                      nil
         | 
| 225 | 
            +
                    when arguments[0].respond_to?(:empty?) && arguments[0].empty?
         | 
| 226 | 
            +
                      nil
         | 
| 227 | 
            +
                    when arguments[0].is_a?(Symbol)
         | 
| 228 | 
            +
                      entries[arguments[0]]
         | 
| 229 | 
            +
                    when arguments[0].respond_to?(:start_with?) && !arguments[0].start_with?('@')
         | 
| 230 | 
            +
                      entries[arguments[0]]
         | 
| 231 | 
            +
                    else
         | 
| 232 | 
            +
                      query(*arguments)
         | 
| 233 | 
            +
                    end
         | 
| 218 234 | 
             
                  else
         | 
| 219 235 | 
             
                    query(*arguments)
         | 
| 220 236 | 
             
                  end
         | 
| 221 237 | 
             
                end
         | 
| 222 238 |  | 
| 223 | 
            -
                # Returns all objects which could not be parsed successfully.
         | 
| 224 | 
            -
                def errors
         | 
| 225 | 
            -
                  @errors ||= []
         | 
| 226 | 
            -
                end
         | 
| 227 239 |  | 
| 228 240 | 
             
                # Returns true if there are object which could not be parsed.
         | 
| 229 241 | 
             
                def errors?
         | 
| @@ -233,14 +245,14 @@ module BibTeX | |
| 233 245 | 
             
                # Returns true if the +Bibliography+ contains no errors and only
         | 
| 234 246 | 
             
                # valid BibTeX objects (meta content is ignored).
         | 
| 235 247 | 
             
                def valid?
         | 
| 236 | 
            -
                  !errors? &&  | 
| 248 | 
            +
                  !errors? && entries.values.all?(&:valid?)
         | 
| 249 | 
            +
                end
         | 
| 250 | 
            +
                
         | 
| 251 | 
            +
                # Returns a list of the names of all authors, editors and translators in the Bibliography.
         | 
| 252 | 
            +
                def names
         | 
| 253 | 
            +
                  map(&:names).flatten
         | 
| 237 254 | 
             
                end
         | 
| 238 255 |  | 
| 239 | 
            -
            		# Returns a list of the names of all authors, editors and translators in the Bibliography.
         | 
| 240 | 
            -
            		def names
         | 
| 241 | 
            -
            			map(&:names).flatten
         | 
| 242 | 
            -
            		end
         | 
| 243 | 
            -
            		
         | 
| 244 256 | 
             
                # Replaces all string symbols which are defined in the bibliography.
         | 
| 245 257 | 
             
                #
         | 
| 246 258 | 
             
                # By default symbols in @string, @preamble and entries are replaced; this
         | 
| @@ -273,8 +285,9 @@ module BibTeX | |
| 273 285 | 
             
                  self
         | 
| 274 286 | 
             
                end
         | 
| 275 287 |  | 
| 288 | 
            +
                
         | 
| 276 289 | 
             
                def sort(*arguments, &block)
         | 
| 277 | 
            -
                   | 
| 290 | 
            +
                  data.sort(*arguments, &block)
         | 
| 278 291 | 
             
                  self
         | 
| 279 292 | 
             
                end
         | 
| 280 293 |  | 
| @@ -283,6 +296,10 @@ module BibTeX | |
| 283 296 | 
             
                  map { |o| o.to_s(options) }.join
         | 
| 284 297 | 
             
                end
         | 
| 285 298 |  | 
| 299 | 
            +
                def inspect
         | 
| 300 | 
            +
                  "#<#{self.class} data=[#{length}]>"
         | 
| 301 | 
            +
                end
         | 
| 302 | 
            +
                
         | 
| 286 303 | 
             
                def to_a(options = {})
         | 
| 287 304 | 
             
                  map { |o| o.to_hash(options) }
         | 
| 288 305 | 
             
                end
         | 
| @@ -308,16 +325,16 @@ module BibTeX | |
| 308 325 | 
             
                end
         | 
| 309 326 |  | 
| 310 327 | 
             
                # Returns a REXML::Document representation of the bibliography using the
         | 
| 311 | 
            -
             | 
| 328 | 
            +
                # BibTeXML format.
         | 
| 312 329 | 
             
                def to_xml(options = {})
         | 
| 313 330 | 
             
                  require 'rexml/document'
         | 
| 314 | 
            -
             | 
| 331 | 
            +
                  
         | 
| 315 332 | 
             
                  xml =  REXML::Document.new
         | 
| 316 333 | 
             
                  xml << REXML::XMLDecl.new('1.0','UTF-8')
         | 
| 317 334 |  | 
| 318 335 | 
             
                  root = REXML::Element.new('bibtex:file')
         | 
| 319 | 
            -
             | 
| 320 | 
            -
             | 
| 336 | 
            +
                  root.add_namespace('bibtex', 'http://bibtexml.sf.net/')
         | 
| 337 | 
            +
                  
         | 
| 321 338 | 
             
                  each { |e| root.add_element(e.to_xml(options)) }
         | 
| 322 339 |  | 
| 323 340 | 
             
                  xml.add_element(root)
         | 
| @@ -342,11 +359,11 @@ module BibTeX | |
| 342 359 | 
             
                # #=> same as above without using a block
         | 
| 343 360 | 
             
                #
         | 
| 344 361 | 
             
                def query(*arguments, &block)
         | 
| 345 | 
            -
                  raise | 
| 362 | 
            +
                  raise ArgumentError, "wrong number of arguments (#{arguments.length} for 0..2)" unless arguments.length.between?(0,2)
         | 
| 346 363 |  | 
| 347 364 | 
             
                  q, selector = arguments.reverse
         | 
| 348 365 | 
             
                  filter = block ? Proc.new { |e| e.match?(q) && block.call(e) } :
         | 
| 349 | 
            -
             | 
| 366 | 
            +
                    Proc.new { |e| e.match?(q) }
         | 
| 350 367 |  | 
| 351 368 | 
             
                  send(query_handler(selector), &filter)
         | 
| 352 369 | 
             
                end
         | 
| @@ -363,26 +380,26 @@ module BibTeX | |
| 363 380 | 
             
                  other.respond_to?(:to_a) ? to_a <=> other.to_a : nil
         | 
| 364 381 | 
             
                end
         | 
| 365 382 |  | 
| 366 | 
            -
             | 
| 367 | 
            -
             | 
| 368 | 
            -
             | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 371 | 
            -
             | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 374 | 
            -
             | 
| 375 | 
            -
             | 
| 376 | 
            -
             | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
| 379 | 
            -
             | 
| 380 | 
            -
             | 
| 381 | 
            -
             | 
| 382 | 
            -
             | 
| 383 | 
            -
             | 
| 384 | 
            -
             | 
| 385 | 
            -
             | 
| 383 | 
            +
                # TODO this should be faster than select_duplicates_by
         | 
| 384 | 
            +
                # def detect_duplicates_by(*arguments)
         | 
| 385 | 
            +
                # end
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                def select_duplicates_by(*arguments)
         | 
| 388 | 
            +
                  d, fs = Hash.new([]), arguments.flatten.map(&:to_sym)
         | 
| 389 | 
            +
                  q('@entry') do |e|
         | 
| 390 | 
            +
                    d[e.generate_hash(fs)] << e
         | 
| 391 | 
            +
                  end
         | 
| 392 | 
            +
                  
         | 
| 393 | 
            +
                  d.values.dup
         | 
| 394 | 
            +
                end
         | 
| 395 | 
            +
                
         | 
| 396 | 
            +
                alias duplicates select_duplicates_by
         | 
| 397 | 
            +
                
         | 
| 398 | 
            +
                def duplicates?
         | 
| 399 | 
            +
                  !select_duplicates_by?.empty?
         | 
| 400 | 
            +
                end
         | 
| 401 | 
            +
                
         | 
| 402 | 
            +
                
         | 
| 386 403 | 
             
                private
         | 
| 387 404 |  | 
| 388 405 | 
             
                def query_handler(selector)
         | 
    
        data/lib/bibtex/elements.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            #--
         | 
| 2 2 | 
             
            # BibTeX-Ruby
         | 
| 3 | 
            -
            # Copyright (C) 2010-2011 | 
| 3 | 
            +
            # Copyright (C) 2010-2011 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
         | 
| @@ -9,45 +9,45 @@ | |
| 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 | 
            -
            # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
| 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 | 
            -
            # along with this program. | 
| 16 | 
            +
            # along with this program.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 17 17 | 
             
            #++
         | 
| 18 18 |  | 
| 19 19 | 
             
            module BibTeX
         | 
| 20 20 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 21 | 
            +
              #
         | 
| 22 | 
            +
              # The base class for BibTeX objects.
         | 
| 23 | 
            +
              #
         | 
| 24 | 
            +
              class Element
         | 
| 25 25 | 
             
                include Comparable
         | 
| 26 26 |  | 
| 27 27 | 
             
                attr_writer :id
         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 28 | 
            +
                attr_reader :bibliography
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                # Returns an array of BibTeX elements.
         | 
| 31 31 | 
             
                def self.parse(input, options = {})
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 32 | 
            +
                  case input
         | 
| 33 | 
            +
                  when Element
         | 
| 34 | 
            +
                    [input]
         | 
| 35 | 
            +
                  when Hash
         | 
| 36 | 
            +
                    [Entry.new(input)]
         | 
| 37 | 
            +
                  when Array
         | 
| 38 | 
            +
                    input.inject([]) { |s,a| s.concat(parse(a, options)) }
         | 
| 39 | 
            +
                  when ::String
         | 
| 40 | 
            +
                    Parser.new(options).parse(input).data.each do |e|
         | 
| 41 | 
            +
                      e.parse_names unless !e.respond_to?(:parse_names) || options[:parse_names] == false
         | 
| 42 | 
            +
                      e.parse_month unless !e.respond_to?(:parse_month) || options[:parse_months] == false
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  else
         | 
| 45 | 
            +
                    raise ArgumentError, "failed to parse Element from #{input.inspect}"
         | 
| 46 | 
            +
                  end
         | 
| 47 47 | 
             
                end
         | 
| 48 48 |  | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 49 | 
            +
                # Returns a string containing the object's content.
         | 
| 50 | 
            +
                def content(options = {}); ''; end
         | 
| 51 51 |  | 
| 52 52 | 
             
                # Invokes BibTeX string replacement on this element.
         | 
| 53 53 | 
             
                def replace(*arguments); self; end
         | 
| @@ -63,19 +63,19 @@ module BibTeX | |
| 63 63 | 
             
                  self.class.name.split(/::/).last.gsub(/([[:lower:]])([[:upper:]])/) { "#{$1}_#{$2}" }.downcase.intern
         | 
| 64 64 | 
             
                end
         | 
| 65 65 |  | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 66 | 
            +
                # Returns a list of names for that Element. All Elements except Entries return an empty list.
         | 
| 67 | 
            +
                def names
         | 
| 68 | 
            +
                  []
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
                
         | 
| 71 71 | 
             
                def has_type?(type)
         | 
| 72 72 | 
             
                  self.type == type.intern || defined?(type) == 'constant' && is_a?(type)
         | 
| 73 73 | 
             
                end
         | 
| 74 74 |  | 
| 75 75 | 
             
                [:entry, :book, :article, :collection, :string, :preamble, :comment]. each do |type|
         | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 76 | 
            +
                  method_id = "#{type}?"
         | 
| 77 | 
            +
                  define_method(method_id) { has_type?(type) } unless method_defined?(method_id)
         | 
| 78 | 
            +
                end
         | 
| 79 79 |  | 
| 80 80 | 
             
                # Returns true if the element matches the given query.
         | 
| 81 81 | 
             
                def matches?(query)
         | 
| @@ -112,85 +112,85 @@ module BibTeX | |
| 112 112 |  | 
| 113 113 | 
             
                alias meet? meets?
         | 
| 114 114 |  | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 115 | 
            +
                alias to_s content
         | 
| 116 | 
            +
                
         | 
| 117 | 
            +
                def to_hash(options = {})
         | 
| 118 | 
            +
                  { type => content }
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
                
         | 
| 121 | 
            +
                def to_yaml(options = {})
         | 
| 122 | 
            +
                  require 'yaml'
         | 
| 123 123 | 
             
                  to_hash.to_yaml
         | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
                
         | 
| 126 | 
            +
                def to_json(options = {})
         | 
| 127 | 
            +
                  MultiJson.encode(to_hash(options))
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                def to_xml(options = {})
         | 
| 131 | 
            +
                  require 'rexml/document'
         | 
| 132 | 
            +
                  xml = REXML::Element.new(type)
         | 
| 133 | 
            +
                  xml.text = content
         | 
| 134 | 
            +
                  xml
         | 
| 135 | 
            +
                end
         | 
| 136 136 |  | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 137 | 
            +
                # Called when the element was added to a bibliography.
         | 
| 138 | 
            +
                def added_to_bibliography(bibliography)
         | 
| 139 | 
            +
                  # raise BibTeXError, "failed to add element to Bibliography: already registered with another Bibliography" unless @bibliography.nil?
         | 
| 140 | 
            +
                  @bibliography = bibliography
         | 
| 141 | 
            +
                  self
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
                
         | 
| 144 | 
            +
                # Called when the element was removed from a bibliography.
         | 
| 145 | 
            +
                def removed_from_bibliography(bibliography)
         | 
| 146 | 
            +
                  @bibliography = nil
         | 
| 147 | 
            +
                  self
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
                
         | 
| 150 | 
            +
                def <=>(other)
         | 
| 151 | 
            +
                  return nil unless other.respond_to? :type and other.respond_to? :to_s
         | 
| 152 | 
            +
                  [type, to_s] <=> [other.type, other.to_s]
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                # Returns the Element as a nicely formatted string.
         | 
| 156 | 
            +
                def inspect
         | 
| 157 | 
            +
                  "#<#{self.class} #{content.gsub(/\n/, ' ')}>"
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
              end
         | 
| 160 160 |  | 
| 161 161 |  | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 162 | 
            +
              #
         | 
| 163 | 
            +
              # Represents a @string object.
         | 
| 164 | 
            +
              #
         | 
| 165 | 
            +
              # In BibTeX @string objects contain a single string constant
         | 
| 166 | 
            +
              # assignment. For example, @string{ foo = "bar" } defines the
         | 
| 167 | 
            +
              # constant `foo'; this constant can be used (using BibTeX's
         | 
| 168 | 
            +
              # string concatenation syntax) in susbsequent
         | 
| 169 | 
            +
              # @string and @preamble objects, as well as in field values
         | 
| 170 | 
            +
              # of regular entries.
         | 
| 171 | 
            +
              #
         | 
| 172 | 
            +
              class String < Element    
         | 
| 173 173 | 
             
                include Replaceable
         | 
| 174 174 |  | 
| 175 | 
            -
             | 
| 175 | 
            +
                attr_reader :key
         | 
| 176 176 |  | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 177 | 
            +
                # Creates a new instance.
         | 
| 178 | 
            +
                def initialize(key = nil, value = nil)
         | 
| 179 | 
            +
                  @key, @value = key.to_sym, Value.new(value)
         | 
| 180 | 
            +
                  yield self if block_given?
         | 
| 181 | 
            +
                end
         | 
| 182 182 |  | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 183 | 
            +
                # Sets the string's key (i.e., the symbol identifying the constant).
         | 
| 184 | 
            +
                def key=(key)
         | 
| 185 | 
            +
                  raise(ArgumentError, "keys must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
         | 
| 186 | 
            +
                  
         | 
| 187 | 
            +
                  unless bibliography.nil?
         | 
| 188 | 
            +
                    bibliography.strings.delete(@key)
         | 
| 189 | 
            +
                    bibliography.strings[key.to_sym] = self
         | 
| 190 | 
            +
                  end
         | 
| 191 191 |  | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 192 | 
            +
                  @key = key.to_sym
         | 
| 193 | 
            +
                end
         | 
| 194 194 |  | 
| 195 195 | 
             
                # Retuns the string's value if parameter matches the key; nil otherwise.
         | 
| 196 196 | 
             
                def [](key)
         | 
| @@ -198,104 +198,104 @@ module BibTeX | |
| 198 198 | 
             
                end
         | 
| 199 199 |  | 
| 200 200 |  | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 201 | 
            +
                # Called when the element was added to a bibliography.
         | 
| 202 | 
            +
                def added_to_bibliography(bibliography)
         | 
| 203 | 
            +
                  super
         | 
| 204 | 
            +
                  bibliography.strings[@key] = self
         | 
| 205 | 
            +
                  self
         | 
| 206 | 
            +
                end
         | 
| 207 | 
            +
                
         | 
| 208 | 
            +
                # Called when the element was removed from a bibliography.
         | 
| 209 | 
            +
                def removed_from_bibliography(bibliography)
         | 
| 210 | 
            +
                  super
         | 
| 211 | 
            +
                  bibliography.strings[@key] = nil
         | 
| 212 | 
            +
                  self
         | 
| 213 | 
            +
                end
         | 
| 214 214 |  | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 215 | 
            +
                # Returns a string representation of the @string's content.
         | 
| 216 | 
            +
                def content
         | 
| 217 | 
            +
                  "#@key = #{@value.to_s(:quotes => '"')}"
         | 
| 218 | 
            +
                end
         | 
| 219 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 | 
            -
             | 
| 220 | 
            +
                # Returns a string representation of the @string object.
         | 
| 221 | 
            +
                def to_s(options = {})
         | 
| 222 | 
            +
                  "@string{ #{content} }"
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
                
         | 
| 225 | 
            +
                def to_hash(options = {})
         | 
| 226 | 
            +
                  { :string => { @key => @value.to_s(:quotes => '"') } }
         | 
| 227 | 
            +
                end
         | 
| 228 | 
            +
                
         | 
| 229 | 
            +
                def to_xml(options = {})
         | 
| 230 | 
            +
                  require 'rexml/document'
         | 
| 231 | 
            +
                  
         | 
| 232 | 
            +
                  xml = REXML::Element.new(:string)
         | 
| 233 | 
            +
                  
         | 
| 234 | 
            +
                  k, v = REXML::Element.new(:key), REXML::Element.new(:value)
         | 
| 235 | 
            +
                  k.text = key.to_s
         | 
| 236 | 
            +
                  v.text = value.to_s(:quotes => '"')
         | 
| 237 | 
            +
                
         | 
| 238 | 
            +
                  xml.add_elements(k)
         | 
| 239 | 
            +
                  xml.add_elements(v)
         | 
| 240 | 
            +
                  
         | 
| 241 | 
            +
                  xml
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
              end
         | 
| 244 244 |  | 
| 245 | 
            -
             | 
| 246 | 
            -
             | 
| 247 | 
            -
             | 
| 248 | 
            -
             | 
| 249 | 
            -
             | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 245 | 
            +
              #
         | 
| 246 | 
            +
              # Represents a @preamble object.
         | 
| 247 | 
            +
              #
         | 
| 248 | 
            +
              # In BibTeX an @preamble object contains a single string literal,
         | 
| 249 | 
            +
              # a single constant, or a concatenation of string literals and
         | 
| 250 | 
            +
              # constants.
         | 
| 251 | 
            +
              class Preamble < Element
         | 
| 252 | 
            +
                include Replaceable
         | 
| 253 253 |  | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 254 | 
            +
                # Creates a new instance.
         | 
| 255 | 
            +
                def initialize(value = '')
         | 
| 256 256 | 
             
                  @value = Value.new(value)
         | 
| 257 | 
            -
             | 
| 257 | 
            +
                end
         | 
| 258 258 |  | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 259 | 
            +
                # Returns a string representation of the @preamble's content.
         | 
| 260 | 
            +
                def content
         | 
| 261 | 
            +
                  @value.to_s(:quotes => '"')
         | 
| 262 | 
            +
                end
         | 
| 263 263 |  | 
| 264 | 
            -
             | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 267 | 
            -
             | 
| 268 | 
            -
             | 
| 264 | 
            +
                # Returns a string representation of the @preamble object
         | 
| 265 | 
            +
                def to_s(options = {})
         | 
| 266 | 
            +
                  "@preamble{ #{content} }"
         | 
| 267 | 
            +
                end
         | 
| 268 | 
            +
              end
         | 
| 269 269 |  | 
| 270 | 
            -
             | 
| 271 | 
            -
             | 
| 270 | 
            +
              # Represents a @comment object.
         | 
| 271 | 
            +
              class Comment < Element
         | 
| 272 272 | 
             
                attr_accessor :content
         | 
| 273 273 |  | 
| 274 | 
            -
             | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 274 | 
            +
                def initialize(content = '')
         | 
| 275 | 
            +
                  @content = content
         | 
| 276 | 
            +
                end
         | 
| 277 277 |  | 
| 278 | 
            -
             | 
| 279 | 
            -
             | 
| 280 | 
            -
             | 
| 281 | 
            -
             | 
| 278 | 
            +
                def to_s(options = {})
         | 
| 279 | 
            +
                  "@comment{ #@content }"
         | 
| 280 | 
            +
                end
         | 
| 281 | 
            +
              end
         | 
| 282 282 |  | 
| 283 | 
            -
             | 
| 284 | 
            -
             | 
| 285 | 
            -
             | 
| 286 | 
            -
             | 
| 287 | 
            -
             | 
| 288 | 
            -
             | 
| 289 | 
            -
             | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 294 | 
            -
             | 
| 295 | 
            -
             | 
| 296 | 
            -
             | 
| 283 | 
            +
              # Represents text in a `.bib' file, but outside of an
         | 
| 284 | 
            +
              # actual BibTeX object; typically, such text is treated
         | 
| 285 | 
            +
              # as a comment and is ignored by the parser. 
         | 
| 286 | 
            +
              # BibTeX-Ruby offers this class to allows for
         | 
| 287 | 
            +
              # post-processing of this type of `meta' content. If you
         | 
| 288 | 
            +
              # want the parser to include +MetaComment+ objects, you
         | 
| 289 | 
            +
              # need to add +:meta_content+ to the parser's +:include+
         | 
| 290 | 
            +
              # option.
         | 
| 291 | 
            +
              class MetaContent < Element
         | 
| 292 | 
            +
                attr_accessor :content
         | 
| 293 | 
            +
                
         | 
| 294 | 
            +
                def initialize(content = '')
         | 
| 295 | 
            +
                  @content = content
         | 
| 296 | 
            +
                end
         | 
| 297 297 |  | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 298 | 
            +
                def to_s(options = {}); @content; end
         | 
| 299 | 
            +
              end
         | 
| 300 300 |  | 
| 301 301 | 
             
            end
         |