module EDSL::DSL

These methods will be extended into any class which includes EDSL. They provide a mechanism for declaring HTML elements as properties of another object

Public Class Methods

alias_accessor(new_name, acc_name) click to toggle source

Allow an accessor to be accessed by a different name

# File lib/edsl/dsl.rb, line 153
def self.alias_accessor(new_name, acc_name)
  self.class.send(:alias_method, new_name, acc_name)
end
define_accessor(acc_name, default_opts) click to toggle source

This vastly simplifies defining custom accessors. If we had to use the base element method for every field that would be tedious. This method allows us to extend the DSL to add a shorthand method for elements.

If we extend the DSL like this:

EDSL.define_accessor(:text_field, how: :text_field, default_method: :value, assign_method: :set)

Then we can use an easier syntax to declare a text field

text_field(:username, id: 'some_id')
# File lib/edsl/dsl.rb, line 146
def self.define_accessor(acc_name, default_opts)
  self.class.send(:define_method, acc_name) do |name, opts = {}, &block|
    element(name, default_opts.merge(opts), &block)
  end
end
define_accessors(accessor_array) click to toggle source

Allow multiple accessors to be defined at once

# File lib/edsl/dsl.rb, line 158
def self.define_accessors(accessor_array)
  accessor_array.each { |acc| define_accessor(*acc) }
end

Public Instance Methods

_add_assignment_methods(name, element_method, opts) click to toggle source

Helper function to reduce perceived complexity of element

# File lib/edsl/dsl.rb, line 89
def _add_assignment_methods(name, element_method, opts)
  assign_method = opts.delete(:assign_method)
  return unless assign_method

  define_method("#{name}=") do |value|
    return assign_method.call(name, self, value) if assign_method.is_a?(Proc)

    send(element_method).send(assign_method, value)
  end
end
_add_common_methods(name, element_method, opts) click to toggle source

Helper function to reduce perceived complexity of element

# File lib/edsl/dsl.rb, line 101
def _add_common_methods(name, element_method, opts)
  default_method = opts.delete(:default_method)
  presence_method = opts.delete(:presence_method) || :present?

  define_method(name) do
    return default_method.call(name, self) if default_method.is_a?(Proc)

    default_method.nil? ? send(element_method) : send(element_method).send(default_method)
  end

  define_method("#{name}?") do
    return presence_method.call(name, self) if presence_method.is_a?(Proc)

    send(element_method).send(presence_method)
  end
end
_add_element_method(name, opts) { |self| ... } click to toggle source

rubocop:disable Metrics/AbcSize Helper function to reduce perceived complexity of element

# File lib/edsl/dsl.rb, line 120
def _add_element_method(name, opts, &block)
  how = opts.delete(:how)
  hooks = opts.delete(:hooks)
  wrapper_fn = opts.delete(:wrapper_fn) || ->(e, _p) { return e }

  ele_meth = "#{name}_element"
  define_method(ele_meth) do
    ele = yield self if block_given?
    ele ||= how.call(name, self, opts) if how.is_a?(Proc)
    ele ||= send(how, opts)
    ele = wrapper_fn.call(ele, self)
    hooks.nil? ? ele : send(:apply_hooks, hooks, ele)
  end
  ele_meth
end
element(name, opts, &block) click to toggle source

This is the core accessor on which everything else is based. Given a name and some options this will generate the following methods:

name - Executes the method found in the :default_method option, or the element itself if none provided.
name= - Executes the method found in the :assign_method option, passing it the value. (optional).
name? - Executes the method found in the :presence_method option, or present?

For example a text field would look like this:

element(:username, id: 'some_id', how: :text_field, default_method: :value, assign_method: :set)

The :how option can either be something that is sendable. or a proc

If send is used, the options will be passed on to the method.
If a proc is used it will be called with the name and opts param as well as the container

A text field could be declared like this:

element(:username, id: 'some_id', how: Proc.new { |name, container, opts| container.text_field(opts) }, default_method: :value, assign_method: :set)
# File lib/edsl/dsl.rb, line 82
def element(name, opts, &block)
  element_method = _add_element_method(name, opts, &block)
  _add_common_methods(name, element_method, opts)
  _add_assignment_methods(name, element_method, opts)
end