lib/csl/style/names.rb in csl-1.0.2 vs lib/csl/style/names.rb in csl-1.1.0

- old
+ new

@@ -1,25 +1,32 @@ +# encoding: utf-8 + module CSL class Style class Names < Node + extend InheritsNameOptions - attr_struct :variable, *Schema.attr(:names, :delimiter, :affixes, :font) + attr_struct :variable, *Schema.attr(:delimiter, :affixes, :font) attr_children :name, :'et-al', :label, :substitute + inherits :names_options + alias labels label def initialize(attributes = {}) super(attributes) children[:label] = [] yield self if block_given? end - def delimiter - attributes.fetch(:delimiter, '') + def delimiter(node = nil, style = nil) + attributes.fetch(:delimiter) do + inherited_names_options(node, style)[:delimiter] || '' + end end def has_variable? attribute?(:variable) end @@ -30,39 +37,56 @@ end class Name < Node + extend InheritsNameOptions attr_struct :form, *Schema.attr(:name, :affixes, :font, :delimiter) - attr_defaults :form => 'long', :delimiter => ', ', - :'delimiter-precedes-last' => 'contextual', :initialize => true, - :'sort-separator' => ', ' + # Having default attributes makes inheritance really difficult. + # + # attr_defaults :form => 'long', :delimiter => ', ', + # :'delimiter-precedes-last' => 'contextual', :initialize => true, + # :'sort-separator' => ', ' attr_children :'name-part' + inherits :name_options + alias parts name_part def initialize(attributes = {}) super(attributes) children[:'name-part'] = [] yield self if block_given? end + def count? + attribute?(:form) && attributes[:form] == 'count' + end - def initialize? - attributes[:initialize].to_s !~ /^false$/i + def name_options + attributes_for :form, :initialize, :'initialize-with', :'sort-separator' end + def initialize_without_hyphen? + !root? && root.respond_to?(:initialize_without_hyphen?) && + root.initialize_without_hyphen? + end + def et_al - parent && parent.et_al + @et_al || parent && parent.et_al end + def et_al=(et_al) + @et_al = et_al + end + # @param names [#to_i, Enumerable] the list of names (or its length) - # @return [Boolean] whether or not the should be truncate + # @return [Boolean] whether or not the list should be truncated def truncate?(names, subsequent = false) names = names.length if names.respond_to?(:length) limit = truncate_when(subsequent) !limit.zero? && names.to_i >= limit @@ -77,54 +101,156 @@ names.take limit end def truncate_when(subsequent = false) if subsequent && attribute?(:'et-al-subsequent-min') - attribute[:'et-al-subsequent-min'].to_i + attributes[:'et-al-subsequent-min'].to_i else - attribute[:'et-al-min'].to_i + attributes[:'et-al-min'].to_i end end def truncate_at(subsequent = false) if subsequent && attribute?(:'et-al-subsequent-use-first') - attribute[:'et-al-subsequent-use-first'].to_i + attributes.fetch(:'et-al-subsequent-use-first', 1).to_i else - attribute[:'et-al-use-first'].to_i + attributes.fetch(:'et-al-use-first', 1).to_i end end + def truncate_at!(at) + attributes[:'et-al-use-first'] = at.to_i + self + end + + def truncate_when!(pos) + attributes[:'et-al-min'] = pos.to_i + self + end + + def truncate_subsequent_at!(at) + attributes[:'et-al-subsequent-use-first'] = at.to_i + self + end + + def truncate_subsequent_when!(pos) + attributes[:'et-al-subsequent-min'] = pos.to_i + self + end + # @return [String] the delimiter between family and given names # in sort order def sort_separator - attributes[:'sort-separator'].to_s + attributes[:'sort-separator'] || ', ' end # @return [String] the delimiter between names def delimiter - attributes[:delimiter].to_s + attributes[:delimiter] || ', ' end def name_as_sort_order? attribute?(:'name-as-sort-order') end + def name_as_sort_order_at?(position) + return false unless name_as_sort_order? + all_names_as_sort_order? || position == 1 && first_name_as_sort_order? + end + def name_as_sort_order attributes[:'name-as-sort-order'].to_s end alias sort_order name_as_sort_order def first_name_as_sort_order? - attributes[:'name-as-sort-order'].to_s =~ /^first$/i + !!(attributes[:'name-as-sort-order'].to_s =~ /^first$/i) end def all_names_as_sort_order? - attributes[:'name-as-sort-order'].to_s =~ /^all$/i + !!(attributes[:'name-as-sort-order'].to_s =~ /^all$/i) end - + def first_name_as_sort_order! + attributes[:'name-as-sort-order'] = 'first' + self + end + + def all_names_as_sort_order! + attributes[:'name-as-sort-order'] = 'all' + self + end + + def delimiter_precedes_et_al?(names) + names = names.length if names.respond_to?(:length) + + case + when delimiter_never_precedes_et_al? + false + when delimiter_always_precedes_et_al? + true + when delimiter_precedes_et_al_after_inverted_name? + name_as_sort_order_at?(names.to_i) + else + names.to_i > 1 + end + end + + # @return [Boolean] whether or not the delimmiter should + # always be inserted before et-al + def delimiter_always_precedes_et_al? + !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^always$/i) + end + + # Set the :'delimiter-precedes-et-al' attribute to 'always'. + # @return [self] self + def delimiter_always_precedes_et_al! + attributes[:'delimiter-precedes-et-al'] = 'always' + self + end + + alias delimiter_precedes_et_al! delimiter_always_precedes_et_al! + + + # @return [Boolean] whether or not the delimiter should + # never be inserted before et-al + def delimiter_never_precedes_et_al? + !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^never$/i) + end + + # Set the :'delimiter-precedes-et-al' attribute to 'never' + # @return [self] self + def delimiter_never_precedes_et_al! + attributes[:'delimiter-precedes-et-al'] = 'never' + self + end + + # @return [Boolean] whether or not the delimtier should + # be inserted between before et-al depending on the + # number of names rendered + def delimiter_contextually_precedes_et_al? + return true unless attribute?[:'delimiter-precedes-et-al'] + !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^contextual/i) + end + + # Set the :'delimiter-precedes-et-al' attribute to 'contextual' + # @return [self] self + def delimiter_contextually_precedes_et_al! + attributes[:'delimiter-precedes-et-al'] = 'contextual' + self + end + + def delimiter_precedes_et_al_after_inverted_name? + !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^after-inverted-name/i) + end + + def delimiter_precedes_et_al_after_inverted_name! + attributes[:'delimiter-precedes-et-al'] = 'after-inverted-name' + self + end + # @param names [#to_i, Enumerable] the list of names (or its length) # @return [Boolean] whether or not the delimiter will be inserted between # the penultimate and the last name def delimiter_precedes_last?(names) names = names.length if names.respond_to?(:length) @@ -134,11 +260,11 @@ true when delimiter_never_precedes_last? false when delimiter_always_precedes_last? true - when delimiter_precedeces_last_after_inverted_name? + when delimiter_precedes_last_after_inverted_name? if name_as_sort_order? all_names_as_sort_order? || names.to_i == 2 else false end @@ -178,10 +304,11 @@ end # @return [Boolean] whether or not the should be inserted between the # penultimate and the last name depending on the number of names def delimiter_contextually_precedes_last? + return true unless attribute?(:'delimiter-precedes-last') !!(attributes[:'delimiter-precedes-last'].to_s =~ /^contextual/i) end # Set the :'delimiter-precedes-last' attribute to 'contextual' # @return [self] self @@ -201,29 +328,41 @@ def ellipsis? attributes[:'et-al-use-last'].to_s =~ /^true$/ end + def ellipsis + "#{delimiter}… " + end + def connector c = attributes[:and] c == 'symbol' ? '&' : c end + + def connector=(c) + attributes[:and] = c + end end class NamePart < Node has_no_children attr_struct :name, :'text-case', *Schema.attr(:affixes, :font) + + def name + attributes[:name] + end end class EtAl < Node has_no_children - attr_struct :term, *Schema.attr(:affixes, :font) + attr_struct :term, :'text-case', *Schema.attr(:affixes, :font) attr_defaults :term => 'et-al' end class Substitute < Node end end -end \ No newline at end of file +end