module WrapIt::Arguments::ClassMethods

{Arguments} Class methods to include

Attributes

provided_arguments[R]
provided_block[R]
provided_options[R]

Public Instance Methods

argument(name, first_only: false, after_options: false, **opts, &block) click to toggle source

Desclares argument for capturing on initialization process.

Inside initialization process, all arguments (except options hash), passed to constructor will be inspected to satisfy conditions, specified in `:if` and `:and` options. If this happens, and block given, it evaluated in context of component instance. If no block given, setter with `name` will be attempted to set value. In any way if conditions satisfied, argument removed from future processing.

If no conditions specified, the `name` of attribute taked as only condition.

@example without conditions - name is a condition

class Button < WrapIt::Base
  argument(:disabled) { |name, value| puts 'DISABLED' }
end

Button.new(template, :disabled)   # => 'DISABLED'
Button.new(template, 'disabled')  # => nothing

@example with conditions and setter

class Button < WrapIt::Base
  argument :disabled, if: /^disable(?:d)?$/

  def disabled=(value)
    puts 'DISABLED'
  end
end

Button.new(template, :disabled)   # => 'DISABLED'
Button.new(template, 'disabled')  # => 'DISABLED'
Button.new(template, :disable)    # => 'DISABLED'
Button.new(template, 'some_text') # => nothing

@overload argument(name, opts = {}, &block)

@param  name [Symbol] unique name, used to refer to this declaration
@param  opts [Hash]   options
@option opts [Object]  :if one or array of conditions that should be
  satisfied to capture argument. See {CaptureArray} for details. If
  array given, conditions will be or'ed.
@option opts [Object]  :and additional one or array of conditions,
  that will be and'ed with :if conditions.
@option opts [Boolean] :first_only (false) stop processing on first
  match
@option opts [Boolean] :after_options (false) process this argument
  after options
@yield [name, value] yields every time argument captured. Evaluated
  in instance context
@yieldparam name [Symbol] name of argument, specified in name param
  above
@yieldparam value [Object] real argument value

@return [void] @since 1.0.0

# File lib/wrap_it/arguments.rb, line 94
def argument(name, first_only: false, after_options: false,
             **opts, &block)
  name.is_a?(String) && name = name.to_sym
  fail ArgumentError, 'Wrong name' unless name.is_a?(Symbol)
  arguments[name] = {
    name: name,
    conditions: Arguments.make_conditions(name, **opts),
    block: block,
    first_only: first_only == true,
    after_options: after_options == true
  }
end
capture_arguments!(args, inherited = true, instance = nil, &block) click to toggle source

Capture arguments for class and it's ancestors. All captured arguments and options will be extracted from original `args` argument.

Actually you rare needs to call this method directly. For example you can call it in instance {Arguments#capture_arguments! capture_arguments!} override to capture arguments for some child components.

@example capturing arguments for child component

class Button < WrapIt::Base
  option(:color) { |name, value| puts "BUTTON COLOR IS: #{value}" }
end

class Toolbar < WrapIt::Base
  protected
  def capture_arguments!(args, &block)
    @button = Button.new(Button.capture_arguments!(args))
    super(args, &block) # ! don't forget to call parent method
  end
end

Toolbar.new(template, color: :red)  # => 'BUTTON COLOR IS red'

@overload capture_arguments!(args, opts = {}, &block)

@param  args [Array<Object>] arguments to process (include options)
@param  opts [Hash] options
@option opts [Boolean] :inherited (true) process ancestors
@option opts [Base] :instance (nil) if specified valid instance,
  all {ClassMethods#argument} and {ClassMethods#option} blocks will
  and setters will be called.
@param  &block [Proc] block, passed to constructor if present

@return [Array<Object>] captured arguments

# File lib/wrap_it/arguments.rb, line 200
def capture_arguments!(args, inherited = true, instance = nil, &block)
  opts = args.extract_options!
  if inherited
    arg_parents.select { |a| a.protected_methods.include?(:extract_for_class) }
               .each { |a| a.extract_for_class(args, opts, instance, &block) }
    result_args = collect_derived(:@provided_arguments, {}, :merge)
                  .values
                  .flatten
    result_opts = collect_derived(:@provided_options, {}, :merge)
                  .values
                  .reduce({}) { |a, e| a.merge!(e) }
  else
    extract_for_class(args, opts, instance, &block)
    result_args = @provided_arguments.values.flatten
    result_opts = @provided_options
                  .values
                  .reduce({}) { |a, e| a.merge!(e) }
  end
  opts.empty? || args << opts
  result_opts.empty? || result_args << result_opts
  result_args
end
option(name, after: nil, **opts, &block) click to toggle source

Desclares option for capturing on initialization process.

Provides same manner as {#argument} but for hash of options, passed to constructor. Specified conditions are applied to options keys, not to values.

> Hint: you can specify argument and options with same name to call > same setter.

@example shared setter

class Button < WrapIt::Base
  REGEXP = /^disable(?:d)?$/

  argument :disabled, if: REGEXP
  option   :disabled, if: %i(disable disabled)

  def disabled=(value)
    if value == true || REGEXP =~ value.to_s
      puts 'DISABLED'
    end
  end
end

Button.new(template, :disabled)       # => 'DISABLED'
Button.new(template, 'disabled')      # => 'DISABLED'
Button.new(template, :disable)        # => 'DISABLED'
Button.new(template, disabled: true)  # => 'DISABLED'
Button.new(template, disable: true)   # => 'DISABLED'
Button.new(template, disable: false)  # => nothing
Button.new(template, 'some_text')     # => nothing

@overload option(name, opts = {}, &block)

@param  name [Symbol] unique name, used to refer to this declaration
@param  opts [Hash]   options
@option opts [Object]  :if see
  {WrapIt::Arguments::ClassMethods#argument}
@option opts [Object]  :and see
  {WrapIt::Arguments::ClassMethods#argument}
@yield [name, value] yields every time option captured. Evaluated
  in instance context
@yieldparam name [Symbol] name of option, specified in name param
  above
@yieldparam value [Object] real option value

@return [void] @since 1.0.0

# File lib/wrap_it/arguments.rb, line 154
def option(name, after: nil, **opts, &block)
  name.is_a?(String) && name = name.to_sym
  fail ArgumentError, 'Wrong name' unless name.is_a?(Symbol)
  @dependencies = !after.nil?
  options[name] = {
    name: name,
    conditions: Arguments.make_conditions(name, **opts),
    block: block
  }
end

Protected Instance Methods

arg_parents() click to toggle source
# File lib/wrap_it/arguments.rb, line 225
def arg_parents
  @arg_parents ||= ancestors.take_while { |a| a != Arguments.base }
                            .reverse
                            .unshift(Arguments.base)
end
argument_provided?(*list) click to toggle source
# File lib/wrap_it/arguments.rb, line 244
def argument_provided?(*list)
  return false if provided_arguments.nil?
  if list.empty?
    return provided_arguments.empty?
  else
    return list.all? do |arg|
      provided_arguments.key?(arg)
    end
  end
end
arguments() click to toggle source
# File lib/wrap_it/arguments.rb, line 263
def arguments
  @arguments ||= {}
end
block_provided?() click to toggle source
# File lib/wrap_it/arguments.rb, line 255
def block_provided?
  provided_block.is_a?(Proc)
end
extract_args(args, list, instance = nil) click to toggle source
# File lib/wrap_it/arguments.rb, line 267
def extract_args(args, list, instance = nil)
  args.respond_to?(:extract!) || args.extend(WrapIt::CaptureArray)
  list.each do |arg|
    processed =
      if arg[:first_only]
        [args.capture_first!(*arg[:conditions])].compact
      else
        args.capture!(*arg[:conditions])
      end
    (provided_arguments[arg[:name]] ||= []).concat(processed)
    next if instance.nil?
    processed.each do |v|
      instance.instance_exec(arg[:name], v, arg[:block], &SETTER)
    end
  end
end
extract_for_class(args, opts, instance = nil, &block) click to toggle source
# File lib/wrap_it/arguments.rb, line 300
def extract_for_class(args, opts, instance = nil, &block)
  @provided_options = {}
  @provided_arguments = {}
  @provided_block = block

  after, before = arguments.values.partition { |x| x[:after_options] }

  extract_args(args, before, instance)
  extract_opts(opts, instance)
  extract_args(args, after, instance)

  @provided_block = nil
end
extract_opts(opts, instance = nil) click to toggle source
# File lib/wrap_it/arguments.rb, line 284
def extract_opts(opts, instance = nil)
  keys = opts.keys.extend(WrapIt::CaptureArray)
  options.each do |name, opt|
    (provided_options[name] ||= {}).merge!(Hash[
      keys.capture!(*opt[:conditions])
        .map do |key|
          value = opts.delete(key)
          unless instance.nil?
            instance.instance_exec(key, value, opt[:block], &SETTER)
          end
          [key, value]
        end
    ])
  end
end
option_provided?(*list) click to toggle source
# File lib/wrap_it/arguments.rb, line 233
def option_provided?(*list)
  return false if provided_options.nil?
  if list.empty?
    return provided_options.empty?
  else
    return list.all? do |option|
      provided_options.key?(option)
    end
  end
end
options() click to toggle source
# File lib/wrap_it/arguments.rb, line 259
def options
  @options ||= {}
end