rxhp 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rxhp/attribute_validator.rb +89 -28
- data/lib/rxhp/composable_element.rb +4 -0
- data/lib/rxhp/constants.rb +9 -2
- data/lib/rxhp/data/html/attributes.rb +4 -4
- data/lib/rxhp/element.rb +39 -5
- data/lib/rxhp/error.rb +6 -0
- data/lib/rxhp/fragment.rb +1 -0
- data/lib/rxhp/html.rb +12 -0
- data/lib/rxhp/html_element.rb +22 -12
- data/lib/rxhp/html_self_closing_element.rb +4 -1
- data/lib/rxhp/html_singleton_element.rb +13 -4
- data/lib/rxhp/scope.rb +51 -27
- data/lib/rxhp/tags/html_tag.rb +3 -0
- metadata +19 -38
@@ -1,7 +1,25 @@
|
|
1
1
|
require 'rxhp/error'
|
2
2
|
|
3
3
|
module Rxhp
|
4
|
+
# Provide support for limiting or requiring attributes.
|
5
|
+
#
|
6
|
+
# Attributes can be:
|
7
|
+
# * whitelisted (see {ClassMethods#accept_attributes})
|
8
|
+
# * required (see {ClassMethods#require_attributes})
|
9
|
+
#
|
10
|
+
# Requiring an attribute automaticaly whitelists it.
|
11
|
+
#
|
12
|
+
# To use:
|
13
|
+
# * +include+ this module
|
14
|
+
# * whitelist/require attributes as appropriate
|
15
|
+
# * call {#validate_attributes!} from wherever seems appropriate - such
|
16
|
+
# {Rxhp::Element#validate!}
|
17
|
+
#
|
18
|
+
# Subclasses will automatically have validated attributes, and will
|
19
|
+
# copy the rules from their parent class. Additional attributes can be
|
20
|
+
# accepted or required in subclasses without affecting the parent class.
|
4
21
|
module AttributeValidator
|
22
|
+
# Indicates that a provided attribute was not whitelisted.
|
5
23
|
class UnacceptableAttributeError < ValidationError
|
6
24
|
attr_reader :element, :attribute, :value
|
7
25
|
def initialize element, attribute, value
|
@@ -10,6 +28,7 @@ module Rxhp
|
|
10
28
|
end
|
11
29
|
end
|
12
30
|
|
31
|
+
# Indicates that a required attribute was not provided.
|
13
32
|
class MissingRequiredAttributeError < ValidationError
|
14
33
|
attr_reader :element, :attribute
|
15
34
|
def initialize element, attribute
|
@@ -18,6 +37,13 @@ module Rxhp
|
|
18
37
|
end
|
19
38
|
end
|
20
39
|
|
40
|
+
# Whether or not the attributes are acceptable.
|
41
|
+
#
|
42
|
+
# If you need more details than just "it's invalid", call
|
43
|
+
# {#validate_attributes!} instead and examine the exceptions it raises.
|
44
|
+
#
|
45
|
+
# @return whether or not the attributes are all whitelisted, and all
|
46
|
+
# required attributes are provided.
|
21
47
|
def valid_attributes?
|
22
48
|
begin
|
23
49
|
self.validate_attributes!
|
@@ -27,6 +53,14 @@ module Rxhp
|
|
27
53
|
end
|
28
54
|
end
|
29
55
|
|
56
|
+
# Check if attributes are valid, and raise an exception if they're not.
|
57
|
+
#
|
58
|
+
# @raise {MissingRequiredAttributeError} if an attribute that is
|
59
|
+
# required was not provided.
|
60
|
+
# @raise {UnacceptableAttributeError} if a non-whitelisted attribute
|
61
|
+
# was provided.
|
62
|
+
# @return [true] if the attribute are all valid, and all required
|
63
|
+
# attributes are provided.
|
30
64
|
def validate_attributes!
|
31
65
|
# Check for required attributes
|
32
66
|
self.class.required_attributes.each do |matcher|
|
@@ -72,6 +106,56 @@ module Rxhp
|
|
72
106
|
end
|
73
107
|
end
|
74
108
|
|
109
|
+
module ClassMethods
|
110
|
+
attr_accessor :acceptable_attributes, :required_attributes
|
111
|
+
# Accept all attributes matching the specified pattern.
|
112
|
+
#
|
113
|
+
# @param pattern can be a:
|
114
|
+
# +Symbol+:: must equal the attribute name after converting to a
|
115
|
+
# +String+, and replacing underscores with hyphens.
|
116
|
+
# +Object+:: must match the attribute name with +===+.
|
117
|
+
# +Array+:: the members must be a any of the above that matches the
|
118
|
+
# attribute name.
|
119
|
+
# +Hash+:: the key can be any of the above that matches the
|
120
|
+
# attribute name; the value is matched against the
|
121
|
+
# attribute value in the same way.
|
122
|
+
# @example
|
123
|
+
# accept_attribute 'id'
|
124
|
+
# accept_attribute /^data-/
|
125
|
+
# accept_attributes ['href', 'src']
|
126
|
+
# accept_attributes ({ 'type' => ['checkbox', 'text', 'submit'] })
|
127
|
+
def accept_attributes pattern
|
128
|
+
acceptable_attributes.push pattern
|
129
|
+
end
|
130
|
+
alias :accept_attribute :accept_attributes
|
131
|
+
|
132
|
+
# Require an attribute matching the specified pattern.
|
133
|
+
#
|
134
|
+
# @param pattern accepts the same values as {#accept_attributes}
|
135
|
+
def require_attributes pattern
|
136
|
+
accept_attributes pattern
|
137
|
+
required_attributes.push pattern
|
138
|
+
end
|
139
|
+
alias :require_attribute :require_attributes
|
140
|
+
|
141
|
+
# Accept any attributes whatsoever.
|
142
|
+
def accept_all_attributes
|
143
|
+
accept_attributes Object
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def inherited(subklass) # @Private @api
|
149
|
+
Rxhp::AttributeValidator.inherited(subklass)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def self.name_from_symbol symbol
|
156
|
+
symbol.to_s.gsub('_', '-')
|
157
|
+
end
|
158
|
+
|
75
159
|
def self.match_value? matcher, value
|
76
160
|
if matcher == String
|
77
161
|
return (value.is_a? String) || (value.is_a? Symbol)
|
@@ -91,34 +175,18 @@ module Rxhp
|
|
91
175
|
end
|
92
176
|
end
|
93
177
|
|
94
|
-
|
95
|
-
symbol.to_s.gsub('_', '-')
|
96
|
-
end
|
97
|
-
|
178
|
+
# Include class methods, and initialize class variables.
|
98
179
|
def self.included(klass)
|
99
180
|
klass.extend(ClassMethods)
|
100
|
-
class << klass
|
101
|
-
attr_accessor :acceptable_attributes, :required_attributes
|
102
|
-
def accept_attributes matcher
|
103
|
-
acceptable_attributes.push matcher
|
104
|
-
end
|
105
|
-
alias :accept_attribute :accept_attributes
|
106
|
-
|
107
|
-
def require_attributes matcher
|
108
|
-
accept_attributes matcher
|
109
|
-
required_attributes.push matcher
|
110
|
-
end
|
111
|
-
alias :require_attribute :require_attributes
|
112
|
-
|
113
|
-
def accept_all_attributes
|
114
|
-
accept_attributes Object
|
115
|
-
end
|
116
|
-
end
|
117
181
|
|
118
182
|
klass.acceptable_attributes = []
|
119
183
|
klass.required_attributes = []
|
120
184
|
end
|
121
185
|
|
186
|
+
# Make subclasses validated too.
|
187
|
+
#
|
188
|
+
# Their accept/require lists will be copied from their superclass, but
|
189
|
+
# can be modified separately.
|
122
190
|
def self.inherited(subklass)
|
123
191
|
subklass.class_eval do
|
124
192
|
include Rxhp::AttributeValidator
|
@@ -126,12 +194,5 @@ module Rxhp
|
|
126
194
|
subklass.acceptable_attributes = subklass.superclass.acceptable_attributes.dup
|
127
195
|
subklass.required_attributes = subklass.superclass.required_attributes.dup
|
128
196
|
end
|
129
|
-
|
130
|
-
module ClassMethods
|
131
|
-
def inherited(subklass)
|
132
|
-
Rxhp::AttributeValidator.inherited(subklass)
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
197
|
end
|
137
198
|
end
|
@@ -12,6 +12,8 @@ module Rxhp
|
|
12
12
|
class ComposableElement < Rxhp::Element
|
13
13
|
include Rxhp::AttributeValidator
|
14
14
|
|
15
|
+
# Check that there are no detectable problems, such as invalid
|
16
|
+
# attributes.
|
15
17
|
def validate!
|
16
18
|
super
|
17
19
|
validate_attributes!
|
@@ -33,6 +35,8 @@ module Rxhp
|
|
33
35
|
end
|
34
36
|
|
35
37
|
# Implement this method - return an Rxhp::Element subclass.
|
38
|
+
#
|
39
|
+
# @yieldreturn child elements
|
36
40
|
def compose
|
37
41
|
raise NotImplementedError.new
|
38
42
|
end
|
data/lib/rxhp/constants.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
module Rxhp
|
2
|
-
#
|
2
|
+
# Render 'nice' HTML
|
3
|
+
# @example
|
4
|
+
# <div><p>foo<br>bar</p></div>
|
3
5
|
HTML_FORMAT = :html
|
6
|
+
# Render ugly, but valid HTML
|
7
|
+
# @example
|
8
|
+
# <div><p>foo<br>bar</div>
|
4
9
|
TINY_HTML_FORMAT = :tiny_html
|
10
|
+
# Render XHTML
|
11
|
+
# @example
|
12
|
+
# <div><p>foo<br />bar</p></div>
|
5
13
|
XHTML_FORMAT = :xhtml
|
6
14
|
|
7
|
-
# Doctypes
|
8
15
|
HTML_5 = "<!DOCTYPE html>\n"
|
9
16
|
HTML_4_01_TRANSITIONAL = <<EOF
|
10
17
|
<!DOCTYPE HTML PUBLIC
|
@@ -2,10 +2,10 @@ require 'uri'
|
|
2
2
|
|
3
3
|
module Rxhp
|
4
4
|
module Html
|
5
|
-
# Given ['foo', 'bar', 'baz']
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# Given +['foo', 'bar', 'baz']+, match:
|
6
|
+
# * +'foo'+
|
7
|
+
# * +'bar baz'+
|
8
|
+
# * +'foo bar baz'+
|
9
9
|
# etc.
|
10
10
|
def self.token_list tokens
|
11
11
|
token = tokens.join('|')
|
data/lib/rxhp/element.rb
CHANGED
@@ -9,18 +9,31 @@ module Rxhp
|
|
9
9
|
# error at render-time :p
|
10
10
|
class Element
|
11
11
|
include ::Rxhp::Scope
|
12
|
-
|
12
|
+
# A name => value map of attributes.
|
13
|
+
attr_accessor :attributes
|
14
|
+
# A list of child elements of this one.
|
15
|
+
attr_accessor :children
|
13
16
|
|
17
|
+
# Construct a new element with no children.
|
14
18
|
def initialize attributes = {}
|
15
19
|
@attributes = attributes
|
16
20
|
@children = Array.new
|
17
21
|
validate!
|
18
22
|
end
|
19
23
|
|
24
|
+
# Whether or not this element has any child element.
|
20
25
|
def children?
|
21
26
|
!children.empty?
|
22
27
|
end
|
23
28
|
|
29
|
+
# Whether there are any detectable problems with this element.
|
30
|
+
#
|
31
|
+
# See {AttributeValidator} for an example.
|
32
|
+
#
|
33
|
+
# You probably don't want to override this function in your subclasses;
|
34
|
+
# instead, you probably want to change {#validate!} to recognize your
|
35
|
+
# validations - all this does is check that it {#validate!} executes
|
36
|
+
# without raising a {ValidationError}.
|
24
37
|
def valid?
|
25
38
|
begin
|
26
39
|
validate!
|
@@ -30,6 +43,9 @@ module Rxhp
|
|
30
43
|
end
|
31
44
|
end
|
32
45
|
|
46
|
+
# Check that this element is valid.
|
47
|
+
#
|
48
|
+
# @raise Rxhp::ValidationError if a problem is found.
|
33
49
|
def validate!
|
34
50
|
# no-op
|
35
51
|
end
|
@@ -37,15 +53,23 @@ module Rxhp
|
|
37
53
|
# Return a flat HTML string for this element and all its' decendants.
|
38
54
|
#
|
39
55
|
# You probably don't want to implement this yourself - interesting
|
40
|
-
# implementations are in
|
41
|
-
#
|
56
|
+
# implementations are in {Fragment}, {HtmlElement}, and
|
57
|
+
# {ComposableElement}.
|
58
|
+
#
|
59
|
+
# Valid options include:
|
60
|
+
# +:pretty+:: add whitespace to make the output more readable. Defaults
|
61
|
+
# to true.
|
62
|
+
# +:indent+:: how many spaces to use to indent when +:pretty+ is true.
|
63
|
+
# +:format+:: See {Rxhp} for values. Default is {Rxhp::HTML_FORMAT}
|
64
|
+
# +:skip_doctype+:: Self explanatory. Defaults to false.
|
65
|
+
# +:doctype+:: See {Rxhp} for values. Default is {Rxhp::HTML_5}
|
42
66
|
def render options = {}
|
43
67
|
raise NotImplementedError.new
|
44
68
|
end
|
45
69
|
|
46
70
|
# Called when something that isn't an element is found in the tree.
|
47
71
|
#
|
48
|
-
# Implemented in
|
72
|
+
# Implemented in {HtmlElement}.
|
49
73
|
def render_string string, options
|
50
74
|
raise NotImplementedError.new
|
51
75
|
end
|
@@ -58,7 +82,11 @@ module Rxhp
|
|
58
82
|
flattened_children.map{ |child| render_child(child, options) }.join
|
59
83
|
end
|
60
84
|
|
61
|
-
# Fill default options
|
85
|
+
# Fill default render options.
|
86
|
+
#
|
87
|
+
# These are as defined for {#render}, with the addition of a
|
88
|
+
# +:depth+ value of 0. Other values aren't guaranteed to stay fixed,
|
89
|
+
# check source for current values.
|
62
90
|
def fill_options options
|
63
91
|
{
|
64
92
|
:pretty => true,
|
@@ -85,6 +113,12 @@ module Rxhp
|
|
85
113
|
end
|
86
114
|
end
|
87
115
|
|
116
|
+
# Normalize the children.
|
117
|
+
#
|
118
|
+
# For example, turn +['foo', 'bar']+ into +['foobar']+.
|
119
|
+
#
|
120
|
+
# This is needed to stop things like pretty printing adding extra
|
121
|
+
# whitespace between the two strings.
|
88
122
|
def flattened_children
|
89
123
|
no_frags = []
|
90
124
|
children.each do |node|
|
data/lib/rxhp/error.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
module Rxhp
|
2
|
+
# Base class for runtime errors from Rxhp.
|
3
|
+
#
|
4
|
+
# Most exceptions in Rxhp are actually subclasses of {Rxhp::ScriptError},
|
5
|
+
# which is not a subclass of this.
|
2
6
|
class Error < ::StandardError
|
3
7
|
end
|
4
8
|
|
9
|
+
# Base class for script errors from Rxhp.
|
5
10
|
class ScriptError < ::ScriptError
|
6
11
|
end
|
7
12
|
|
13
|
+
# Base class for element correctness errors from Rxhp.
|
8
14
|
class ValidationError < Rxhp::ScriptError
|
9
15
|
end
|
10
16
|
end
|
data/lib/rxhp/fragment.rb
CHANGED
@@ -6,6 +6,7 @@ module Rxhp
|
|
6
6
|
# Can be used like an array, or if you just need something that acts like
|
7
7
|
# an element - this is used internally as the root of all render trees.
|
8
8
|
class Fragment < Element
|
9
|
+
# Call {#render_children}
|
9
10
|
def render options = {}
|
10
11
|
self.render_children(options)
|
11
12
|
end
|
data/lib/rxhp/html.rb
CHANGED
@@ -2,7 +2,19 @@ require 'rxhp/data/html/attributes'
|
|
2
2
|
require 'rxhp/data/html/tags'
|
3
3
|
|
4
4
|
module Rxhp
|
5
|
+
# Namespace for all HTML-related classes and methods.
|
6
|
+
#
|
7
|
+
# Most of RXhp is for generic trees; everything that is HTML or XML
|
8
|
+
# specific is defined here, or in {HtmlElement} and its subclasses.
|
5
9
|
module Html
|
10
|
+
# Add a child node.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# include Rxhp::Html
|
14
|
+
# p do
|
15
|
+
# text 'foo'
|
16
|
+
# text 'bar'
|
17
|
+
# end
|
6
18
|
def fragment x
|
7
19
|
Rxhp::Scope.current.children.push x
|
8
20
|
end
|
data/lib/rxhp/html_element.rb
CHANGED
@@ -10,30 +10,38 @@ module Rxhp
|
|
10
10
|
#
|
11
11
|
# To use:
|
12
12
|
# 1. subclass
|
13
|
-
# 2. define tag_name
|
14
|
-
# 3. call Rxhp::Scope.define_element('foo', Foo) to register
|
15
|
-
#
|
13
|
+
# 2. define {#tag_name}
|
14
|
+
# 3. call +Rxhp::Scope.define_element('foo', Foo, MyModule)+ to register
|
15
|
+
# the class
|
16
|
+
# ... or just add a +define_tag+ line to html.rb.
|
16
17
|
#
|
17
18
|
# There's another two base classes for special types of html elements:
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
19
|
+
# {HtmlSelfClosingElement}::: elements where in HTML, the closing tag is
|
20
|
+
# optional - for example, <p> and <li>
|
21
|
+
# {HtmlSingletonElement}::: not only is the closing tag optional, but
|
22
|
+
# child elements are forbidden - for example,
|
23
|
+
# <br> and <img>
|
22
24
|
#
|
23
|
-
# These can also be defined via Rxhp::Html#define_tag
|
25
|
+
# These can also be defined via {Rxhp::Html#define_tag}
|
24
26
|
#
|
25
27
|
# If you're making a custom element that's purely server-side (i.e. is
|
26
|
-
# just composed of HTML elements), you want to subclass
|
27
|
-
# instead.
|
28
|
+
# just composed of HTML elements), you want to subclass
|
29
|
+
# {ComposableElement} instead.
|
28
30
|
class HtmlElement < Element
|
29
31
|
include Rxhp::AttributeValidator
|
30
32
|
accept_attributes Rxhp::Html::GLOBAL_ATTRIBUTES
|
31
33
|
accept_attributes Rxhp::Html::GLOBAL_EVENT_HANDLERS
|
32
34
|
|
35
|
+
# Literal string to include in render output.
|
36
|
+
#
|
37
|
+
# For example, +'html'+ will lead to +'<html>...</html>'+.
|
33
38
|
def tag_name
|
34
39
|
raise NotImplementedError.new
|
35
40
|
end
|
36
41
|
|
42
|
+
# Check that the element usage does nto have detectable errors.
|
43
|
+
#
|
44
|
+
# At the moment, this just checks for attribute correctness.
|
37
45
|
def validate!
|
38
46
|
super
|
39
47
|
validate_attributes!
|
@@ -42,7 +50,7 @@ module Rxhp
|
|
42
50
|
# Render the element.
|
43
51
|
#
|
44
52
|
# Pays attention to the formatter type, doctype, pretty print options,
|
45
|
-
# etc.
|
53
|
+
# etc. See {Element#render} for options.
|
46
54
|
def render options = {}
|
47
55
|
validate!
|
48
56
|
options = fill_options(options)
|
@@ -66,7 +74,9 @@ module Rxhp
|
|
66
74
|
end
|
67
75
|
end
|
68
76
|
|
69
|
-
#
|
77
|
+
# Render child elements.
|
78
|
+
#
|
79
|
+
# Increases the depth count for the sake of pretty printing.
|
70
80
|
def render_children options = {}
|
71
81
|
child_options = options.dup
|
72
82
|
child_options[:depth] += 1
|
@@ -4,11 +4,14 @@ module Rxhp
|
|
4
4
|
# Base class for HTML elements where the closing tag is optional, but
|
5
5
|
# there can still be children.
|
6
6
|
#
|
7
|
-
# For example,
|
7
|
+
# For example, +</p>+ is optional in HTML, but required in XHTML.
|
8
8
|
# This will change whether they're included or not based on the selected
|
9
9
|
# render format.
|
10
10
|
class HtmlSelfClosingElement < HtmlElement
|
11
11
|
protected
|
12
|
+
# Render a close tag if appropriate.
|
13
|
+
#
|
14
|
+
# The close tag is appropriate if we're outputting nice HTML, or XHTML.
|
12
15
|
def render_close_tag options
|
13
16
|
super if options[:format] != Rxhp::TINY_HTML_FORMAT
|
14
17
|
end
|
@@ -4,22 +4,31 @@ require 'rxhp/error'
|
|
4
4
|
module Rxhp
|
5
5
|
# Superclass for all HTML elements that should never have children.
|
6
6
|
#
|
7
|
-
# This is enforced. Examples include
|
7
|
+
# This is enforced. Examples include +<br>+, +<img>+ etc
|
8
8
|
#
|
9
9
|
# There is never a close tag:
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# * in HTML it would be optional (and meaningless) anyway
|
11
|
+
# * people don't expect to see them
|
12
|
+
# * in XHTML, the opening tag will have been self closing.
|
13
13
|
class HtmlSingletonElement < HtmlElement
|
14
|
+
# Exception indicating that you gave a singleton element children.
|
15
|
+
#
|
16
|
+
# For example, +<br>foo</br>+ is invalid.
|
14
17
|
class HasChildrenError < Rxhp::ValidationError
|
15
18
|
end
|
16
19
|
|
20
|
+
# Check that there are no child elements.
|
21
|
+
#
|
22
|
+
# @raises {HasChildrenError}
|
17
23
|
def validate!
|
18
24
|
super
|
19
25
|
raise HasChildrenError.new unless children.empty?
|
20
26
|
end
|
21
27
|
|
22
28
|
protected
|
29
|
+
# Skip the closing tag.
|
30
|
+
#
|
31
|
+
# In XHTML mode, {#render_open_tag} should have made it self-closing.
|
23
32
|
def render_close_tag options
|
24
33
|
nil
|
25
34
|
end
|
data/lib/rxhp/scope.rb
CHANGED
@@ -1,52 +1,82 @@
|
|
1
|
+
require 'continuation' unless RUBY_VERSION =~ /^1\.8\./
|
1
2
|
module Rxhp
|
2
3
|
autoload :Fragment, 'rxhp/fragment'
|
3
4
|
# A place for factory methods to be defined.
|
4
5
|
#
|
5
|
-
# These are methods like Rxhp::Scope#h1 which creates an
|
6
|
-
#
|
6
|
+
# These are methods like +Rxhp::Scope#h1+ which creates an instance of
|
7
|
+
# +Rxhp::Html::H1+.
|
7
8
|
#
|
8
9
|
# The actual HTML classes are defined in rxhp/html.rb
|
9
10
|
#
|
10
11
|
module Scope
|
11
12
|
# Helper function to append a child to the current context.
|
12
|
-
#
|
13
|
+
#
|
14
|
+
# @example Here's one I made earlier
|
13
15
|
# inner = body { 'hi' }
|
14
16
|
# html do
|
15
17
|
# fragment inner
|
16
18
|
# end
|
19
|
+
#
|
20
|
+
# @example Multiple +String+ children
|
21
|
+
# p do
|
22
|
+
# text 'foo'
|
23
|
+
# text 'bar'
|
24
|
+
# end
|
17
25
|
def fragment x
|
18
26
|
Rxhp::Scope.current.children.push x
|
19
27
|
end
|
20
28
|
alias :frag :fragment
|
21
29
|
alias :text :fragment
|
22
30
|
|
31
|
+
# The element nesting scope.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# Rxhp::Scope.current.should be_a Rxhp::Fragment
|
35
|
+
# html.do
|
36
|
+
# Rxhp::Scope.current.should be_a Rxhp::Html::Html
|
37
|
+
# body do
|
38
|
+
# Rxhp::Scope.current.should be_a Rxhp::Html::Body
|
39
|
+
# end
|
40
|
+
# end
|
23
41
|
def self.current
|
24
|
-
|
42
|
+
callcc do |cc|
|
43
|
+
begin
|
44
|
+
throw(:rxhp_parent, cc)
|
45
|
+
rescue NameError, ArgumentError
|
46
|
+
Rxhp::Fragment.new
|
47
|
+
end
|
48
|
+
end
|
25
49
|
end
|
26
50
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
51
|
+
# Set the value of {#current} for a block, and call it.
|
52
|
+
#
|
53
|
+
# Used by {#define_element}
|
54
|
+
def self.with_parent parent, &block
|
55
|
+
# push element onto the render stack...
|
56
|
+
cc = catch(:rxhp_parent) do
|
57
|
+
# ... and call the block with that new stack
|
58
|
+
block.call
|
59
|
+
nil
|
34
60
|
end
|
35
|
-
|
61
|
+
cc.call(parent) if cc
|
36
62
|
end
|
37
63
|
|
38
|
-
# Define
|
64
|
+
# Define a factory method that takes a block, with a scope.
|
65
|
+
#
|
66
|
+
# @param [String] name is the name of the method to define
|
67
|
+
# @param [Class] klass is the {Element} subclass to construct
|
68
|
+
# @param [Module] namespace is where to define the method
|
39
69
|
#
|
40
|
-
#
|
70
|
+
# @example
|
71
|
+
# define_element tag, Tag
|
72
|
+
# tag
|
41
73
|
# tag 'content'
|
42
|
-
# tag
|
43
|
-
# tag
|
44
|
-
# tag(:attribute=>'value') do
|
45
|
-
# content
|
74
|
+
# tag(:attribute => value)
|
75
|
+
# tag('content', :attribute => 'value')
|
76
|
+
# tag(:attribute => 'value') do
|
77
|
+
# text 'content'
|
46
78
|
# end
|
47
|
-
|
48
|
-
# tag (:attribute => value)
|
49
|
-
def self.define_element name, klass, namespace
|
79
|
+
def self.define_element name, klass, namespace = Kernel
|
50
80
|
impl = Proc.new do |*args, &block|
|
51
81
|
# Yay for faking named parameters as a hash :p
|
52
82
|
children = nil
|
@@ -101,11 +131,5 @@ module Rxhp
|
|
101
131
|
# end
|
102
132
|
(class <<namespace; self; end).send(:define_method, name, impl)
|
103
133
|
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
def self.stack
|
108
|
-
Thread.current[:rxhp_scope_stack] ||= []
|
109
|
-
end
|
110
134
|
end
|
111
135
|
end
|
data/lib/rxhp/tags/html_tag.rb
CHANGED
metadata
CHANGED
@@ -1,33 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rxhp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 1
|
10
|
-
version: 0.1.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Fred Emmott
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2012-01-23 00:00:00 Z
|
12
|
+
date: 2012-01-26 00:00:00.000000000Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
14
|
description: An object-oriented validating HTML template system
|
22
|
-
email:
|
15
|
+
email:
|
23
16
|
- rxhp-gem@fredemmott.co.uk
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- lib/rxhp/attribute_validator.rb
|
32
22
|
- lib/rxhp/composable_element.rb
|
33
23
|
- lib/rxhp/constants.rb
|
@@ -45,36 +35,27 @@ files:
|
|
45
35
|
- lib/rxhp.rb
|
46
36
|
homepage: https://github.com/fredemmott/rxhp
|
47
37
|
licenses: []
|
48
|
-
|
49
38
|
post_install_message:
|
50
39
|
rdoc_options: []
|
51
|
-
|
52
|
-
require_paths:
|
40
|
+
require_paths:
|
53
41
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
43
|
none: false
|
56
|
-
requirements:
|
57
|
-
- -
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
|
60
|
-
|
61
|
-
- 0
|
62
|
-
version: "0"
|
63
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
49
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
segments:
|
70
|
-
- 0
|
71
|
-
version: "0"
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
72
54
|
requirements: []
|
73
|
-
|
74
55
|
rubyforge_project:
|
75
56
|
rubygems_version: 1.8.6
|
76
57
|
signing_key:
|
77
58
|
specification_version: 3
|
78
59
|
summary: An object-oriented validating HTML template system
|
79
60
|
test_files: []
|
80
|
-
|
61
|
+
has_rdoc:
|