lib/db_mod/statements/configuration/defaults.rb in db_mod-0.0.5 vs lib/db_mod/statements/configuration/defaults.rb in db_mod-0.0.6

- old
+ new

@@ -12,17 +12,25 @@ # VALUES # ($1, $2, $3) # RETURNING p, q, r # )) { defaults(5, 6).single(:row) } # + # def_prepared(:c, 'SELECT a FROM b WHERE d = $e AND f > $g') do + # # procs may be used + # defaults g: ->(args) { args[:e] * 10 } + # end + # # # ... # # a # y => 10 # a 11 # y => 11 # # # defaults filled in from the right # b 1, 2 # => { 'p' => '1', 'q' => '2', 'r' => '6' } + # + # # proc defaults executed when method is called + # c e: 2 # === c e: 2, g: 20 module Defaults # Extend a method definition by wrapping it with a proc that will # try to fill in any omitted arguments with given defaults. # # @param definition [Proc] base method definition, @@ -30,11 +38,14 @@ # @param params [Hash<Symbol,value>,Array<value>] # see {Configuration.def_configurable} # @param defaults [Hash<Symbol,value,Array<value>] # default values, in the same form as they would be provided # to the original method definition except that some values - # may be omitted + # may be omitted. Defaults may either be constant values, or + # a lambda proc may be given, which will be passed the + # entirety of the argument list and should return a single + # value to be used when none is given # @return [Proc] new method definition, or the same one # if no default values have been appended def self.extend(definition, params, defaults) return definition if defaults.nil? @@ -55,42 +66,71 @@ # argument values for one or more parameters. # # @param definition [Proc] base method definition, # with parameter validation already attached # @param defaults [Hash<Symbol,value>] - # default parameter values + # see {Defaults.extend} + # @return [Proc] wrapped method definition def self.extend_named_args_method(definition, defaults) unless defaults.is_a? Hash fail ArgumentError, 'hash expected for defaults' end lambda do |*args| - Defaults.use_named_defaults(args, defaults) + Defaults.use_named_defaults(self, args, defaults) instance_exec(*args, &definition) end end # Fill in any missing parameter arguments using default # values where available. # + # @param scope [Object] scope to be used for executing + # default values that are lambda procedures. Should + # be the instance object where the method has been + # defined. # @param args [[Hash<Symbol,value>]] method arguments # before processing and validation # @param defaults [Hash<Symbol,value>] # default parameter values - def self.use_named_defaults(args, defaults) + # @see Defaults.extend_named_args_method + def self.use_named_defaults(scope, args, defaults) # Special case when no args given. args << {} if args.empty? # If the args are weird, expect normal parameter validation # to pick it up. return args unless args.last.is_a? Hash defaults.each do |arg, value| - args.last[arg] = value unless args.last.key? arg + next if args.last.key? arg + + args.last[arg] = value! value, scope, args.last end end + # Execute the default 'value' if it is a +Proc+, + # or just return it. + # + # @param value [Proc,Object] default value as specified + # by {MethodConfiguration#defaults} + # @param scope [Object] scope to be used for executing + # default values that are lambda procedures. Should + # be the instance object where the method has been + # defined. + # @param args [Hash,Array] fixed or named argument + # list, to be passed to the 'value' if it is a proc + # @return [Object] value to be passed to the parametered + # database query + def self.value!(value, scope, args) + if value.is_a? Proc + scope.instance_exec(args, &value) + else + value + end + end + # Extend a method with numbered parameters, providing # default argument values for one or more parameters. # Defaults will be applied, in the same left-to-right # order, but at the right-hand side of the parameter # list, as with normal method default arguments. @@ -99,10 +139,11 @@ # with parameter validation already attached # @param arity [Fixnum] number of arguments expected # by the base method definition # @param defaults [Array] # default parameter values + # @return [Proc] wrapped method definition def self.extend_fixed_args_method(definition, arity, defaults) fail ArgumentError, 'too many defaults' if defaults.size > arity unless defaults.is_a? Array fail ArgumentError, 'array expected for defaults' @@ -110,29 +151,35 @@ arity = (arity - defaults.size)..arity fail ArgumentError, 'too many defaults' if arity.min < 0 lambda do |*args| - Defaults.use_fixed_defaults(args, defaults, arity) + Defaults.use_fixed_defaults(self, args, defaults, arity) instance_exec(*args, &definition) end end # Fill in any missing parameter arguments using default values # where available. # + # @param scope [Object] scope to be used for executing + # default values that are lambda procedures. Should + # be the instance object where the method has been + # defined. # @param args [Array] method arguments # before processing and validation # @param defaults [Array] default parameter values # @param arity [Range<Fixnum>] number of arguments # expected by the base method definition - def self.use_fixed_defaults(args, defaults, arity) + # @raise [ArgumentError] if there are not enough or too many args + # @see Defaults.extend_fixed_args_method + def self.use_fixed_defaults(scope, args, defaults, arity) unless arity.include? args.count fail ArgumentError, "#{args.count} given, (#{arity}) expected" end defaults[args.size - arity.min...defaults.size].each do |arg| - args << arg + args << value!(arg, scope, args) end end end end end