lib/option_initializer.rb in option_initializer-1.3.0 vs lib/option_initializer.rb in option_initializer-1.5.0
- old
+ new
@@ -1,14 +1,13 @@
-require "option_initializer/version"
+require 'option_initializer/version'
+require 'set'
module OptionInitializer
class OptionInitializingTemplate
attr_reader :options
alias to_h options
- const_set :VALIDATORS, []
-
def initialize base, options, need_validation
validate options if need_validation
@base = base
@options = options
end
@@ -40,14 +39,17 @@
validate opts
self.class.new @base, @options.merge(opts), false
end
def validate hash
- self.class.const_get(:VALIDATORS).each do |validator|
- hash.each do |k, v|
- validator.call k, v
- end
+ 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
module MethodCallShortcut
@@ -63,37 +65,44 @@
def validate_options options
raise TypeError,
"wrong argument type #{options.class} (expected Hash)" unless
options.is_a?(Hash)
- return if options.respond_to?(:option_validated?)
- validators = self.class.const_get(:OptionInitializing).const_get(:VALIDATORS)
- validators.each do |validator|
- options.each do |k, v|
- validator.call k, v
- end
+ return if options.respond_to?(:option_validated?) && options.option_validated?
+ avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s|
+ self.class.const_get(:OptionInitializing).const_get(s)
+ }
+ options.each do |k, v|
+ avals[k] && avals[k].call(v)
+ vals[k] && vals[k].call(v)
+ vals[nil] && vals[nil].call(k, v)
end
options
end
def self.included base
unless base.constants.map(&:to_sym).include?(:OptionInitializing)
- base.const_set :OptionInitializing, OptionInitializingTemplate.dup
+ base.const_set :OptionInitializing, oi = OptionInitializingTemplate.dup
+ oi.class_eval do
+ const_set :VALIDATORS, {}
+ const_set :ARG_VALIDATORS, {}
+ end
end
base.class_eval do
class << self
[:option_initializer, :option_initializer!, :option_validator].each do |m|
undef_method(m) if method_defined?(m)
end
end
- def base.option_validator &block
+ def base.option_validator sym = nil, &block
raise ArgumentError, "block must be given" unless block
- raise ArgumentError, "invalid arity (expected: 2)" unless block.arity == 2
+ a = sym ? 1 : 2
+ raise ArgumentError, "invalid arity (expected: #{a})" unless block.arity == a
oi = self.const_get(:OptionInitializing)
- oi.const_get(:VALIDATORS).push block
+ oi.const_get(:VALIDATORS)[sym] = block
end
def base.option_initializer *syms
oi = self.const_get(:OptionInitializing)
@@ -101,20 +110,102 @@
case sym
when Symbol, String
arr << [sym.to_sym, 1]
when Hash
arr.concat sym.map { |k, v|
- unless (v.is_a?(Fixnum) && v > 0) || (v.is_a?(Range) && v.begin > 0) || v == :block
- raise ArgumentError, "invalid number of arguments specified for #{k}"
+ case v
+ when Fixnum
+ raise ArgumentError, "invalid number of arguments specified for #{k}" if v <= 0
+ 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) }
+ when Class, :*, :&
+ # noop
+ else
+ raise ArgumentError, "invalid option definition: `#{v}'"
end
[k.to_sym, v]
}
else
- raise ArgumentError, "invalid option specification"
+ raise ArgumentError, "invalid option definition"
end
}
+ # Setup validators
+ vals = oi.const_get(:ARG_VALIDATORS)
+ pairs.each do |pair|
+ sym, nargs = pair
+ case nargs
+ when :&
+ vals[sym] = proc { |v|
+ if !v.is_a?(Proc)
+ raise TypeError, "wrong argument type #{v.class} (expected Proc)"
+ end
+ }
+ when 1
+ # good to go
+ vals.delete sym
+ when :*
+ vals[sym] = proc { |v|
+ if !v.is_a?(Array)
+ raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
+ end
+ }
+ when Fixnum
+ vals[sym] = proc { |v|
+ if !v.is_a?(Array)
+ raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
+ elsif nargs != v.length
+ raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
+ end
+ }
+ when Range
+ vals[sym] = proc { |v|
+ if !v.is_a?(Array)
+ raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
+ elsif !nargs.include?(v.length)
+ raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
+ end
+ }
+ when Set
+ vals[sym] = proc { |v|
+ if !nargs.include?(v)
+ raise ArgumentError, "invalid option value: `#{v}' (expected one of #{nargs.to_a.inspect})"
+ end
+ }
+ when Array
+ vals[sym] = proc { |v|
+ if !v.is_a?(Array)
+ raise ArgumentError, "wrong number of arguments (1 for #{nargs.length})"
+ elsif nargs.length != v.length
+ raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs.length})"
+ else
+ v.zip(nargs).each do |ec|
+ e, c = ec
+ case c
+ when Class
+ 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
+ end
+ end
+ end
+ }
+ when Class
+ vals[sym] = proc { |v|
+ if !v.is_a?(nargs)
+ raise TypeError, "wrong argument type #{v.class} (expected #{nargs})"
+ end
+ }
+ end
+ end
+
# Class methods
pairs.each do |pair|
sym = pair.first
self.class_eval do
@@ -131,41 +222,28 @@
oi.class_eval do
pairs.each do |pair|
sym, nargs = pair
undef_method(sym) if method_defined?(sym)
define_method(sym) do |*v, &b|
- case nargs
- when :block
- if b
- if v.empty?
- merge(sym => b)
- else
- raise ArgumentError, "only block expected"
- end
- else
- raise ArgumentError, "block expected but not given"
- end
- when 1
- if b && v.empty?
+ if nargs == :&
+ if v.empty?
merge(sym => b)
- elsif b && !v.empty?
- raise ArgumentError, "wrong number of arguments (#{v.length} for 0 when block given)"
- elsif v.length == 1
- merge(sym => v.first)
else
- raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
+ raise ArgumentError, "wrong number of arguments (#{v.length} for 0)"
end
- when Range, Fixnum
- if b
- raise ArgumentError, "block not expected"
- elsif (nargs.is_a?(Range) && !nargs.include?(v.length)) ||
- (nargs.is_a?(Fixnum) && nargs != v.length)
- raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
+ elsif b
+ raise ArgumentError, "block not expected"
+ else
+ case nargs
+ when 1, Class, Set
+ if v.length == 1
+ merge(sym => v.first)
+ else
+ raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
+ end
else
merge(sym => v)
end
- else
- raise ArgumentError, "invalid option specification"
end
end
end
end
end