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.
@@ -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
- def self.name_from_symbol symbol
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
@@ -1,10 +1,17 @@
1
1
  module Rxhp
2
- # Basic output formats
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'], match:
6
- # - 'foo'
7
- # - 'bar baz'
8
- # - 'foo bar baz'
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
- attr_accessor :attributes, :children
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 Rxhp::Fragment, Rxhp::HtmlElement, and
41
- # Rxhp::ComposableElement
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 Rxhp::HtmlElement.
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
@@ -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 the class
15
- # ... or just add a define_tag line to html.rb.
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
- # - HtmlSelfClosingElement - elements where in HTML, the closing tag is
19
- # optional - for example, <p>, <li>, and <body>
20
- # - HtmlSingletonElement - not only is the closing tag optional, but
21
- # child elements are forbidden - for example, <br> and <img>
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 ComposableElement
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
- # Override to increase the depth count for the sake of pretty printing
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, </p> is optional in HTML, but required in XHTML.
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 '<br>', '<img>' etc
7
+ # This is enforced. Examples include +<br>+, +<img>+ etc
8
8
  #
9
9
  # There is never a close tag:
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.
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 Rxhp::Html::H1
6
- # instance.
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
- # Allows you to do this:
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
- self.stack.last || Rxhp::Fragment.new
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
- def self.with_parent parent
28
- result = nil
29
- begin
30
- self.stack.push parent
31
- result = yield
32
- ensure
33
- self.stack.pop
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
- result
61
+ cc.call(parent) if cc
36
62
  end
37
63
 
38
- # Define the factory method.
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
- # can be called like:
70
+ # @example
71
+ # define_element tag, Tag
72
+ # tag
41
73
  # tag 'content'
42
- # tag { content }
43
- # tag 'content', :attribute => 'value'
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
- # tag
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
@@ -3,6 +3,9 @@ require 'rxhp/scope'
3
3
 
4
4
  module Rxhp
5
5
  module Html
6
+ # Special-case for the <html> tag.
7
+ #
8
+ # This handles doctype rendering.
6
9
  class Html < HtmlSelfClosingElement
7
10
  def tag_name; 'html'; end
8
11
 
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
- hash: 25
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
- hash: 3
60
- segments:
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
- hash: 3
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: