lib/option_initializer.rb in option_initializer-1.5.0 vs lib/option_initializer.rb in option_initializer-1.5.1

- old
+ new

@@ -1,59 +1,96 @@ require 'option_initializer/version' require 'set' -module OptionInitializer - class OptionInitializingTemplate - attr_reader :options - alias to_h options - - def initialize base, options, need_validation - validate options if need_validation - @base = base - @options = options +unless Class.respond_to?(:|) + class Class + def | other_class + unless other_class.is_a?(Class) + raise TypeError, "wrong argument type (expected: Class)" + end + OptionInitializer::ClassMatch.new(self, other_class) end + end +else + Kernel.warn "Class already has `|' method. OptionInitializer will not override its behavior." +end - def new *args, &block - args = args.dup - opts = @options +# @private +class OptionInitializingTemplate + attr_reader :options + alias to_h options - # Convention. Deal with it. - if args.last.is_a?(Hash) - validate args.last - opts = opts.merge(args.last) - args.pop - else - opts = opts.dup - end + def initialize base, options, need_validation + validate options if need_validation + @base = base + @options = options + end - opts.instance_eval do - def option_validated? - true - end + def new *args, &block + args = args.dup + opts = @options + + # Convention. Deal with it. + if args.last.is_a?(Hash) + validate args.last + opts = opts.merge(args.last) + args.pop + else + opts = opts.dup + end + + opts.instance_eval do + def option_validated? + true end - args << opts + end + args << opts - @base.new(*args, &block) + @base.new(*args, &block) + end + + def merge opts + validate opts + self.class.new @base, @options.merge(opts), false + end + + def validate hash + avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s| + self.class.const_get(s) + } + hash.each do |k, v| + avals[k] && avals[k].call(v) + vals[k] && vals[k].call(v) + vals[nil] && vals[nil].call(k, v) end + end +end - def merge opts - validate opts - self.class.new @base, @options.merge(opts), false +module OptionInitializer + class ClassMatch + def initialize *classes + @classes = Set[*classes] end - def validate hash - avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s| - self.class.const_get(s) - } - hash.each do |k, v| - avals[k] && avals[k].call(v) - vals[k] && vals[k].call(v) - vals[nil] && vals[nil].call(k, v) + def | other_class + unless other_class.is_a?(Class) + raise TypeError, "wrong argument type (expected: Class)" end + ClassMatch.new(*@classes.union([other_class])) end + + def match object + @classes.any? { |k| object.is_a? k } + end + + def to_s + a = @classes.map(&:to_s) + [a[0...-1].join(', '), a.last].reject(&:empty?).join(', or ') + end end + # @private module MethodCallShortcut def method_missing sym, *args, &block # 1.8 if @base.instance_methods.map(&:to_sym).include?(sym) new.send sym, *args, &block @@ -77,10 +114,11 @@ vals[nil] && vals[nil].call(k, v) end options end + # @private def self.included base unless base.constants.map(&:to_sym).include?(:OptionInitializing) base.const_set :OptionInitializing, oi = OptionInitializingTemplate.dup oi.class_eval do const_set :VALIDATORS, {} @@ -118,13 +156,17 @@ when Range raise ArgumentError, "invalid number of arguments specified for #{k}" if v.begin < 0 when Set raise ArgumentError, "empty set of values specified for #{k}" if v.length == 0 when Array - raise ArgumentError, "invalid option definition: `#{v}'" unless v.all? { |e| e.is_a?(Class) || e.is_a?(Set) } + unless v.all? { |e| [Class, Set, ClassMatch].any? { |kl| e.is_a?(kl) } } + raise ArgumentError, "invalid option definition: `#{v}'" + end when Class, :*, :& # noop + when ClassMatch + # noop else raise ArgumentError, "invalid option definition: `#{v}'" end [k.to_sym, v] } @@ -189,20 +231,30 @@ raise TypeError, "wrong argument type #{e.class} (expected #{c})" unless e.is_a?(c) when Set unless c.include?(e) raise ArgumentError, "invalid option value: `#{e}' (expected one of #{c.to_a.inspect})" end + when ClassMatch + unless c.match e + raise TypeError, "wrong argument type #{e.class} (expected #{c})" + end end end end } when Class vals[sym] = proc { |v| if !v.is_a?(nargs) raise TypeError, "wrong argument type #{v.class} (expected #{nargs})" end } + when ClassMatch + vals[sym] = proc { |v| + unless nargs.match v + raise TypeError, "wrong argument type #{v.class} (expected #{nargs})" + end + } end end # Class methods pairs.each do |pair| @@ -232,10 +284,10 @@ end elsif b raise ArgumentError, "block not expected" else case nargs - when 1, Class, Set + when 1, Class, Set, ClassMatch if v.length == 1 merge(sym => v.first) else raise ArgumentError, "wrong number of arguments (#{v.length} for 1)" end