bibtex-ruby 1.2.1 → 1.3.0
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 +6 -1
 - data/Gemfile.lock +48 -5
 - data/History.txt +16 -1
 - data/Manifest +43 -19
 - data/README.md +178 -167
 - data/Rakefile +26 -5
 - data/auto.watchr +6 -0
 - data/bibtex-ruby.gemspec +8 -5
 - data/examples/bib2html.rb +28 -18
 - data/features/bibtex.feature +96 -0
 - data/features/entries.feature +67 -0
 - data/features/issues/slash_keys.feature +21 -0
 - data/features/names.feature +72 -0
 - data/features/preambles.feature +27 -0
 - data/features/query.feature +56 -0
 - data/features/replacement.feature +68 -0
 - data/features/step_definitions/bibtex_steps.rb +74 -0
 - data/features/step_definitions/name_steps.rb +13 -0
 - data/features/strings.feature +52 -0
 - data/features/support/env.rb +7 -0
 - data/lib/bibtex.rb +5 -1
 - data/lib/bibtex/bibliography.rb +218 -95
 - data/lib/bibtex/bibtex.y +18 -15
 - data/lib/bibtex/elements.rb +130 -136
 - data/lib/bibtex/entry.rb +133 -69
 - data/lib/bibtex/extensions.rb +0 -35
 - data/lib/bibtex/lexer.rb +9 -9
 - data/lib/bibtex/name_parser.output +464 -0
 - data/lib/bibtex/name_parser.rb +490 -0
 - data/lib/bibtex/names.rb +162 -0
 - data/lib/bibtex/names.y +196 -0
 - data/lib/bibtex/parser.output +5 -5
 - data/lib/bibtex/parser.rb +19 -16
 - data/lib/bibtex/replaceable.rb +52 -0
 - data/lib/bibtex/utilities.rb +23 -5
 - data/lib/bibtex/value.rb +201 -0
 - data/lib/bibtex/version.rb +1 -1
 - data/test/benchmark.rb +52 -0
 - data/test/bibtex/test_bibliography.rb +141 -0
 - data/test/bibtex/test_elements.rb +40 -0
 - data/test/bibtex/test_entry.rb +99 -0
 - data/test/bibtex/test_names.rb +23 -0
 - data/test/bibtex/test_parser.rb +79 -0
 - data/test/bibtex/test_string.rb +83 -0
 - data/test/bibtex/test_utilities.rb +34 -0
 - data/test/bibtex/test_value.rb +70 -0
 - data/test/{bib/10_bibdesk.bib → fixtures/bibdesk.bib} +1 -1
 - data/test/{bib/05_comment.bib → fixtures/comment.bib} +0 -0
 - data/test/{bib/08_decoret.bib → fixtures/decoret.bib} +0 -0
 - data/test/{bib/00_empty.bib → fixtures/empty.bib} +0 -0
 - data/test/{bib/07_entry.bib → fixtures/entry.bib} +0 -0
 - data/test/{bib/09_errors.bib → fixtures/errors.bib} +0 -0
 - data/test/{bib/01_no_bibtex.bib → fixtures/no_bibtex.bib} +0 -0
 - data/test/{bib/06_preamble.bib → fixtures/preamble.bib} +1 -1
 - data/test/{bib/11_roundtrip.bib → fixtures/roundtrip.bib} +1 -1
 - data/test/helper.rb +17 -2
 - data/test/test_bibtex.rb +87 -93
 - data/test/test_export.rb +18 -22
 - metadata +85 -30
 - data/test/bib/02_string.bib +0 -1
 - data/test/bib/03_string.bib +0 -25
 - data/test/bib/04_string_replacement.bib +0 -16
 - data/test/test_comment.rb +0 -21
 - data/test/test_entry.rb +0 -98
 - data/test/test_preamble.rb +0 -39
 - data/test/test_string.rb +0 -97
 - data/test/test_utilities.rb +0 -36
 
    
        data/lib/bibtex/names.rb
    ADDED
    
    | 
         @@ -0,0 +1,162 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #--
         
     | 
| 
      
 2 
     | 
    
         
            +
            # BibTeX-Ruby
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (C) 2010-2011  Sylvester Keil <sylvester.keil.or.at>
         
     | 
| 
      
 4 
     | 
    
         
            +
            # 
         
     | 
| 
      
 5 
     | 
    
         
            +
            # This program is free software: you can redistribute it and/or modify
         
     | 
| 
      
 6 
     | 
    
         
            +
            # it under the terms of the GNU General Public License as published by
         
     | 
| 
      
 7 
     | 
    
         
            +
            # the Free Software Foundation, either version 3 of the License, or
         
     | 
| 
      
 8 
     | 
    
         
            +
            # (at your option) any later version.
         
     | 
| 
      
 9 
     | 
    
         
            +
            # 
         
     | 
| 
      
 10 
     | 
    
         
            +
            # This program is distributed in the hope that it will be useful,
         
     | 
| 
      
 11 
     | 
    
         
            +
            # but WITHOUT ANY WARRANTY; without even the implied warranty of
         
     | 
| 
      
 12 
     | 
    
         
            +
            # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
         
     | 
| 
      
 13 
     | 
    
         
            +
            # GNU General Public License for more details.
         
     | 
| 
      
 14 
     | 
    
         
            +
            # 
         
     | 
| 
      
 15 
     | 
    
         
            +
            # You should have received a copy of the GNU General Public License
         
     | 
| 
      
 16 
     | 
    
         
            +
            # along with this program.  If not, see <http://www.gnu.org/licenses/>.
         
     | 
| 
      
 17 
     | 
    
         
            +
            #++
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            module BibTeX
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              class Names < Value
         
     | 
| 
      
 24 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 25 
     | 
    
         
            +
                
         
     | 
| 
      
 26 
     | 
    
         
            +
                def_delegators :@tokens, :each, :sort
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                def self.parse(string)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  Names.new(NameParser.new.parse(string))
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                def initialize(*arguments)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @tokens = []
         
     | 
| 
      
 34 
     | 
    
         
            +
                  arguments.flatten.compact.each do |argument|
         
     | 
| 
      
 35 
     | 
    
         
            +
                    add(argument)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def replace(*arguments); self; end
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                def join; self; end
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                def value
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @tokens.join(' and ')
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                def to_s(options = {})
         
     | 
| 
      
 48 
     | 
    
         
            +
                  return value unless options.has_key?(:quotes)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  *q = options[:quotes]
         
     | 
| 
      
 50 
     | 
    
         
            +
                  [q[0], value, q[-1]].compact.join
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                def name?; true; end
         
     | 
| 
      
 54 
     | 
    
         
            +
                def numeric?; false; end
         
     | 
| 
      
 55 
     | 
    
         
            +
                def atomic?; true; end
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                alias :names? :name?
         
     | 
| 
      
 58 
     | 
    
         
            +
                alias :symbol? :numeric?
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                def to_name; self; end
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                def add(name)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  case
         
     | 
| 
      
 64 
     | 
    
         
            +
                  when name.is_a?(Name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    @tokens << name
         
     | 
| 
      
 66 
     | 
    
         
            +
                  when name.respond_to?(:to_s)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @tokens += Names.parse(name.to_s)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  else
         
     | 
| 
      
 69 
     | 
    
         
            +
                    raise ArgumentError, "failed to add #{name.inspect}: not a name."
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  self
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
                
         
     | 
| 
      
 74 
     | 
    
         
            +
                alias :<< :add
         
     | 
| 
      
 75 
     | 
    
         
            +
                alias :push :add
         
     | 
| 
      
 76 
     | 
    
         
            +
                
         
     | 
| 
      
 77 
     | 
    
         
            +
                def <=>(other)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  other.respond_to?(:to_a) ? to_a <=> other.to_a  : super
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
                
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              class Name < Struct.new(:first, :last, :prefix, :suffix)
         
     | 
| 
      
 84 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 85 
     | 
    
         
            +
                include Comparable
         
     | 
| 
      
 86 
     | 
    
         
            +
                
         
     | 
| 
      
 87 
     | 
    
         
            +
                def_delegators :to_s, :empty?, :=~, :match, :length, :intern, :to_sym, :end_with?, :start_with?, :include?, :upcase, :downcase, :reverse, :chop, :chomp, :rstrip, :gsub, :sub, :size, :strip, :succ, :to_str, :split, :each_byte, :each_char, :each_line
         
     | 
| 
      
 88 
     | 
    
         
            +
                
         
     | 
| 
      
 89 
     | 
    
         
            +
                class << self    
         
     | 
| 
      
 90 
     | 
    
         
            +
                  def parse(string)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    [NameParser.new.parse(string)].flatten[0]
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                  
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # Returns true if thing looks like a name.
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # Actually converts thing to a string and tries to parse it.
         
     | 
| 
      
 96 
     | 
    
         
            +
                  def looks_like?(thing)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    thing.respond_to?(:to_s) && [Name.new.parse(string)].flatten.compact.empty?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
                
         
     | 
| 
      
 101 
     | 
    
         
            +
                def initialize(attributes = {})
         
     | 
| 
      
 102 
     | 
    
         
            +
                  attributes.each do |key,value|
         
     | 
| 
      
 103 
     | 
    
         
            +
                    send("#{key}=", value) if respond_to?(key)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
                
         
     | 
| 
      
 107 
     | 
    
         
            +
                def initalize_copy(other)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  each_pair { |k,v| self[k] = v }
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
                
         
     | 
| 
      
 111 
     | 
    
         
            +
                def blank?
         
     | 
| 
      
 112 
     | 
    
         
            +
                  to_a.compact.empty?
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
                
         
     | 
| 
      
 115 
     | 
    
         
            +
                def display_order
         
     | 
| 
      
 116 
     | 
    
         
            +
                  [prefix, last, first, suffix].compact.join(' ')
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
                
         
     | 
| 
      
 119 
     | 
    
         
            +
                alias :display :display_order
         
     | 
| 
      
 120 
     | 
    
         
            +
                
         
     | 
| 
      
 121 
     | 
    
         
            +
                def sort_order
         
     | 
| 
      
 122 
     | 
    
         
            +
                  [[prefix,last].compact.join(' '), suffix, first].compact.join(', ')
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
                
         
     | 
| 
      
 125 
     | 
    
         
            +
                alias :to_s :sort_order
         
     | 
| 
      
 126 
     | 
    
         
            +
                
         
     | 
| 
      
 127 
     | 
    
         
            +
                def <=>(other)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  other.is_a?(Name) ? [last, prefix, first, suffix].compact.join(' ') <=> [other.last, other.prefix, other.first, other.suffix].compact.join(' ') : super
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
                
         
     | 
| 
      
 131 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 132 
     | 
    
         
            +
                  Hash[each_pair.to_a]
         
     | 
| 
      
 133 
     | 
    
         
            +
                end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                [:strip!, :upcase!, :downcase!, :sub!, :gsub!, :chop!, :chomp!, :rstrip!].each do |method_id|
         
     | 
| 
      
 136 
     | 
    
         
            +
                  define_method(method_id) do |*arguments, &block|
         
     | 
| 
      
 137 
     | 
    
         
            +
                    each do |part|
         
     | 
| 
      
 138 
     | 
    
         
            +
                      part.send(method_id, *arguments, &block)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
                    self
         
     | 
| 
      
 141 
     | 
    
         
            +
                  end
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
                
         
     | 
| 
      
 144 
     | 
    
         
            +
                def to_citeproc
         
     | 
| 
      
 145 
     | 
    
         
            +
                  {
         
     | 
| 
      
 146 
     | 
    
         
            +
                    'family' => [prefix, last].compact.join(' '),
         
     | 
| 
      
 147 
     | 
    
         
            +
                    'given' =>  [first, suffix].compact.join(', '),
         
     | 
| 
      
 148 
     | 
    
         
            +
                    'parse-names' => true
         
     | 
| 
      
 149 
     | 
    
         
            +
                  }
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
                
         
     | 
| 
      
 152 
     | 
    
         
            +
                alias :family :last
         
     | 
| 
      
 153 
     | 
    
         
            +
                alias :family= :last=    
         
     | 
| 
      
 154 
     | 
    
         
            +
                alias :given :first
         
     | 
| 
      
 155 
     | 
    
         
            +
                alias :given= :first=
         
     | 
| 
      
 156 
     | 
    
         
            +
                alias :jr :suffix
         
     | 
| 
      
 157 
     | 
    
         
            +
                alias :jr= :suffix=
         
     | 
| 
      
 158 
     | 
    
         
            +
                alias :von :prefix
         
     | 
| 
      
 159 
     | 
    
         
            +
                alias :von= :prefix=    
         
     | 
| 
      
 160 
     | 
    
         
            +
                
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/bibtex/names.y
    ADDED
    
    | 
         @@ -0,0 +1,196 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #--
         
     | 
| 
      
 2 
     | 
    
         
            +
            # BibTeX-Ruby
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (C) 2010-2011  Sylvester Keil <http://sylvester.keil.or.at>
         
     | 
| 
      
 4 
     | 
    
         
            +
            # 
         
     | 
| 
      
 5 
     | 
    
         
            +
            # This program is free software: you can redistribute it and/or modify
         
     | 
| 
      
 6 
     | 
    
         
            +
            # it under the terms of the GNU General Public License as published by
         
     | 
| 
      
 7 
     | 
    
         
            +
            # the Free Software Foundation, either version 3 of the License, or
         
     | 
| 
      
 8 
     | 
    
         
            +
            # (at your option) any later version.
         
     | 
| 
      
 9 
     | 
    
         
            +
            # 
         
     | 
| 
      
 10 
     | 
    
         
            +
            # This program is distributed in the hope that it will be useful,
         
     | 
| 
      
 11 
     | 
    
         
            +
            # but WITHOUT ANY WARRANTY; without even the implied warranty of
         
     | 
| 
      
 12 
     | 
    
         
            +
            # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
         
     | 
| 
      
 13 
     | 
    
         
            +
            # GNU General Public License for more details.
         
     | 
| 
      
 14 
     | 
    
         
            +
            # 
         
     | 
| 
      
 15 
     | 
    
         
            +
            # You should have received a copy of the GNU General Public License
         
     | 
| 
      
 16 
     | 
    
         
            +
            # along with this program.  If not, see <http://www.gnu.org/licenses/>.
         
     | 
| 
      
 17 
     | 
    
         
            +
            #++
         
     | 
| 
      
 18 
     | 
    
         
            +
            #
         
     | 
| 
      
 19 
     | 
    
         
            +
            # A BibTeX grammar for the parser generator +racc+
         
     | 
| 
      
 20 
     | 
    
         
            +
            #
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # -*- racc -*-
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            class BibTeX::NameParser
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            token COMMA UWORD LWORD PWORD AND ERROR
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            expect 0
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            rule
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              result :                           { result = [] }
         
     | 
| 
      
 33 
     | 
    
         
            +
                     | names                     { result = val[0] }
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              names : name                       { result = [val[0]] }
         
     | 
| 
      
 36 
     | 
    
         
            +
                    | names AND name             { result << val[2] }
         
     | 
| 
      
 37 
     | 
    
         
            +
              
         
     | 
| 
      
 38 
     | 
    
         
            +
              name : last                        { result = Name.new(:von => val[0][0], :last => val[0][1]) }
         
     | 
| 
      
 39 
     | 
    
         
            +
                   | u_words last                { result = Name.new(:first => val[0], :von => val[1][0], :last => val[1][1]) }
         
     | 
| 
      
 40 
     | 
    
         
            +
                   | sort COMMA first            { result = Name.new(:von => val[0][0], :last => val[0][1], :jr => val[2][0], :first => val[2][1]) }
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              sort : u_words                     { result = [nil,val[0]]}
         
     | 
| 
      
 43 
     | 
    
         
            +
                   | LWORD                       { result = [nil,val[0]]}
         
     | 
| 
      
 44 
     | 
    
         
            +
                   | von LWORD                   { result = [val[0],val[1]]}
         
     | 
| 
      
 45 
     | 
    
         
            +
                   | von u_words                 { result = [val[0],val[1]]}
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
              last : word                        { result = [nil,val[0]]}
         
     | 
| 
      
 48 
     | 
    
         
            +
                   | von LWORD                   { result = [val[0],val[1]]}
         
     | 
| 
      
 49 
     | 
    
         
            +
                   | von u_words                 { result = [val[0],val[1]]}
         
     | 
| 
      
 50 
     | 
    
         
            +
              
         
     | 
| 
      
 51 
     | 
    
         
            +
              first : opt_words                  { result = [nil,val[0]] }
         
     | 
| 
      
 52 
     | 
    
         
            +
                    | opt_words COMMA opt_words  { result = [val[0],val[2]] }
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              u_words : u_word                   { result = val[0] }
         
     | 
| 
      
 55 
     | 
    
         
            +
                      | u_words u_word           { result = val[0,2].join(' ') }
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              u_word : UWORD                     { result = val[0] }
         
     | 
| 
      
 58 
     | 
    
         
            +
                     | PWORD                     { result = val[0] }
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              von : LWORD                        { result = val[0] }
         
     | 
| 
      
 61 
     | 
    
         
            +
                  | von u_words LWORD            { result = val[0,3].join(' ') }
         
     | 
| 
      
 62 
     | 
    
         
            +
                  | von LWORD                    { result = val[0,2].join(' ') }
         
     | 
| 
      
 63 
     | 
    
         
            +
                
         
     | 
| 
      
 64 
     | 
    
         
            +
              words : word                       { result = val[0] }
         
     | 
| 
      
 65 
     | 
    
         
            +
                    | words word                 { result = val[0,2].join(' ') }
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              opt_words :                        { result = nil }
         
     | 
| 
      
 68 
     | 
    
         
            +
                        | words                  { result = val[0] }
         
     | 
| 
      
 69 
     | 
    
         
            +
              
         
     | 
| 
      
 70 
     | 
    
         
            +
              word : LWORD                       { result = val[0] }
         
     | 
| 
      
 71 
     | 
    
         
            +
                   | UWORD                       { result = val[0] }
         
     | 
| 
      
 72 
     | 
    
         
            +
                   | PWORD                       { result = val[0] }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            ---- header
         
     | 
| 
      
 77 
     | 
    
         
            +
            require 'strscan'
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            ---- inner
         
     | 
| 
      
 80 
     | 
    
         
            +
              
         
     | 
| 
      
 81 
     | 
    
         
            +
              def initialize(options = {})
         
     | 
| 
      
 82 
     | 
    
         
            +
                self.options.merge!(options)
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              def options
         
     | 
| 
      
 86 
     | 
    
         
            +
                @options ||= { :debug => ENV['DEBUG'] == true }
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
              
         
     | 
| 
      
 89 
     | 
    
         
            +
              def parse(input)
         
     | 
| 
      
 90 
     | 
    
         
            +
                @yydebug = options[:debug]
         
     | 
| 
      
 91 
     | 
    
         
            +
                scan(input)
         
     | 
| 
      
 92 
     | 
    
         
            +
                do_parse
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
              
         
     | 
| 
      
 95 
     | 
    
         
            +
              def next_token
         
     | 
| 
      
 96 
     | 
    
         
            +
                @stack.shift
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
              
         
     | 
| 
      
 99 
     | 
    
         
            +
              def on_error(tid, val, vstack)
         
     | 
| 
      
 100 
     | 
    
         
            +
                BibTeX.log.error("Failed to parse BibTeX Name on value %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect])
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
              def scan(input)
         
     | 
| 
      
 104 
     | 
    
         
            +
                @src = StringScanner.new(input)
         
     | 
| 
      
 105 
     | 
    
         
            +
                @brace_level = 0
         
     | 
| 
      
 106 
     | 
    
         
            +
                @stack = []
         
     | 
| 
      
 107 
     | 
    
         
            +
                @word = [:PWORD,'']
         
     | 
| 
      
 108 
     | 
    
         
            +
                do_scan
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
              
         
     | 
| 
      
 111 
     | 
    
         
            +
              private
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
              def do_scan
         
     | 
| 
      
 114 
     | 
    
         
            +
                until @src.eos?
         
     | 
| 
      
 115 
     | 
    
         
            +
                  case
         
     | 
| 
      
 116 
     | 
    
         
            +
                  when @src.scan(/,?\s+and\s+/io)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    push_word
         
     | 
| 
      
 118 
     | 
    
         
            +
                    @stack.push([:AND,@src.matched])
         
     | 
| 
      
 119 
     | 
    
         
            +
                    
         
     | 
| 
      
 120 
     | 
    
         
            +
                  when @src.scan(/[\t\r\n\s]+/o)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    push_word
         
     | 
| 
      
 122 
     | 
    
         
            +
                  
         
     | 
| 
      
 123 
     | 
    
         
            +
                  when @src.scan(/,/o)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    push_word
         
     | 
| 
      
 125 
     | 
    
         
            +
                    @stack.push([:COMMA,@src.matched])
         
     | 
| 
      
 126 
     | 
    
         
            +
                    
         
     | 
| 
      
 127 
     | 
    
         
            +
                  when @src.scan(/[[:lower:]][^\t\r\n\s\{\}\d\\,]*/o)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    is_lowercase
         
     | 
| 
      
 129 
     | 
    
         
            +
                    @word[1] << @src.matched
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  when @src.scan(/[[:upper:]][^\t\r\n\s\{\}\d\\,]*/o)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    is_uppercase
         
     | 
| 
      
 133 
     | 
    
         
            +
                    @word[1] << @src.matched
         
     | 
| 
      
 134 
     | 
    
         
            +
                    
         
     | 
| 
      
 135 
     | 
    
         
            +
                  when @src.scan(/(\d|\\.)+/o)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    @word[1] << @src.matched
         
     | 
| 
      
 137 
     | 
    
         
            +
                    
         
     | 
| 
      
 138 
     | 
    
         
            +
                  when @src.scan(/\{/o)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    scan_literal(@src.matched)
         
     | 
| 
      
 140 
     | 
    
         
            +
                    
         
     | 
| 
      
 141 
     | 
    
         
            +
                  when @src.scan(/\}/o)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    error_unbalanced
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                  when @src.scan(/./o)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    @word[1] << @src.matched
         
     | 
| 
      
 146 
     | 
    
         
            +
                  end
         
     | 
| 
      
 147 
     | 
    
         
            +
                end
         
     | 
| 
      
 148 
     | 
    
         
            +
                
         
     | 
| 
      
 149 
     | 
    
         
            +
                push_word
         
     | 
| 
      
 150 
     | 
    
         
            +
                @stack
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
              
         
     | 
| 
      
 153 
     | 
    
         
            +
              def push_word
         
     | 
| 
      
 154 
     | 
    
         
            +
                unless @word[1].empty?
         
     | 
| 
      
 155 
     | 
    
         
            +
                  @stack.push(@word)
         
     | 
| 
      
 156 
     | 
    
         
            +
                  @word = [:PWORD,'']
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
              end
         
     | 
| 
      
 159 
     | 
    
         
            +
              
         
     | 
| 
      
 160 
     | 
    
         
            +
              def is_lowercase
         
     | 
| 
      
 161 
     | 
    
         
            +
                @word[0] = :LWORD if @word[0] == :PWORD
         
     | 
| 
      
 162 
     | 
    
         
            +
              end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
              def is_uppercase
         
     | 
| 
      
 165 
     | 
    
         
            +
                @word[0] = :UWORD if @word[0] == :PWORD
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
              
         
     | 
| 
      
 168 
     | 
    
         
            +
              def scan_literal(content = '')
         
     | 
| 
      
 169 
     | 
    
         
            +
                @brace_level += 1
         
     | 
| 
      
 170 
     | 
    
         
            +
                content << @src.scan_until(/[^\\][\{\}]/o).to_s # TODO accept empty braces {}
         
     | 
| 
      
 171 
     | 
    
         
            +
                case @src.matched
         
     | 
| 
      
 172 
     | 
    
         
            +
                when /\{/
         
     | 
| 
      
 173 
     | 
    
         
            +
                  scan_braced_expression(content)
         
     | 
| 
      
 174 
     | 
    
         
            +
                when /\}/
         
     | 
| 
      
 175 
     | 
    
         
            +
                  @brace_level -= 1
         
     | 
| 
      
 176 
     | 
    
         
            +
                  if @brace_level >= 0
         
     | 
| 
      
 177 
     | 
    
         
            +
                    @word[1] << content
         
     | 
| 
      
 178 
     | 
    
         
            +
                  else
         
     | 
| 
      
 179 
     | 
    
         
            +
                    error_unbalanced
         
     | 
| 
      
 180 
     | 
    
         
            +
                  end
         
     | 
| 
      
 181 
     | 
    
         
            +
                else
         
     | 
| 
      
 182 
     | 
    
         
            +
                  error_unbalanced
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
              end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
              def error_unexpected
         
     | 
| 
      
 187 
     | 
    
         
            +
                @stack.push [:ERROR,@src.matched]
         
     | 
| 
      
 188 
     | 
    
         
            +
                BibTeX.log.warn("NameParser: unexpected token `#{@src.matched}' at position #{@src.pos}; brace level #{@brace_level}.")
         
     | 
| 
      
 189 
     | 
    
         
            +
              end
         
     | 
| 
      
 190 
     | 
    
         
            +
              
         
     | 
| 
      
 191 
     | 
    
         
            +
              def error_unbalanced
         
     | 
| 
      
 192 
     | 
    
         
            +
                @stack.push [:ERROR,'}']
         
     | 
| 
      
 193 
     | 
    
         
            +
                BibTeX.log.warn("NameParser: unbalanced braces at position #{@src.pos}; brace level #{@brace_level}.")
         
     | 
| 
      
 194 
     | 
    
         
            +
              end
         
     | 
| 
      
 195 
     | 
    
         
            +
              
         
     | 
| 
      
 196 
     | 
    
         
            +
            # -*- racc -*-
         
     | 
    
        data/lib/bibtex/parser.output
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ rule 2 bibliography: objects 
     | 
|
| 
       7 
7 
     | 
    
         
             
            rule 3 objects: object
         
     | 
| 
       8 
8 
     | 
    
         
             
            rule 4 objects: objects object
         
     | 
| 
       9 
9 
     | 
    
         
             
            rule 5 object: AT at_object
         
     | 
| 
       10 
     | 
    
         
            -
            rule 6 object:  
     | 
| 
      
 10 
     | 
    
         
            +
            rule 6 object: META_CONTENT
         
     | 
| 
       11 
11 
     | 
    
         
             
            rule 7 object: ERROR
         
     | 
| 
       12 
12 
     | 
    
         
             
            rule 8 at_object: comment
         
     | 
| 
       13 
13 
     | 
    
         
             
            rule 9 at_object: string
         
     | 
| 
         @@ -106,7 +106,7 @@ rule 33 value: LBRACE content RBRACE 
     | 
|
| 
       106 
106 
     | 
    
         
             
              ERROR (6) 7
         
     | 
| 
       107 
107 
     | 
    
         
             
              EQ (7) 17 30
         
     | 
| 
       108 
108 
     | 
    
         
             
              LBRACE (8) 12 15 16 25 33
         
     | 
| 
       109 
     | 
    
         
            -
               
     | 
| 
      
 109 
     | 
    
         
            +
              META_CONTENT (9) 6
         
     | 
| 
       110 
110 
     | 
    
         
             
              NAME (10) 17 20 25 26 30
         
     | 
| 
       111 
111 
     | 
    
         
             
              NUMBER (11) 27 32
         
     | 
| 
       112 
112 
     | 
    
         
             
              PREAMBLE (12) 15
         
     | 
| 
         @@ -122,7 +122,7 @@ state 0 
     | 
|
| 
       122 
122 
     | 
    
         | 
| 
       123 
123 
     | 
    
         
             
              AT            shift, and go to state 4
         
     | 
| 
       124 
124 
     | 
    
         
             
              ERROR         shift, and go to state 6
         
     | 
| 
       125 
     | 
    
         
            -
               
     | 
| 
      
 125 
     | 
    
         
            +
              META_CONTENT  shift, and go to state 5
         
     | 
| 
       126 
126 
     | 
    
         
             
              $default      reduce using rule 1 (bibliography)
         
     | 
| 
       127 
127 
     | 
    
         | 
| 
       128 
128 
     | 
    
         
             
              bibliography  go to state 1
         
     | 
| 
         @@ -142,7 +142,7 @@ state 2 
     | 
|
| 
       142 
142 
     | 
    
         | 
| 
       143 
143 
     | 
    
         
             
              AT            shift, and go to state 4
         
     | 
| 
       144 
144 
     | 
    
         
             
              ERROR         shift, and go to state 6
         
     | 
| 
       145 
     | 
    
         
            -
               
     | 
| 
      
 145 
     | 
    
         
            +
              META_CONTENT  shift, and go to state 5
         
     | 
| 
       146 
146 
     | 
    
         
             
              $default      reduce using rule 2 (bibliography)
         
     | 
| 
       147 
147 
     | 
    
         | 
| 
       148 
148 
     | 
    
         
             
              object        go to state 8
         
     | 
| 
         @@ -172,7 +172,7 @@ state 4 
     | 
|
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
            state 5
         
     | 
| 
       174 
174 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
               6) object :  
     | 
| 
      
 175 
     | 
    
         
            +
               6) object : META_CONTENT _
         
     | 
| 
       176 
176 
     | 
    
         | 
| 
       177 
177 
     | 
    
         
             
              $default      reduce using rule 6 (object)
         
     | 
| 
       178 
178 
     | 
    
         | 
    
        data/lib/bibtex/parser.rb
    CHANGED
    
    | 
         @@ -15,32 +15,35 @@ module_eval(<<'...end bibtex.y/module_eval...', 'bibtex.y', 89) 
     | 
|
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
              attr_reader :lexer
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
              def initialize(options={})
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                @ 
     | 
| 
       21 
     | 
    
         
            -
                @lexer = Lexer.new(options)
         
     | 
| 
      
 18 
     | 
    
         
            +
              def initialize(options = {})
         
     | 
| 
      
 19 
     | 
    
         
            +
            		self.options.merge!(options)
         
     | 
| 
      
 20 
     | 
    
         
            +
                @lexer = Lexer.new(@options)
         
     | 
| 
       22 
21 
     | 
    
         
             
              end
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
      
 23 
     | 
    
         
            +
            	def options
         
     | 
| 
      
 24 
     | 
    
         
            +
            		@options ||= { :include => [:errors], :debug => ENV['DEBUG'] == true }
         
     | 
| 
      
 25 
     | 
    
         
            +
            	end
         
     | 
| 
      
 26 
     | 
    
         
            +
            	
         
     | 
| 
       24 
27 
     | 
    
         
             
              def parse(input)
         
     | 
| 
       25 
     | 
    
         
            -
                @yydebug =  
     | 
| 
      
 28 
     | 
    
         
            +
                @yydebug = debug?
         
     | 
| 
       26 
29 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                 
     | 
| 
       28 
     | 
    
         
            -
                 
     | 
| 
      
 30 
     | 
    
         
            +
                @lexer.src = input
         
     | 
| 
      
 31 
     | 
    
         
            +
                @lexer.analyse
         
     | 
| 
       29 
32 
     | 
    
         | 
| 
       30 
33 
     | 
    
         
             
                do_parse
         
     | 
| 
       31 
34 
     | 
    
         
             
              end
         
     | 
| 
       32 
35 
     | 
    
         | 
| 
       33 
36 
     | 
    
         
             
              def next_token
         
     | 
| 
       34 
     | 
    
         
            -
                token =  
     | 
| 
      
 37 
     | 
    
         
            +
                token = @lexer.next_token
         
     | 
| 
       35 
38 
     | 
    
         
             
                if token[0] == :ERROR
         
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
      
 39 
     | 
    
         
            +
                  include_errors? ? token : next_token
         
     | 
| 
       37 
40 
     | 
    
         
             
                else
         
     | 
| 
       38 
41 
     | 
    
         
             
                  [token[0],token[1][0]]
         
     | 
| 
       39 
42 
     | 
    
         
             
                end
         
     | 
| 
       40 
43 
     | 
    
         
             
              end
         
     | 
| 
       41 
44 
     | 
    
         | 
| 
       42 
45 
     | 
    
         
             
              def debug?
         
     | 
| 
       43 
     | 
    
         
            -
                @options[:debug] == true 
     | 
| 
      
 46 
     | 
    
         
            +
                @options[:debug] == true
         
     | 
| 
       44 
47 
     | 
    
         
             
              end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
       46 
49 
     | 
    
         
             
              def include_errors?
         
     | 
| 
         @@ -156,7 +159,7 @@ racc_token_table = { 
     | 
|
| 
       156 
159 
     | 
    
         
             
              :ERROR => 6,
         
     | 
| 
       157 
160 
     | 
    
         
             
              :EQ => 7,
         
     | 
| 
       158 
161 
     | 
    
         
             
              :LBRACE => 8,
         
     | 
| 
       159 
     | 
    
         
            -
              : 
     | 
| 
      
 162 
     | 
    
         
            +
              :META_CONTENT => 9,
         
     | 
| 
       160 
163 
     | 
    
         
             
              :NAME => 10,
         
     | 
| 
       161 
164 
     | 
    
         
             
              :NUMBER => 11,
         
     | 
| 
       162 
165 
     | 
    
         
             
              :PREAMBLE => 12,
         
     | 
| 
         @@ -195,7 +198,7 @@ Racc_token_to_s_table = [ 
     | 
|
| 
       195 
198 
     | 
    
         
             
              "ERROR",
         
     | 
| 
       196 
199 
     | 
    
         
             
              "EQ",
         
     | 
| 
       197 
200 
     | 
    
         
             
              "LBRACE",
         
     | 
| 
       198 
     | 
    
         
            -
              " 
     | 
| 
      
 201 
     | 
    
         
            +
              "META_CONTENT",
         
     | 
| 
       199 
202 
     | 
    
         
             
              "NAME",
         
     | 
| 
       200 
203 
     | 
    
         
             
              "NUMBER",
         
     | 
| 
       201 
204 
     | 
    
         
             
              "PREAMBLE",
         
     | 
| 
         @@ -222,7 +225,7 @@ Racc_token_to_s_table = [ 
     | 
|
| 
       222 
225 
     | 
    
         
             
              "assignment",
         
     | 
| 
       223 
226 
     | 
    
         
             
              "value" ]
         
     | 
| 
       224 
227 
     | 
    
         | 
| 
       225 
     | 
    
         
            -
            Racc_debug_parser =  
     | 
| 
      
 228 
     | 
    
         
            +
            Racc_debug_parser = false
         
     | 
| 
       226 
229 
     | 
    
         | 
| 
       227 
230 
     | 
    
         
             
            ##### State transition tables end #####
         
     | 
| 
       228 
231 
     | 
    
         | 
| 
         @@ -230,7 +233,7 @@ Racc_debug_parser = true 
     | 
|
| 
       230 
233 
     | 
    
         | 
| 
       231 
234 
     | 
    
         
             
            module_eval(<<'.,.,', 'bibtex.y', 32)
         
     | 
| 
       232 
235 
     | 
    
         
             
              def _reduce_1(val, _values, result)
         
     | 
| 
       233 
     | 
    
         
            -
                 result = Bibliography.new 
         
     | 
| 
      
 236 
     | 
    
         
            +
                 result = BibTeX::Bibliography.new 
         
     | 
| 
       234 
237 
     | 
    
         
             
                result
         
     | 
| 
       235 
238 
     | 
    
         
             
              end
         
     | 
| 
       236 
239 
     | 
    
         
             
            .,.,
         
     | 
| 
         @@ -244,7 +247,7 @@ module_eval(<<'.,.,', 'bibtex.y', 33) 
     | 
|
| 
       244 
247 
     | 
    
         | 
| 
       245 
248 
     | 
    
         
             
            module_eval(<<'.,.,', 'bibtex.y', 35)
         
     | 
| 
       246 
249 
     | 
    
         
             
              def _reduce_3(val, _values, result)
         
     | 
| 
       247 
     | 
    
         
            -
                 result = Bibliography.new << val[0] 
         
     | 
| 
      
 250 
     | 
    
         
            +
                 result = BibTeX::Bibliography.new << val[0] 
         
     | 
| 
       248 
251 
     | 
    
         
             
                result
         
     | 
| 
       249 
252 
     | 
    
         
             
              end
         
     | 
| 
       250 
253 
     | 
    
         
             
            .,.,
         
     | 
| 
         @@ -265,7 +268,7 @@ module_eval(<<'.,.,', 'bibtex.y', 38) 
     | 
|
| 
       265 
268 
     | 
    
         | 
| 
       266 
269 
     | 
    
         
             
            module_eval(<<'.,.,', 'bibtex.y', 39)
         
     | 
| 
       267 
270 
     | 
    
         
             
              def _reduce_6(val, _values, result)
         
     | 
| 
       268 
     | 
    
         
            -
                 result = BibTeX:: 
     | 
| 
      
 271 
     | 
    
         
            +
                 result = BibTeX::MetaContent.new(val[0]) 
         
     | 
| 
       269 
272 
     | 
    
         
             
                result
         
     | 
| 
       270 
273 
     | 
    
         
             
              end
         
     | 
| 
       271 
274 
     | 
    
         
             
            .,.,
         
     |