class Formular::Element

The Element class is responsible for defining what the html should look like. This includes default attributes, and the function to use to render the html actual rendering is done via a HtmlBlock class

Constants

Container

These three are really just provided for convenience when creating other elements

Control
Div
Fieldset

define some base classes to build from or easily use elsewhere

Legend
P
Small
Span
Wrapped

Attributes

builder[R]
html_blocks[R]
options[R]
tag[R]

Public Class Methods

add_option_keys(*keys) click to toggle source

blacklist the keys that should NOT end up as html attributes

# File lib/formular/element.rb, line 58
def self.add_option_keys(*keys)
  self.option_keys += keys
end
call(**options, &block) click to toggle source
# File lib/formular/element.rb, line 73
def self.call(**options, &block)
  new(**options, &block)
end
html(context = :default, &block) click to toggle source

define what your html should look like this block is executed in the context of an HtmlBlock instance

# File lib/formular/element.rb, line 46
def self.html(context = :default, &block)
  self.html_blocks[context] = block
end
new(**options, &block) click to toggle source
# File lib/formular/element.rb, line 77
def initialize(**options, &block)
  @builder = options.delete(:builder)
  @options = options
  normalize_options
  process_options
  @block = block
  @tag = self.class.tag_name
  @html_blocks = define_html_blocks
end
process_option(key, processor, condition = {}) click to toggle source

process an option value (i.e. escape html) This occurs after the value has been set (either by default or by user input) you can make this conditional by providing a condition e.g. if: :some_method or unless: :some_method

# File lib/formular/element.rb, line 40
def self.process_option(key, processor, condition = {})
  self.processing_hash[key] = { processor: processor, condition: condition }
end
rename_html_context(old_context, new_context) click to toggle source

a convenient way of changing the key for a context useful for inheritance if you want to replace a context but still access the original function

# File lib/formular/element.rb, line 53
def self.rename_html_context(old_context, new_context)
  self.html_blocks[new_context] = self.html_blocks.delete(old_context)
end
set_default(key, value, condition = {}) click to toggle source

set the default value of an option or attribute you can make this conditional by providing a condition e.g. if: :some_method or unless: :some_method to respect the order defaults are declared, rather than overriting existing defaults we should delete the existing and create a new k/v pair

# File lib/formular/element.rb, line 31
def self.set_default(key, value, condition = {})
  self.default_hash.delete(key) # attempt to delete an existing key
  self.default_hash[key] = { value: value, condition: condition }
end
tag(name) click to toggle source

define the name of the html tag for the element e.g. tag :span tag 'input' Note that if you leave this out, the tag will be inferred based on the name of your class Also, this is not inherited

# File lib/formular/element.rb, line 69
def self.tag(name)
  self.tag_name = name
end

Public Instance Methods

attributes() click to toggle source
# File lib/formular/element.rb, line 88
def attributes
  attrs = @options.select { |k, v| @options[k] || true unless option_key?(k) }
  Attributes[attrs]
end
to_html(context: nil) click to toggle source
# File lib/formular/element.rb, line 93
def to_html(context: nil)
  context ||= self.class.html_context
  html_blocks[context].call
end
Also aliased as: to_s
to_s(context: nil)
Alias for: to_html

Private Instance Methods

define_html_blocks() click to toggle source
# File lib/formular/element.rb, line 101
def define_html_blocks
  self.class.html_blocks.each_with_object({}) do |(context, block), hash|
    hash[context] = HtmlBlock.new(self, block)
  end
end
evaluate_option_condition?(condition = {}) click to toggle source

this evaluates any conditons placed on our defaults returning true or false e.g. set_default :checked, “checked”, if: :is_checked? set_default :class, [“form-control”], unless: :file_input?

# File lib/formular/element.rb, line 155
def evaluate_option_condition?(condition = {})
  return true if condition.empty?
  operator = condition.keys[0]
  condition_result = Uber::Options::Value.new(condition.values[0]).evaluate(self)

  case operator.to_sym
  when :if     then condition_result
  when :unless then !condition_result
  end
end
normalize_options() click to toggle source

Options passed into our element instance (@options) take precident over class level defaults Take each default value and merge it with options. This way ordering is important and we can access values as they are evaluated

# File lib/formular/element.rb, line 110
def normalize_options
  self.class.default_hash.each do |key, hash|
    should_merge = key.to_s.include?('class') && !options[key].nil?

    next if options.has_key?(key) && !should_merge

    # if our default is conditional and the condition evaluates to false then skip
    next unless evaluate_option_condition?(hash[:condition])

    val = Uber::Options::Value.new(hash[:value]).evaluate(self)

    # if our default value is nil then skip
    next if val.nil?

    # otherwise perform the actual merge, classes get joined, otherwise we overwrite
    should_merge ? @options[key] += val : @options[key] = val
  end
end
option_key?(k) click to toggle source
# File lib/formular/element.rb, line 147
def option_key?(k)
  self.class.option_keys.include?(k)
end
process_options() click to toggle source

Options passed into our element instance (@options) take precident over class level defaults Take each default value and merge it with options. This way ordering is important and we can access values as they are evaluated

# File lib/formular/element.rb, line 132
def process_options
  self.class.processing_hash.each do |key, hash|
    # we can't process if our option is nil
    next if options[key].nil?
    # don't process if our condition is false
    next unless evaluate_option_condition?(hash[:condition])

    # get our value
    val = self.send(hash[:processor], options[key]) # TODO enable procs and blocks

    # set our value
    @options[key] = val
  end
end