lib/roxml/options.rb in Empact-roxml-2.2 vs lib/roxml/options.rb in Empact-roxml-2.3.0

- old
+ new

@@ -49,15 +49,15 @@ end def to_ref(args, type, name) case type when :attr - XMLAttributeRef.new(nil, to_hash_args(args, type, name)) + XMLAttributeRef.new(to_hash_args(args, type, name)) when :text - XMLTextRef.new(nil, to_hash_args(args, type, name)) + XMLTextRef.new(to_hash_args(args, type, name)) when Symbol - XMLTextRef.new(nil, to_hash_args(args, type, name)) + XMLTextRef.new(to_hash_args(args, type, name)) else raise ArgumentError, "Missing key description #{{:type => type, :name => name}.pp_s}" end end @@ -77,18 +77,45 @@ end end end class Opts # :nodoc: - attr_reader :name, :type, :hash, :blocks + attr_reader :name, :type, :hash, :blocks, :default, :accessor + class << self + def silence_xml_name_warning? + @silence_xml_name_warning || (ROXML.const_defined?('SILENCE_XML_NAME_WARNING') && ROXML::SILENCE_XML_NAME_WARNING) + end + + def silence_xml_name_warning! + @silence_xml_name_warning = true + end + end + def initialize(sym, *args, &block) + @accessor = sym @opts = extract_options!(args) + @default = @opts.delete(:else) - @opts.reverse_merge!(:from => sym.to_s, :as => [], :else => nil, :in => nil) + @opts.reverse_merge!(:as => [], :in => nil) @opts[:as] = [*@opts[:as]] + @type = extract_type(args) + @opts[:as] << :bool if @accessor.to_s.ends_with?('?') + + if @type.respond_to?(:xml_name?) && @type.xml_name? + unless self.class.silence_xml_name_warning? + warn "WARNING: As of 2.3, a breaking change has been in the naming of sub-objects. " + + "ROXML now considers the xml_name of the sub-object before falling back to the accessor name of the parent. " + + "Use :from on the parent declaration to override this behavior. Set ROXML::SILENCE_XML_NAME_WARNING to avoid this message." + self.class.silence_xml_name_warning! + end + @opts[:from] ||= @type.tag_name + else + @opts[:from] ||= variable_name + end + @blocks = collect_blocks(block, @opts[:as]) @name = @opts[:from].to_s @name = @name.singularize if hash? || array? if hash? && (hash.key.name? || hash.value.name?) @@ -96,18 +123,18 @@ end raise ArgumentError, "Can't specify both :else default and :required" if required? && default end + def variable_name + accessor.to_s.ends_with?('?') ? accessor.to_s.chomp('?') : accessor.to_s + end + def hash @hash ||= HashDesc.new(@opts.delete(:hash), name) if hash? end - def default - @opts[:else] - end - def hash? @type == :hash end def content? @@ -129,20 +156,72 @@ def required? @opts[:required] end private + BLOCK_TO_FLOAT = lambda do |val| + if val.is_a? Array + val.collect do |v| + Float(v) + end + else + Float(val) + end + end + + BLOCK_TO_INT = lambda do |val| + if val.is_a? Array + val.collect do |v| + Integer(v) + end + else + Integer(val) + end + end + + TRUE_VALS = %w{TRUE True true 1} + FALSE_VALS = %w{FALSE False false 0} + BLOCK_SHORTHANDS = { - :integer => lambda {|val| Integer(val) }, - Integer => lambda {|val| Integer(val) }, - :float => lambda {|val| Float(val) }, - Float => lambda {|val| Float(val) } + :integer => BLOCK_TO_INT, + Integer => BLOCK_TO_INT, + :float => BLOCK_TO_FLOAT, + Float => BLOCK_TO_FLOAT, + :bool => nil, + :bool_standalone => lambda do |val| + if TRUE_VALS.include? val + true + elsif FALSE_VALS.include? val + false + else + nil + end + end, + + :bool_combined => lambda do |val| + if TRUE_VALS.include? val + true + elsif FALSE_VALS.include? val + false + else + val + end + end } def collect_blocks(block, as) shorthands = as & BLOCK_SHORTHANDS.keys - raise ArgumentError, "multiple block shorthands supplied #{shorthands.map(&:to_s).join(', ')}" if shorthands.size > 1 - [BLOCK_SHORTHANDS[shorthands.first], block].compact + if shorthands.size > 1 + raise ArgumentError, "multiple block shorthands supplied #{shorthands.map(&:to_s).join(', ')}" + end + + shorthand = shorthands.first + if shorthand == :bool + # if a second block is present, and we can't coerce the xml value + # to bool, we need to be able to pass it to the user-provided block + shorthand = block ? :bool_combined : :bool_standalone + end + [BLOCK_SHORTHANDS[shorthand], block].compact end def extract_options!(args) opts = args.extract_options! unless (opts.keys & HASH_KEYS).empty? \ No newline at end of file