Module: Rxhp::Scope

Included in:
Element
Defined in:
lib/rxhp/scope.rb

Overview

A place for factory methods to be defined.

These are methods like Rxhp::Scope#h1 which creates an instance of Rxhp::Html::H1.

The actual HTML classes are defined in rxhp/html.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.currentObject

The element nesting scope.

Examples:

Rxhp::Scope.current.should be_a Rxhp::Fragment
html.do
  Rxhp::Scope.current.should be_a Rxhp::Html::Html
  body do
    Rxhp::Scope.current.should be_a Rxhp::Html::Body
  end
end


41
42
43
44
45
46
47
48
49
# File 'lib/rxhp/scope.rb', line 41

def self.current
  callcc do |cc|
    begin
      throw(:rxhp_parent, cc)
    rescue NameError, ArgumentError
      Rxhp::Fragment.new
    end
  end
end

.define_element(name, klass, namespace = Kernel) ⇒ Object

Define a factory method that takes a block, with a scope.

Examples:

define_element tag, Tag
tag
tag 'content'
tag(:attribute => value)
tag('content', :attribute => 'value')
tag(:attribute => 'value') do
  text 'content'
end

Parameters:

  • name (String)

    is the name of the method to define

  • klass (Class)

    is the Element subclass to construct

  • namespace (Module) (defaults to: Kernel)

    is where to define the method



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rxhp/scope.rb', line 79

def self.define_element name, klass, namespace = Kernel
  impl = Proc.new do |*args, &block|
    # Yay for faking named parameters as a hash :p
    children = nil
    attributes = {}
    args.each do |arg|
      if arg.is_a?(Hash)
        attributes = arg
      else
        children ||= []
        children.push arg
      end
    end

    # Create the actual element
    element = klass.new(attributes)
    Rxhp::Scope.current.children.push element

    # Append non-block children
    if children
      children.each do |child|
        element.children.push child
      end
    end

    if block
      Rxhp::Scope.with_parent(element) do
        if block.call.is_a? String
          raise Rxhp::ScriptError.new(
            "In a block, use the 'text' method to include Strings"
          )
        end
      end
      element.validate! if element.respond_to?(:validate!)
      nil
    end
    element
  end

  # Instance method if mixed in.
  #
  # Usage:
  #  include Rxhp::Html
  #  html do
  #    ...
  #  end
  namespace.send(:define_method, name, impl)
  # Class method for fully-qualified.
  #
  # Usage:
  #  Rxhp::Html.html do
  #    ...
  #  end
  (class <<namespace; self; end).send(:define_method, name, impl)
end

.with_parent(parent, &block) ⇒ Object

Set the value of #current for a block, and call it.

Used by #define_element



54
55
56
57
58
59
60
61
62
# File 'lib/rxhp/scope.rb', line 54

def self.with_parent parent, &block
  # push element onto the render stack...
  cc = catch(:rxhp_parent) do
    # ... and call the block with that new stack
    block.call
    nil
  end
  cc.call(parent) if cc
end

Instance Method Details

#fragment(x) ⇒ Object Also known as: frag, text

Helper function to append a child to the current context.

Examples:

Here’s one I made earlier

inner = body { 'hi' }
html do
  fragment inner
end

Multiple String children

p do
  text 'foo'
  text 'bar'
end


25
26
27
# File 'lib/rxhp/scope.rb', line 25

def fragment x
  Rxhp::Scope.current.children.push x
end