Module: EDSL::DSL

Defined in:
lib/edsl/dsl.rb

Overview

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.alias_accessor(new_name, acc_name) ⇒ Object

Allow an accessor to be accessed by a different name



153
154
155
# 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) ⇒ Object

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')


146
147
148
149
150
# 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) ⇒ Object

Allow multiple accessors to be defined at once



158
159
160
# File 'lib/edsl/dsl.rb', line 158

def self.define_accessors(accessor_array)
  accessor_array.each { |acc| define_accessor(*acc) }
end

Instance Method Details

#_add_assignment_methods(name, element_method, opts) ⇒ Object

Helper function to reduce perceived complexity of element



89
90
91
92
93
94
95
96
97
98
# 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) ⇒ Object

Helper function to reduce perceived complexity of element



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 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, &block) ⇒ Object

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



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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) ⇒ Object

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)


82
83
84
85
86
# 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