rxhp 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: