lib/csl/locale/term.rb in csl-1.0.0.pre10 vs lib/csl/locale/term.rb in csl-1.0.0.pre11

- old
+ new

@@ -9,54 +9,113 @@ undef_method :[]= def initialize(attributes = {}) super(attributes) - @registry, children[:term] = Hash.new { |h,k| h[k] = [] }, [] + children[:term] = [] + @registry = Term::Registry.new + @ordinals = Term::Registry.new + yield self if block_given? end alias each each_child - def lookup(query) - query = { :name => query } unless query.is_a?(Hash) + def lookup(name, options = {}) + options[:name] = name = name.to_s - terms = if query[:name].is_a?(Regexp) - registry.select { |name, _| name =~ query[:name] }.flatten(1) + term = registry[name].detect { |t| t.match?(options) } + return term unless term.nil? && options.delete(:'gender-form') + + registry[name].detect { |t| t.match?(options) } + end + alias [] lookup + + def ordinalize_modulo(number, divisor, options = {}) + ordinal = ordinalize(number, options) + return unless ordinal && ordinal.match_modulo?(divisor) + ordinal + end + + def ordinalize(number, options = {}) + return unless has_ordinals? + + if number == :default + options[:name] = 'ordinal' else - registry[query[:name].to_s] + options[:name] = 'ordinal-%02d' % number end + + if options[:form].to_s =~ /^long/i + options.delete :form + options[:name][0,0] = 'long-' + end + + ordinal = ordinals[number].detect { |t| t.match?(options) } + return ordinal unless ordinal.nil? && options.delete(:'gender-form') + + ordinals[number].detect { |t| t.match?(options) } + end - terms.detect { |t| t.match?(query) } + # @return [Boolean] whether or not regular terms are registered at this node + def has_terms? + not registry.empty? end - alias [] lookup - def lookup_modulo(query, divisor) - term = lookup(query) - return if term.nil? || !term.match_modulo?(divisor) - term + # @return [Boolean] whether or not ordinal terms are registered at this node + def has_ordinals? + not ordinals.empty? end + + def has_legacy_ordinals? + has_ordinals? && !ordinals.key?(:default) + end + def drop_ordinals + tmp = ordinals.values.flatten(1) + ordinals.clear + delete_children tmp + end + private # @!attribute [r] registry # @return [Hash] a private registry to map term names to the respective # term objects for quick term look-up attr_reader :registry + # @!attribute [r] ordinals + # @return [Hash] a private registry to map ordinals to the respective + # term objects for quick ordinal look-up + attr_reader :ordinals + def added_child(term) raise ValidationError, "failed to register term #{term.inspect}: name attribute missing" unless term.attribute?(:name) - registry[term[:name]].push(term) + if term.ordinal? + store = ordinals[term.ordinal] + else + store = registry[term[:name]] + end + + delete_children store.select { |value| term.exact_match? value } + + store.push(term) + term end def deleted_child(term) - registry[term[:name]].delete(term) + if term.ordinal? + ordinals[term.ordinal].delete(term) + else + registry[term[:name]].delete(term) + end end + end class Term < Node attr_struct :name, :form, :gender, :'gender-form', :match attr_children :single, :multiple @@ -74,11 +133,11 @@ # # @return [Boolean] whether or not the ordinal term matches the # passed-in divisor. def match_modulo?(divisor) return false unless ordinal? - + case attributes.match when '2-digits' divisor.to_i == 100 when '1-digit' divisor.to_i == 10 @@ -86,28 +145,34 @@ divisor.to_i == 1 else true end end - alias matches_modulo? match_modulo? - + # @return [Boolean] whether or not this term is an ordinal term def ordinal? - /^ordinal(-\d\d+)?$/ === attributes.name + /^(long-)?ordinal(-\d\d+)?$/ === attributes.name end - + + # @return [Fixnum, :default, nil] + def ordinal + return unless ordinal? + return :default if attributes.name == 'ordinal' + attributes.name[/\d+/].to_i + end + def gendered? - !attributes.gender.blank? + not attributes.gender.blank? end def neutral? - !gendered? + not gendered? end def textnode? - !text.blank? + not text.blank? end def singularize return text if textnode? children.single.to_s @@ -198,9 +263,14 @@ else false end end + class Registry < ::Hash + def initialize + super { |h,k| h[k] = [] } + end + end end TextNode.types << Term end end \ No newline at end of file