lib/citeproc/names.rb in citeproc-1.0.0.pre12 vs lib/citeproc/names.rb in citeproc-1.0.0

- old
+ new

@@ -42,23 +42,21 @@ include Attributes include Comparable # Class instance variables - @romanesque = CiteProc.oniguruma { - '^[\p{Latin}\p{Greek}\p{Cyrillic}\p{Hebrew}\p{Armenian}\p{Georgian}\p{Common}]*$' - } || CiteProc.ruby_18 { - # @todo improve fallback range - /^[a-zA-Zäöüéè\s[:punct:]]*$/u - } + @romanesque = + /^[\p{Latin}\p{Greek}\p{Cyrillic}\p{Hebrew}\p{Armenian}\p{Georgian}\p{Common}]*$/ # Default formatting options @defaults = { :form => 'long', :'name-as-sort-order' => false, :'demote-non-dropping-particle' => :never, :'sort-separator' => ', ', + :initialize => true, + :'initialize-with-hyphen' => true, :'initialize-with' => nil }.freeze @parts = [:family, :given,:literal, :suffix, :'dropping-particle', :'non-dropping-particle'].freeze @@ -73,10 +71,12 @@ # @!attribute [r] options # @return the name's formatting options attr_reader :options + attr_reader :sort_prefix + attr_predicates :'comma-suffix', :'static-ordering', :multi, *@parts # Aliases [[:particle, :'non_dropping_particle']].each do |a, m| alias_method(a, m) if method_defined?(m) @@ -90,12 +90,13 @@ pa, pm = "has_#{a}?", "has_#{m}?" alias_method(pa, pm) if method_defined?(pm) end # Names quack sorta like a String - def_delegators :to_s, :=~, :===, - *String.instance_methods(false).reject { |m| m =~ /^\W|!$|to_s|replace|first|last/ } + def_delegators :to_s, :=~, :===, *String.instance_methods(false).reject { |m| + m.to_s =~ /^[\W_]|[!=_]$|^(to_s|inspect|replace|first|last|dup|clone)$/ + } # Delegate bang! methods to each field's value String.instance_methods(false).each do |m| if m.to_s.end_with?('!') define_method(m) do |*arguments, &block| @@ -124,16 +125,28 @@ @attributes = other.attributes.deep_copy @options = other.options.dup end + # Resets the object's options to the default settings. + # @return [self] + def reset! + @options = Name.defaults.dup + end + + # Returns a copy of the name object with all options + # reset to their default settings. + # @return [Name] a copy of the name with default options + def reset + dup.reset! + end + # @return [Boolean] whether or not the Name looks like it belongs to a person def personal? !empty? && !literal? end - # A name is `romanesque' if it contains only romanesque characters. This # should be the case for the majority of names written in latin- or # greek-based script. It will be false, for example, for names written # in Chinese, Japanese, Arabic or Hebrew. # @@ -171,19 +184,19 @@ !sort_order? end # Sets the name to use sort-order. The reverse of {#display_order!}. # @return [self] - def sort_order! - options[:'name-as-sort-order'] = true + def sort_order!(toggle = true) + options[:'name-as-sort-order'] = !!toggle self end # Sets the name to use display-order. The reverse of {#sort_order!}. # @return [self] - def display_order! - options[:'name-as-sort-order'] = false + def display_order!(toggle = true) + options[:'name-as-sort-order'] = !toggle self end # @return [String] the current sort separator def sort_separator @@ -198,11 +211,11 @@ end # Use short form for printing the name # @return [self] def short_form! - options[:form] = :short + options[:form] = 'short' self end # @return [Boolean] whether or not the long form will be used for printing def long_form? @@ -210,19 +223,46 @@ end # Use long form for printing the name # @return [self] def long_form! - options[:form] = :long + options[:form] = 'long' self end # @return [Boolean] whether or not initials will be used for printing def initials? !!options[:'initialize-with'] && personal? && romanesque? end + def initialize_with + options[:'initialize-with'].to_s + end + + def initialize_existing_only? + options[:initialize].to_s == 'false' + end + + def initialize_without_hyphen? + !options[:'initialize-with-hyphen'] + end + + def initialize_without_hyphen! + options[:'initialize-with-hyphen'] = false + end + + def initials + case + when !initials? + given + when initialize_existing_only? + existing_initials_of given + else + initials_of given + end + end + def demote_non_dropping_particle? always_demote_non_dropping_particle? || !!(sort_order? && options[:'demote-non-dropping-particle'] =~ /^sort(-only)?$/i) end @@ -264,35 +304,40 @@ def <=>(other) return nil unless other.respond_to?(:sort_order_downcase) sort_order_downcase <=> other.sort_order_downcase end - # @return [String] the name formatted according to the current options def to_s + [given, family].compact_join(' ') + end + + # @return [String] the name formatted according to the current options + def format case when literal? literal.to_s when static_order? - [family, given].compact.join(' ') + [family, initials].compact.join(' ') when !short_form? case when !sort_order? - [[given, dropping_particle, particle, family].compact_join(' '), + [[initials, dropping_particle, particle, family].compact_join(' '), suffix].compact_join(comma_suffix? ? comma : ' ') when !demote_particle? - [[particle, family].compact_join(' '), [given, + [[particle, family].compact_join(' '), [initials, dropping_particle].compact_join(' '), suffix].compact_join(comma) else - [family, [given, dropping_particle, particle].compact_join(' '), + [family, [initials, dropping_particle, particle].compact_join(' '), suffix].compact_join(comma) end else [particle, family].compact_join(' ') end end + alias print format # @return [Array<String>] an ordered array of formatted name parts to be used for sorting def sort_order case when literal? @@ -324,12 +369,46 @@ "#<CiteProc::Name #{to_s.inspect}>" end private - attr_reader :sort_prefix + def filter_key(key) + key = key.to_s.tr('_', '-') + key = 'non-dropping-particle' if key == 'particle' + super key + end + def initials_of(string) + string = string.dup + + string.gsub!(/([[:upper:]])[^[:upper:]\s-]*\s*/, "\\1#{initialize_with}") + + initialize_hyphen!(string) + + string.strip! + string + end + + def initialize_hyphen!(string) + if initialize_without_hyphen? + string.tr!('-', '') + else + string.gsub!(/\s*-/, '-') + end + end + + def existing_initials_of(string) + string = string.dup + + string.gsub!(/([[:upper:]])([[:upper:]])/, '\1 \2') + string.gsub!(/\b([[:upper:]])\b[^[:alpha:]-]*/, "\\1#{initialize_with}") + + initialize_hyphen!(string) + + string.strip! + string + end end @@ -481,11 +560,11 @@ @value << value when value.respond_to?(:each_pair), value.respond_to?(:to_hash) @value << Name.new(value) when value.respond_to?(:to_s) begin - @value.concat Namae.parse!(value.to_s) + @value.concat Namae.parse!(value.to_s).map { |n| Name.new n } rescue raise TypeError, $!.message end else raise TypeError, "failed to create names from #{value.inspect}" @@ -633,19 +712,19 @@ # @return [String] the formatted list of names def to_s case when truncate? [names[0...max_names].join(delimiter), options[:'et-al']].join(truncated_delimiter) - when length < 2 + when length < 3 names.join(last_delimiter) else [names[0...-1].join(delimiter), names[-1]].join(last_delimiter) end end # @return [String] the names in a BibTeX-compatible format def to_bibtex - map { |n| n.dup.sort_order! }.join(' and ') + map { |n| n.dup.sort_order!.format }.join(' and ') end # @return [Array<Hash>] the list of names converted to hash objects def to_citeproc map(&:to_citeproc)