lib/citeproc/names.rb in citeproc-1.0.0.pre5 vs lib/citeproc/names.rb in citeproc-1.0.0.pre6
- old
+ new
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
module CiteProc
-
+
# Names consist of several dependent parts of strings. Simple personal names
# are composed of family and given elements, containing respectively the
# family and given name of the individual.
#
# Name.new(:family => 'Doe', :given => 'Jane')
@@ -30,17 +30,17 @@
# name (e.g., for Hungarian names). This behavior can be prompted by
# including activating static-ordering:
#
# Name.new(:family => 'Murakami', :given => 'Haruki').to_s
# #-> "Haruki Murakami"
- #
+ #
# Name.new(:family => 'Murakami', :given => 'Haruki').static_order!.to_s
# #-> "Murakami Haruki"
class Name
-
+
extend Forwardable
-
+
include Attributes
include Comparable
# Class instance variables
@@ -57,28 +57,28 @@
:'name-as-sort-order' => false,
:'demote-non-dropping-particle' => :never,
:'sort-separator' => ', ',
:'initialize-with' => nil
}.freeze
-
+
@parts = [:family, :given,:literal, :suffix, :'dropping-particle',
:'non-dropping-particle'].freeze
-
+
class << self
attr_reader :defaults, :parts, :romanesque
end
-
+
# Method generators
-
+
# @!attribute [r] options
# @return the name's formatting options
attr_reader :options
-
+
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)
wa, wm = "#{a}=", "#{m}="
@@ -88,15 +88,15 @@
alias_method(pa, pm) if method_defined?(pm)
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/ }
-
+
# 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|
Name.parts.each do |part|
@@ -105,47 +105,47 @@
end
self
end
end
end
-
-
+
+
# Instance methods
-
+
def initialize(attributes = {}, options = {})
@options = Name.defaults.merge(options)
@sort_prefix = (/^(the|an?|der|die|das|eine?|l[ae])\s+|^l\W/i).freeze
-
+
merge(attributes)
-
+
yield self if block_given?
end
-
+
def initialize_copy(other)
@attributes = other.attributes.deep_copy
@options = other.options.dup
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.
#
# @return [Boolean] whether or not the name is romanesque
def romanesque?
!!([given, family].join.gsub(Variable.markup, '') =~ Name.romanesque)
end
-
+
alias byzantine? romanesque?
-
+
# @return [Boolean] whether or not the name should be printed in static order
def static_order?
static_ordering? || !romanesque?
end
@@ -164,36 +164,36 @@
# @return [Boolean] whether or not the name will be printed in sort-order
def sort_order?
!!(options[:'name-as-sort-order'].to_s =~ /^(y(es)?|always|t(rue)?)$/i)
end
-
+
def display_order?
!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
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
self
end
-
+
# @return [String] the current sort separator
def sort_separator
options[:'sort-separator']
end
-
+
alias comma sort_separator
-
+
# @return [Boolean] whether or not the short form will be used for printing
def short_form?
options[:form].to_s =~ /short/i
end
@@ -213,23 +213,23 @@
# @return [self]
def long_form!
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 demote_non_dropping_particle?
always_demote_non_dropping_particle? ||
!!(sort_order? && options[:'demote-non-dropping-particle'] =~ /^sort(-only)?$/i)
end
alias demote_particle? demote_non_dropping_particle?
-
+
def never_demote_non_dropping_particle?
!!(options[:'demote-non-dropping-particle'] =~ /^never$/i)
end
def never_demote_non_dropping_particle!
@@ -263,11 +263,11 @@
# comparison; nil if the name cannot be compared to the passed-in object
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
case
when literal?
literal.to_s
@@ -284,16 +284,16 @@
dropping_particle].compact_join(' '), suffix].compact_join(comma)
else
[family, [given, dropping_particle, particle].compact_join(' '),
suffix].compact_join(comma)
- end
+ end
else
[particle, family].compact_join(' ')
end
end
-
+
# @return [Array<String>] an ordered array of formatted name parts to be used for sorting
def sort_order
case
when literal?
[literal.to_s.sub(sort_prefix, '')]
@@ -301,56 +301,56 @@
[[particle, family].compact_join(' '), dropping_particle, given, suffix].map(&:to_s)
else
[family, [particle, dropping_particle].compact_join(' '), given, suffix].map(&:to_s)
end
end
-
+
# @return [String] the name as a string stripped off all markup
def strip_markup
gsub(Variable.markup, '')
end
-
+
# @return [self] the name with all parts stripped off markup
def strip_markup!
gsub!(Variable.markup, '')
end
-
+
# @return [Array<String>] the sort order array stripped off markup and downcased
def sort_order_downcase
sort_order.map { |s| s.downcase.gsub(Variable.markup, '') }
end
-
+
# @return [String] a human-readable representation of the name object
def inspect
"#<CiteProc::Name #{to_s.inspect}>"
end
-
+
private
-
+
attr_reader :sort_prefix
-
+
end
-
-
-
+
+
+
# Represents a {Variable} containing an ordered list of {Name}
# objects. The names can be formatted using CSL formatting options (see
# {Names.defaults} for details).
class Names < Variable
-
+
@defaults = {
:and => ' & ',
:delimiter => ', ',
:'delimiter-precedes-last' => :contextual,
:'et-al' => 'et al.',
:'et-al-min' => 5,
:'et-al-use-first' => 3,
:'et-al-subsequent-min' => 5,
:'et-al-subsequent-use-first' => 3
}.freeze
-
+
class << self
# @!attribute [r] defaults
# @example
# {
@@ -386,13 +386,13 @@
# :'et-al-subsequent-use-first' => 3
# # See above. Abbreviation rules for subsequent cites (cites
# # referencing earlier cited items)
# }
#
- # @return [Hash] the Names' default formatting options
+ # @return [Hash] the Names' default formatting options
attr_reader :defaults
-
+
# Parses the passed-in string and returns a Names object. Behaves like
# parse but returns nil for bad input without raising an error.
#
# @see .parse!
#
@@ -401,11 +401,11 @@
def parse(names)
parse!(names)
rescue ParseError
nil
end
-
+
# Parses the passed-in string and returns a Names object.
#
# @param names [String] the name or names to be parsed
# @return [Names] the parsed names
#
@@ -415,23 +415,23 @@
rescue
raise ParseError, $!.message
end
end
-
+
include Enumerable
# @!attribute [r] options
# @return [Hash] the current formatting options
attr_reader :options
-
+
alias names value
-
+
# Don't expose value/names writer
undef_method :value=
-
+
# Delegate bang! methods to each name
Name.instance_methods(false).each do |m|
if m.to_s.end_with?('!')
define_method(m) do |*arguments, &block|
names.each do |name|
@@ -439,44 +439,44 @@
end
self
end
end
end
-
+
# Names quack sorta like an Array
def_delegators :names, :length, :empty?, :[], :join
-
+
# Some delegators should return self
# @!method push(name)
# Appends the given name to the list of names.
# @param name [Name] a name
# @return [self]
# @!method unshift(name)
# Inserts the given name at the beginning of the list of names.
# @param name [Name] a name
- # @return [self]
+ # @return [self]
[:<<, :push, :unshift].each do |m|
define_method(m) do |*arguments, &block|
names.send(m, *arguments, &block)
self
end
end
-
+
def initialize(*arguments)
@options = Names.defaults.dup
super(arguments.flatten(1))
end
-
+
def initialize_copy(other)
@options, @value = other.options.dup, other.value.map(&:dup)
end
-
+
def replace(values)
@value = []
-
+
[*values].each do |value|
case
when value.is_a?(Name)
@value << value
when value.respond_to?(:each_pair), value.respond_to?(:to_hash)
@@ -486,68 +486,68 @@
@value.concat Namae.parse!(value.to_s)
rescue
raise TypeError, $!.message
end
else
- raise TypeError, "failed to create names from #{value.inspect}"
+ raise TypeError, "failed to create names from #{value.inspect}"
end
end
-
+
self
end
-
+
# @return [Fixnum] the maximum number of names that should be printed
def max_names
[length, options[:'et-al-use-first'].to_i.abs].min
end
-
+
# @return [Boolean] whether or not the Names should be truncate
def truncate?
length >= options[:'et-al-min'].to_i.abs
end
-
+
# @return [Boolean] whether ot not the Names, if printed on subsequent
# cites, should be truncated
def truncate_subsequent?
length >= options[:'et-al-subsequent-min'].to_i
end
-
+
# @return [String] the delimiter between names
def delimiter
options[:delimiter]
end
-
+
# @return [String] the delimiter between the penultimate and last name
# @see #connector
# @see #delimiter_precedes_last?
def last_delimiter
if delimiter_precedes_last?
[delimiter, connector].compact.join.squeeze(' ')
else
connector
end
end
-
+
# @return [String] the delimiter between the last name printed name and
# the 'and others' term
def truncated_delimiter
max_names > 1 ? delimiter : ' '
end
-
+
# @return [Boolean] whether or not the delimiter will be inserted between
# the penultimate and the last name
def delimiter_precedes_last?
case
when delimiter_never_precedes_last?
- false
+ false
when delimiter_always_precedes_last?
true
else
length > 2
end
end
-
+
# @return [Boolean] whether or not the should always be inserted between
# the penultimate and the last name
def delimiter_always_precedes_last?
!!(options[:'delimiter-precedes-last'].to_s =~ /^always$/i)
end
@@ -559,11 +559,11 @@
self
end
alias delimiter_precedes_last! delimiter_always_precedes_last!
-
+
# @return [Boolean] whether or not the should never be inserted between
# the penultimate and the last name
def delimiter_never_precedes_last?
!!(options[:'delimiter-precedes-last'].to_s =~ /^never$/i)
end
@@ -585,71 +585,78 @@
# @return [self] self
def delimiter_contextually_precedes_last!
options[:'delimiter-precedes-last'] = :contextual
self
end
-
+
# @return [String] the connector between the penultimate and the last name
def connector
options[:and]
end
-
+
# @return [false] Names are non-numeric Variables
def numeric?
false
end
+ # @return [Boolean] whether or not the variable holds more than one Name
+ def plural?
+ length > 1
+ end
+
# Calls a block once for each name. If no block is given, an enumerator
# is returned instead.
#
# @yieldparam name [Name] a name in the list
- # @return [self,Enumerator] self or an enumerator if no block is given
+ # @return [self,Enumerator] self or an enumerator if no block is given
def each
if block_given?
names.each(&Proc.new)
self
else
to_enum
end
end
-
+
# Compares two lists of Names.
# @param other [(Name)] a list of names
# @return [Fixnum,nil] -1, 0, or 1 depending on the result of the
# comparison; or nil if the two objects cannot be compared
def <=>(other)
return nil unless other.respond_to?(:to_a)
to_a <=> other.to_a
end
-
+
+ alias to_i length
+
# Converts the list of names into a formatted string depending on the
# current formatting options.
# @return [String] the formatted list of names
def to_s
case
- when truncate?
+ when truncate?
[names[0...max_names].join(delimiter), options[:'et-al']].join(truncated_delimiter)
when length < 2
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 ')
end
-
+
# @return [Array<Hash>] the list of names converted to hash objects
def to_citeproc
map(&:to_citeproc)
end
-
+
# @return [String] a human-readable representation of the Names object
def inspect
"#<CiteProc::Names #{to_s.inspect}>"
end
-
+
end
-
+
end