class WrapIt::Container

Describes elements that can contain other elements

@author Alexey Ovchinnikov <alexiss@cybernetlab.ru>

@todo single_child realization @todo refactor code for more clearness

Constants

CONTENT_REPLACE_REGEXP
CONTENT_SPLIT_REGEXP

Attributes

children[R]

list of children elements

extract_children[W]

children can be extracted from normal template flow and rendered in separate section.

Public Class Methods

child(name, *args, option: nil, **opts, &block) click to toggle source

Defines helper for child elements creation.

@example simple usage

class Item < WrapIt::Base
  include TextContainer
end

class List < WrapIt::Container
  default_tag 'ul'
  child :item, tag: 'li'
end

list = List.new(template)
list.item 'list item 1'
list.item 'list item 2'
list.render # => '<ul><li>list item 1'</li><li>list item 2</li></ul>'

@example with option

class Button < WrapIt::Container
  include TextContainer
  html_class 'btn'
  child :icon, tag: 'i', option: true
end

btn = Button.new(template, 'Home', icon: { class: 'i-home' })
btn.render # => '<div class="btn">Home<i class="i-home"></i></div>'

@overload child(name, class_name = nil, [args, …], opts = {}, &block)

@param name [Symbol, String] helper method name
@param class_name [String, Base] class for child elements. If ommited
  WrapIt::Base will be used
@param args [Object] any arguments that will be passed to child
  element constructor
@param opts [Hash] options
@option opts [true, Symbol] :option if specified, child can be created
  via option with same name (if :option is true) or with specified
  name
@option opts [Symbol] :section section to that this children will be
  rendered. By default children rendered to `children`. Refer to
  {Sections} module for details.

@return [String]

# File lib/wrap_it/container.rb, line 79
def self.child(name, *args, option: nil, **opts, &block)
  name.is_a?(String) && name.to_sym
  name.is_a?(Symbol) || fail(ArgumentError, 'Wrong child name')
  child_class =
    if args.first.is_a?(String) || args.first.is_a?(Class)
      args.shift
    else
      'WrapIt::Base'
    end
  child_class = child_class.name if child_class.is_a?(Class)

  define_method name do |*hargs, extracted: false, **hopts, &hblock|
    hargs += args
    # TODO: merge html class correctly. Now it just overrided by opts
    hopts.merge!(opts)
    hopts[:helper_name] = name
    child = prepare_child(child_class, block, *hargs, **hopts, &hblock)
    add_children(name, child, extracted: extracted)
  end

  add_child_option(name, option)
end

Private Class Methods

add_child_option(name, option) click to toggle source
# File lib/wrap_it/container.rb, line 164
def self.add_child_option(name, option)
  return if option.nil?
  option.is_a?(Array) || option = [option]
  option.each do |opt_name|
    opt_name = name if opt_name == true
    option(opt_name) do |_, args|
      self.deffered_render = true
      args.is_a?(Array) || args = [args]
      opts = args.extract_options!
      send(name, *args, extracted: true, **opts)
    end
  end
end

Public Instance Methods

extract_children?() click to toggle source
# File lib/wrap_it/container.rb, line 28
def extract_children?
  @extract_children == true
end

Private Instance Methods

add_children(name, item, extracted: false) click to toggle source
# File lib/wrap_it/container.rb, line 129
def add_children(name, item, extracted: false)
  deffered_render? && @children << item
  return if extracted == true
  if !deffered_render? && (omit_content? || extract_children?)
    self[item.render_to] << capture { item.render }
  end
  if omit_content? || extract_children?
    empty_html
  else
    if deffered_render?
      html_safe("<!-- WrapIt::Container(#{item.object_id.to_s(16)}) -->")
    else
      item.render
    end
  end
end
prepare_child(helper_class, class_block, *args, section: nil, **opts, &helper_block) click to toggle source
# File lib/wrap_it/container.rb, line 146
def prepare_child(helper_class, class_block, *args,
                  section: nil, **opts,
                  &helper_block)
  section ||= :children
  item = Object
    .const_get(helper_class)
    .new(@template, *args, **opts, &helper_block)
  item.instance_variable_set(:@render_to, section)
  item.instance_variable_set(:@parent, self)
  item.define_singleton_method(:render_to) { @render_to }
  item.define_singleton_method(:render_to=) do |value|
    self.class.sections.include?(value) && @render_to = value
  end
  item.define_singleton_method(:parent) { @parent }
  class_block.nil? || instance_exec(item, &class_block)
  item
end