module Blockenspiel::DSLSetupMethods

DSL setup methods

These class methods are available after you have included the Blockenspiel::DSL module.

By default, a class that has DSL capability will automatically make all public methods available to parameterless blocks, except for the initialize method, any methods whose names begin with an underscore, and any methods whose names end with an equals sign.

If you want to change this behavior, use the directives defined here to control exactly which methods are available to parameterless blocks.

Public Instance Methods

dsl_attr_accessor(*names_) click to toggle source

A DSL-friendly attr_accessor.

This creates the usual “name” and “name=” methods in the current class that can be used in the usual way. However, its implementation of the “name” method (the getter) also takes an optional parameter that causes it to behave as a setter. This is done because the usual setter syntax cannot be used in a parameterless block, since it is syntactically indistinguishable from a local variable assignment. The “name” method is exposed as a dsl_method.

For example:

dsl_attr_accessor :foo

enables the following:

my_block do |param|
  param.foo = 1   # Usual setter syntax works
  param.foo 2     # Alternate setter syntax also works
  puts param.foo  # Usual getter syntax still works
end

my_block do
  # foo = 1       # Usual setter syntax does NOT work since it
                  #   looks like a local variable assignment
  foo 2           # Alternate setter syntax does work
  puts foo        # Usual getter syntax still works
end
# File lib/blockenspiel/dsl_setup.rb, line 263
def dsl_attr_accessor(*names_)
  names_.each do |name_|
    unless name_.kind_of?(::String) || name_.kind_of?(::Symbol)
      raise ::TypeError, "#{name_.inspect} is not a symbol"
    end
    unless name_.to_s =~ /^[_a-zA-Z]\w+$/
      raise ::NameError, "invalid attribute name #{name_.inspect}"
    end
    module_eval("def #{name_}(value_=::Blockenspiel::NO_VALUE); ::Blockenspiel::NO_VALUE.equal?(value_) ? @#{name_} : @#{name_} = value_; end\n")
    alias_method("#{name_}=", name_)
    dsl_method(name_)
  end
end
dsl_attr_writer(*names_) click to toggle source

A DSL-friendly attr_writer.

This creates the usual “name=” method in the current class that can be used in the usual way. However, it also creates the method “name”, which also functions as a setter (but not a getter). This is done because the usual setter syntax cannot be used in a parameterless block, since it is syntactically indistinguishable from a local variable assignment. The “name” method is exposed as a dsl_method.

For example:

dsl_attr_writer :foo

is functionally equivalent to:

attr_writer :foo
alias_method :foo, :foo=
dsl_method :foo

which enables the following:

my_block do |param|
  param.foo = 1   # Usual setter syntax works
  param.foo 2     # Alternate setter syntax also works
end
my_block do
  # foo = 1       # Usual setter syntax does NOT work since it
                  #   looks like a local variable assignment
  foo(2)          # Alternate setter syntax does work
end
# File lib/blockenspiel/dsl_setup.rb, line 309
def dsl_attr_writer(*names_)
  names_.each do |name_|
    attr_writer(name_)
    alias_method(name_, "#{name_}=")
    dsl_method(name_)
  end
end
dsl_method(name_, delegate_=nil) click to toggle source

Make a particular method available to parameterless DSL blocks.

To explicitly make a method available to parameterless blocks:

dsl_method :my_method

To explicitly exclude a method from parameterless blocks:

dsl_method :my_method, false

To explicitly make a method available to parameterless blocks, but point it to a method of a different name on the target class:

dsl_method :my_method, :target_class_method
# File lib/blockenspiel/dsl_setup.rb, line 175
def dsl_method(name_, delegate_=nil)
  name_ = name_.to_sym
  if delegate_
    delegate_ = delegate_.to_sym
  elsif delegate_.nil?
    delegate_ = name_
  end
  @_blockenspiel_methods[name_] = delegate_
  unless @_blockenspiel_module.public_method_defined?(name_)
    @_blockenspiel_module.module_eval("def #{name_}(*params_, &block_); val_ = ::Blockenspiel._target_dispatch(self, :#{name_}, params_, block_); ::Blockenspiel::NO_VALUE.equal?(val_) ? super(*params_, &block_) : val_; end\n")
  end
end
dsl_methods(*names_) click to toggle source

Control the behavior of methods with respect to parameterless blocks, or make a list of methods available to parameterless blocks in bulk.

To enable automatic exporting of methods to parameterless blocks. After executing this command, all public methods defined in the class will be available on parameterless blocks, until dsl_methods false is called:

dsl_methods true

To disable automatic exporting of methods to parameterless blocks. After executing this command, methods defined in this class will be excluded from parameterless blocks, until dsl_methods true is called:

dsl_methods false

To make a list of methods available to parameterless blocks in bulk:

dsl_methods :my_method1, :my_method2, ...

You can also point dsl methods to a method of a different name on the target class, by using a hash syntax, as follows:

dsl_methods :my_method1 => :target_class_method1,
            :my_method2 => :target_class_method2

You can mix non-renamed and renamed method declarations as long as the renamed (hash) methods are at the end. e.g.:

dsl_methods :my_method1, :my_method2 => :target_class_method2
# File lib/blockenspiel/dsl_setup.rb, line 216
def dsl_methods(*names_)
  if names_.size == 0 || names_ == [true]
    @_blockenspiel_active = true
  elsif names_ == [false]
    @_blockenspiel_active = false
  else
    if names_.last.kind_of?(::Hash)
      names_.pop.each do |name_, delegate_|
        dsl_method(name_, delegate_)
      end
    end
    names_.each do |name_|
      dsl_method(name_, name_)
    end
  end
end