rml 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rml +17 -0
- data/lib/rml.rb +290 -0
- data/lib/rml/sinatra.rb +25 -0
- data/lib/rsm.rb +185 -0
- data/lib/tags.rb +418 -0
- metadata +57 -0
data/bin/rml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rml'
|
3
|
+
|
4
|
+
if ARGV[0].nil?
|
5
|
+
puts "/*********************************\\"
|
6
|
+
puts "* *"
|
7
|
+
puts "* RML: Ruby Markup Language *"
|
8
|
+
puts "* *"
|
9
|
+
puts "* Usage: *"
|
10
|
+
puts "* rml my_template.rml *"
|
11
|
+
puts "* *"
|
12
|
+
puts "* Output: Valid XHTML 1.0 *"
|
13
|
+
puts "* *"
|
14
|
+
puts "\\*********************************/"
|
15
|
+
else
|
16
|
+
puts RML.new.markup_file(ARGV[0])
|
17
|
+
end
|
data/lib/rml.rb
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
# ==RML: Ruby template engine
|
2
|
+
#
|
3
|
+
# Pure ruby xhtml markup language. Similar to Markaby, but with one big difference.
|
4
|
+
# RML is aimed to provide valid and only valid xhtml 1.0.
|
5
|
+
# It's mean, you got exception in runtime, if try to write not valid xhtml.
|
6
|
+
#
|
7
|
+
# ====Example:
|
8
|
+
# doctype!
|
9
|
+
# html do
|
10
|
+
# head { title 'RML Test' }
|
11
|
+
# body do
|
12
|
+
# div_main do
|
13
|
+
# div_menu do
|
14
|
+
# {"ruby!" => "ruby-lang.org", "gems!" => "rubyforge.org", "doc!" => "ruby-doc.org"}.each_pair do |t, s|
|
15
|
+
# a t, :href => s
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# div_content do
|
19
|
+
# h1 "Try RML"
|
20
|
+
# end
|
21
|
+
# div_footer do
|
22
|
+
# p "Generated by RML", :style => "text-align: center"
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# to insert DOCTYPE definition use doctype!
|
30
|
+
#
|
31
|
+
# to specify element id use '_'
|
32
|
+
# p_test "test" #=> <p id="test">test</p>
|
33
|
+
#
|
34
|
+
# to specify element class use '.'
|
35
|
+
# p.test "test" #=> <p class="test">test</p>
|
36
|
+
#
|
37
|
+
# you can use multiple classes for element
|
38
|
+
# p.test.test1 "test" #=> <p class="test test1">test</p>
|
39
|
+
#
|
40
|
+
# if you want to mix tags and text in parent tag, use method text:
|
41
|
+
# div.text do
|
42
|
+
# text "this is"
|
43
|
+
# br
|
44
|
+
# text "div with text"
|
45
|
+
# end
|
46
|
+
# also, you can use data method, to insert unescaped text,
|
47
|
+
# for example, result of the method, providing html:
|
48
|
+
# div.text do
|
49
|
+
# data "<p>some html</p>"
|
50
|
+
# data gen_html
|
51
|
+
# end
|
52
|
+
# use data method carefully! there's no validation for it
|
53
|
+
#
|
54
|
+
# you can use templatesin separate files, for example:
|
55
|
+
# div.external do
|
56
|
+
# rml :external #load 'external.rml' here
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# all code validating according to XHTML 1.0 DTD(not fully implemented yet) i.e.:
|
60
|
+
# td :width => "20%" #=> Attribute 'width' not allowed for tag <td> (AttrNotAllowedException)
|
61
|
+
# head { p "p in head"} #=> Tag <head> should't contain child tag <p> (TagNotAllowedException)
|
62
|
+
#
|
63
|
+
# mayby, for some reasons you want to disable xhtml validation,
|
64
|
+
# to do it use method dirty :
|
65
|
+
# dirty do
|
66
|
+
# td :width => "20%" # no exception here!
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# ====Limitations
|
70
|
+
# - to use attributes containing ':' or '-', instead standart syntax :attr use 'attr'.to_sym
|
71
|
+
# - you can't use css classes and ids containing '-' with '_' and '.',
|
72
|
+
# instead of div_id-with-dash or div.class-with-dash use div :class => "class_with_dash" and div :id => "id_with_dash"
|
73
|
+
require 'cgi'
|
74
|
+
require File.dirname(__FILE__)+'/tags'
|
75
|
+
require File.dirname(__FILE__)+'/rsm'
|
76
|
+
|
77
|
+
|
78
|
+
class AttrNotAllowedException < Exception
|
79
|
+
end
|
80
|
+
|
81
|
+
class AttrRequiredException < Exception
|
82
|
+
end
|
83
|
+
|
84
|
+
class TagNotAllowedException < Exception
|
85
|
+
end
|
86
|
+
|
87
|
+
class TextNotAllowedException < Exception
|
88
|
+
end
|
89
|
+
|
90
|
+
class AttributeException < Exception
|
91
|
+
end
|
92
|
+
|
93
|
+
class String
|
94
|
+
def tab n=1
|
95
|
+
if self.count("\n") > 1
|
96
|
+
self.split("\r\n").collect { |s| "\t"*n + s }.join("\r\n")
|
97
|
+
else
|
98
|
+
"\t"*n + self
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class RML
|
104
|
+
|
105
|
+
def initialize
|
106
|
+
@dirty = false
|
107
|
+
reinit
|
108
|
+
end
|
109
|
+
|
110
|
+
def reinit
|
111
|
+
@tag_stack = []
|
112
|
+
@html = ''
|
113
|
+
@tag_css = nil
|
114
|
+
@css_classes = []
|
115
|
+
end
|
116
|
+
|
117
|
+
def allow_dirty_code d
|
118
|
+
@dirty = d
|
119
|
+
end
|
120
|
+
|
121
|
+
def use_bound b
|
122
|
+
@bound = b
|
123
|
+
end
|
124
|
+
|
125
|
+
def method_missing sym, *args, &block
|
126
|
+
args.flatten!
|
127
|
+
if @tag_css
|
128
|
+
@css_classes << sym
|
129
|
+
if not args.empty? or not block.nil?
|
130
|
+
tag = @tag_css
|
131
|
+
@tag_css = nil
|
132
|
+
classes = @css_classes.join(' ')
|
133
|
+
@css_classes = []
|
134
|
+
method_missing tag, add_attr(args, :class => classes), &block
|
135
|
+
end
|
136
|
+
elsif Tags.keys.include? sym
|
137
|
+
if args.empty? and block.nil? and not Tags[sym][:tags].empty?
|
138
|
+
@tag_css = sym
|
139
|
+
else
|
140
|
+
process_tag sym, args, &block
|
141
|
+
end
|
142
|
+
elsif Tags.keys.include? sym.to_s.split('_')[0].to_sym
|
143
|
+
if args.empty? and block.nil? and not Tags[sym.to_s.split('_')[0].to_sym][:tags].empty?
|
144
|
+
@tag_css = sym
|
145
|
+
else
|
146
|
+
process_tag sym.to_s.split('_')[0].to_sym, add_attr(args, :id => sym.to_s.split('_')[1]), &block
|
147
|
+
end
|
148
|
+
else
|
149
|
+
raise NoMethodError, "Undefined method '#{sym}'"
|
150
|
+
end
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
def process_tag name, attrs, &block
|
155
|
+
raise TagNotAllowedException, "Tag <#{@tag_stack.last}> should't contain child tag <#{name}>" unless @tag_stack.empty? or Tags[@tag_stack.last][:tags].include? name or @dirty
|
156
|
+
css = ''
|
157
|
+
content = ''
|
158
|
+
attr_str = ''
|
159
|
+
|
160
|
+
attributes = get_attrs(attrs)
|
161
|
+
content = get_content(attrs)
|
162
|
+
|
163
|
+
if not attributes.nil?
|
164
|
+
attributes.keys.each do |a|
|
165
|
+
raise AttrNotAllowedException, "Attribute '#{a}' not allowed for tag <#{name}>" unless Tags[name][:attrs].include? a or @dirty
|
166
|
+
end
|
167
|
+
Tags[name][:required_attrs].each do |a|
|
168
|
+
raise AttrRequiredException, "Attribute '#{a}' required for tag <#{name}>" unless attributes.include? a or @dirty
|
169
|
+
end
|
170
|
+
attributes.each_pair do |k,v|
|
171
|
+
attr_str += " #{k}=\"#{CGI.escapeHTML(v.to_s)}\""
|
172
|
+
end
|
173
|
+
else
|
174
|
+
raise AttrRequiredException, "Attributes '#{Tags[name][:required_attrs].join(', ')}' required for tag <#{name}>" unless Tags[name][:required_attrs].empty? or @dirty
|
175
|
+
end
|
176
|
+
|
177
|
+
if block
|
178
|
+
@html += "<#{name.to_s+attr_str}>#{content}\r\n".tab(@tag_stack.length)
|
179
|
+
@tag_stack << name
|
180
|
+
instance_eval &block
|
181
|
+
@html += "</#{@tag_stack.pop}>\r\n".tab(@tag_stack.length)
|
182
|
+
else
|
183
|
+
if Tags[name][:tags].empty? or content.empty?
|
184
|
+
@html += "<#{name.to_s+attr_str} />\r\n".tab(@tag_stack.length)
|
185
|
+
else
|
186
|
+
@html += "<#{name.to_s+attr_str}>#{content}</#{name}>\r\n".tab(@tag_stack.length)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
192
|
+
# args -
|
193
|
+
# [0] args
|
194
|
+
# [0] Hash or String
|
195
|
+
# [1] Hash or String
|
196
|
+
# [1] hash => params
|
197
|
+
|
198
|
+
def add_attr *args
|
199
|
+
i = 0
|
200
|
+
i = 1 if args[0][0].class == String
|
201
|
+
args[0][i] = {} if args[0][i].nil? or args[0][i].class != Hash
|
202
|
+
args[1].each_pair do |k,v|
|
203
|
+
args[0][i][k] = v
|
204
|
+
end
|
205
|
+
args[0]
|
206
|
+
end
|
207
|
+
|
208
|
+
def get_content args
|
209
|
+
i = -1
|
210
|
+
i = 0 if args[0].class == String
|
211
|
+
i = 1 if args[1].class == String
|
212
|
+
return CGI.escapeHTML(args[i]) if i >= 0
|
213
|
+
''
|
214
|
+
end
|
215
|
+
|
216
|
+
def get_attrs args
|
217
|
+
i = -1
|
218
|
+
i = 0 if args[0].class == Hash
|
219
|
+
i = 1 if args[1].class == Hash
|
220
|
+
return args[i] if i >= 0
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def dirty &block
|
225
|
+
@dirty = true
|
226
|
+
instance_eval &block
|
227
|
+
@dirty = false
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
def html *attrs, &block
|
232
|
+
method_missing :html, add_attr(attrs, :xmlns => "http://www.w3.org/1999/xhtml"), &block
|
233
|
+
end
|
234
|
+
|
235
|
+
def p *attrs, &block
|
236
|
+
method_missing :p, attrs, &block
|
237
|
+
end
|
238
|
+
|
239
|
+
def headfix *attrs, &block
|
240
|
+
method_missing :head, attrs, &block
|
241
|
+
end
|
242
|
+
|
243
|
+
def text t
|
244
|
+
raise TextNotAllowedException, "Tag <#{@tag_stack.last}> should't contain text" unless Tags[@tag_stack.last][:tags].include?(:pcdata) or @dirty
|
245
|
+
@html += CGI.escapeHTML(t).tab(@tag_stack.length)+"\r\n"
|
246
|
+
end
|
247
|
+
|
248
|
+
def data t
|
249
|
+
@html += t
|
250
|
+
end
|
251
|
+
|
252
|
+
def doctype!
|
253
|
+
@html += '<?xml version="1.0" encoding="utf-8" ?>'+"\r\n"
|
254
|
+
@html += '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' + "\r\n"
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
def markup_file file
|
259
|
+
tmpl = ''
|
260
|
+
begin
|
261
|
+
tmpl = File.open(file).read
|
262
|
+
rescue
|
263
|
+
raise "Can't open file: #{file}"
|
264
|
+
end
|
265
|
+
instance_eval tmpl
|
266
|
+
end
|
267
|
+
|
268
|
+
def markup &proc
|
269
|
+
instance_eval &proc
|
270
|
+
self
|
271
|
+
end
|
272
|
+
|
273
|
+
def to_s
|
274
|
+
@html
|
275
|
+
end
|
276
|
+
|
277
|
+
def rml file
|
278
|
+
markup_file file.to_s + ".rml"
|
279
|
+
end
|
280
|
+
#todo add cdata to script and style
|
281
|
+
def rsm file, &block
|
282
|
+
s = RSM.new
|
283
|
+
if not file.nil?
|
284
|
+
s.markup File.open(file.to_s + ".rsm").read
|
285
|
+
else
|
286
|
+
s.markup &block
|
287
|
+
end
|
288
|
+
process_tag :style, [s.to_s, {:type => 'text/html'}]
|
289
|
+
end
|
290
|
+
end
|
data/lib/rml/sinatra.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../rml'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module RML
|
5
|
+
|
6
|
+
def rml(content, options={})
|
7
|
+
require 'rml'
|
8
|
+
render(:rml, content, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def render_rml(content, options = {}, &b)
|
14
|
+
rml_options = (options[:options] || {})
|
15
|
+
r = ::RML.new
|
16
|
+
r.allow_dirty_code true if rml_options[:dirty]
|
17
|
+
r.instance_eval content
|
18
|
+
r.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
class EventContext
|
23
|
+
include RML
|
24
|
+
end
|
25
|
+
end
|
data/lib/rsm.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# Syntax:
|
2
|
+
# _main {
|
3
|
+
# padding.left '0px'
|
4
|
+
# }
|
5
|
+
# provide:
|
6
|
+
# #main {
|
7
|
+
# padding-left: 0px
|
8
|
+
# }
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# main {
|
12
|
+
# padding.left '0px'
|
13
|
+
# }
|
14
|
+
# provide:
|
15
|
+
# .main {
|
16
|
+
# padding-left: 0px
|
17
|
+
# }
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# tr {
|
21
|
+
# padding.left '0px'
|
22
|
+
# }
|
23
|
+
# provide:
|
24
|
+
# tr {
|
25
|
+
# padding-left: 0px
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# div.main {
|
30
|
+
# padding.left '0px'
|
31
|
+
# }
|
32
|
+
# provide:
|
33
|
+
# div.main {
|
34
|
+
# padding-left: 0px
|
35
|
+
# }
|
36
|
+
#
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# body_div_p {
|
40
|
+
# padding '0px'
|
41
|
+
# }
|
42
|
+
# provide:
|
43
|
+
# body, div, p {
|
44
|
+
# padding: 0px
|
45
|
+
# }
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# ugly, but no idea how to do better
|
49
|
+
# body{div{
|
50
|
+
# padding '0px'
|
51
|
+
# }}
|
52
|
+
# provide:
|
53
|
+
# body div {
|
54
|
+
# padding: 0px
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
#
|
58
|
+
# includes for reusable styles
|
59
|
+
# inc! {
|
60
|
+
# color 'white'
|
61
|
+
# }
|
62
|
+
# _main {
|
63
|
+
# inc!
|
64
|
+
# text.align 'center'
|
65
|
+
# }
|
66
|
+
# provide:
|
67
|
+
# #main {
|
68
|
+
# color: white
|
69
|
+
# text-align: center
|
70
|
+
# }
|
71
|
+
require File.dirname(__FILE__)+'/tags'
|
72
|
+
|
73
|
+
class RSM
|
74
|
+
def initialize
|
75
|
+
@block = false
|
76
|
+
@prev_block = false
|
77
|
+
@styles = ''
|
78
|
+
@css = ''
|
79
|
+
@attr = false #for attrs with dash
|
80
|
+
@tag_class = false #for div.class
|
81
|
+
@includes = {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def block= val
|
85
|
+
@block = val
|
86
|
+
end
|
87
|
+
|
88
|
+
def method_missing sym, *args, &block
|
89
|
+
if @block
|
90
|
+
if not block.nil? and @prev_block
|
91
|
+
#body{div{p{
|
92
|
+
process_style sym, *args, &block
|
93
|
+
end
|
94
|
+
@css += " {\r\n" if @prev_block
|
95
|
+
if block.nil?
|
96
|
+
if args.empty?
|
97
|
+
if @includes.include? sym
|
98
|
+
@css += @includes[sym]
|
99
|
+
else
|
100
|
+
@css+="\t#{sym}-"
|
101
|
+
@attr = true
|
102
|
+
end
|
103
|
+
else
|
104
|
+
@css += "\t" unless @attr
|
105
|
+
@css+="#{sym}: #{args.join(" ")}\r\n"
|
106
|
+
@attr = false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@prev_block = false
|
110
|
+
else
|
111
|
+
if block.nil? and args.empty?
|
112
|
+
@css += sym.to_s
|
113
|
+
elsif sym.to_s[-1] == ?!
|
114
|
+
r = RSM.new
|
115
|
+
r.block = true
|
116
|
+
r.markup &block
|
117
|
+
@includes[sym] = r.to_s
|
118
|
+
else
|
119
|
+
@block = true
|
120
|
+
@prev_block = true
|
121
|
+
process_style sym, args, &block
|
122
|
+
@block = false
|
123
|
+
@css += "}\r\n\r\n"
|
124
|
+
@tag_class = false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
def process_style name, *args, &block
|
131
|
+
if name.to_s[0] == ?_
|
132
|
+
@css += "##{name.to_s[1..-1]}"
|
133
|
+
elsif Tags.include? name.to_s.split('_')[0].to_sym
|
134
|
+
@css += "." if @tag_class
|
135
|
+
@css += "#{name.to_s.split('_').join(', ')} "
|
136
|
+
@prev_class = true if block.nil?
|
137
|
+
@tag_class = true if block.nil?
|
138
|
+
else
|
139
|
+
@css += ".#{name} "
|
140
|
+
end
|
141
|
+
instance_eval &block unless block.nil?
|
142
|
+
end
|
143
|
+
|
144
|
+
def markup str=nil, &block
|
145
|
+
if str.nil?
|
146
|
+
instance_eval &block
|
147
|
+
else
|
148
|
+
instance_eval str
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def to_s
|
153
|
+
@css
|
154
|
+
end
|
155
|
+
end
|
156
|
+
#r = RSM.new
|
157
|
+
#r.markup do
|
158
|
+
# _main {
|
159
|
+
# padding.left '0px'
|
160
|
+
# }
|
161
|
+
# main {
|
162
|
+
# padding.left '0px'
|
163
|
+
# }
|
164
|
+
# tr {
|
165
|
+
# padding.left '0px'
|
166
|
+
# }
|
167
|
+
# div.main {
|
168
|
+
# padding.left '0px'
|
169
|
+
# }
|
170
|
+
# body_div_p {
|
171
|
+
# padding '0px'
|
172
|
+
# }
|
173
|
+
# body{div{
|
174
|
+
# padding '0px'
|
175
|
+
# }}
|
176
|
+
# inc! {
|
177
|
+
# color 'white'
|
178
|
+
# }
|
179
|
+
# _main {
|
180
|
+
# inc!
|
181
|
+
# text.align 'center'
|
182
|
+
# }
|
183
|
+
|
184
|
+
#end
|
185
|
+
#puts r.to_s
|
data/lib/tags.rb
ADDED
@@ -0,0 +1,418 @@
|
|
1
|
+
AttrI18n = [:lang, 'xml:lang'.to_sym, :dir]
|
2
|
+
AttrCore = [:id, :class, :style, :title]
|
3
|
+
AttrEvents = [:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover, :onmousemove, :onmouseout, :onkeypress, :onkeydown, :onkeyup]
|
4
|
+
AttrFocus = [:accesskey, :tabindex, :onfocus, :onblur]
|
5
|
+
AttrCellAlign = [:align, :char, :charoff, :valign]
|
6
|
+
|
7
|
+
Attrs = AttrI18n + AttrCore + AttrEvents
|
8
|
+
AttrAll = [:xmlns, :profile, 'http-equip'.to_sym, :content, :scheme, :charset, :hreflang, :type, :rel, :rev, :media, 'xml:space'.to_sym, :src, :defer, :onload, :onuload, :cite, :datetime, :shape, :coords, :declare, :classid, :codebase, :data, :codetype, :archive, :standby, :height, :width, :usemap, :name, :value, :valuetype, :alt, :longdesc, :ismap, :nohref, :action, :method, :enctype, :onsubmit, :onreset, :accept, 'accept-charset'.to_sym, :for, :checked, :disabled, :readonly, :size, :maxlength, :onselect, :onchange, :multiple, :label, :selected, :summary, :border, :frame, :rules, :cellpadding, :cellspacing, :span, :abbr, :axis, :headers, :scope, :rowspan, :ccolspan] + Attrs + AttrFocus + AttrCellAlign
|
9
|
+
|
10
|
+
TagsSpecialPre = [:br, :span, :bdo, :map]
|
11
|
+
TagsSpecial = [:object, :img] + TagsSpecialPre
|
12
|
+
TagsFontStyle = [:tt, :i, :b, :big, :small]
|
13
|
+
TagsPhrase = [:em, :strong, :dfn, :code, :q, :samp, :kbd, :var, :cite, :abbr, :acronym, :sub, :sup]
|
14
|
+
TagsInlineForms = [:input, :select, :textarea, :label, :button]
|
15
|
+
TagsMiscInline = [:ins, :del, :script]
|
16
|
+
TagsMisc = [:noscript] + TagsMiscInline
|
17
|
+
TagsInline = [:a] + TagsSpecial + TagsFontStyle + TagsPhrase + TagsInlineForms
|
18
|
+
TagsInlineAll = [:pcdata] + TagsInline + TagsMiscInline
|
19
|
+
TagsHeading = [:h1, :h2, :h3, :h4, :h5, :h6]
|
20
|
+
TagsLists = [:ul, :ol, :dl]
|
21
|
+
TagsBlockText = [:pre, :hr, :blockquote, :address]
|
22
|
+
TagsBlock = [:p, :div, :table, :fieldset] + TagsHeading + TagsLists + TagsBlockText
|
23
|
+
TagsBlockAll = [:form] + TagsBlock + TagsMisc
|
24
|
+
TagsFlow = [:pcdata, :form] + TagsBlock + TagsInline + TagsMisc
|
25
|
+
TagsAContent = [:pcdata] + TagsSpecial + TagsFontStyle + TagsPhrase + TagsInlineForms + TagsMiscInline
|
26
|
+
TagsPreContent = [:pcdata, :a] + TagsFontStyle + TagsPhrase + TagsSpecialPre + TagsInlineForms + TagsMiscInline
|
27
|
+
TagsFormContent = TagsBlock + TagsMisc
|
28
|
+
TagsButtonContent = [:pcdata, :div, :table] + TagsHeading + TagsLists + TagsBlockText + TagsSpecial + TagsFontStyle + TagsPhrase + TagsMisc
|
29
|
+
TagsHeadMisc = [:script, :style, :meta, :link, :object]
|
30
|
+
#todo add tags
|
31
|
+
Tags = {
|
32
|
+
:html => {
|
33
|
+
:attrs => [:id, :xmlns] + AttrI18n,
|
34
|
+
:tags => [:head, :body],
|
35
|
+
:required_attrs => [],
|
36
|
+
},
|
37
|
+
:head => {
|
38
|
+
:attrs => [:id, :profile] + AttrI18n,
|
39
|
+
:tags => [:title, :base] + TagsHeadMisc,
|
40
|
+
:required_attrs => [],
|
41
|
+
},
|
42
|
+
:title => {
|
43
|
+
:attrs => [:id] + AttrI18n,
|
44
|
+
:tags => [:pcdata],
|
45
|
+
:required_attrs => [],
|
46
|
+
},
|
47
|
+
:base => {
|
48
|
+
:attrs => [:id, :href],
|
49
|
+
:tags => [],
|
50
|
+
:required_attrs => [:href],
|
51
|
+
},
|
52
|
+
:meta => {
|
53
|
+
:attrs => [:id, 'http-equip'.to_sym, :name, :content, :scheme] + AttrI18n,
|
54
|
+
:tags => [],
|
55
|
+
:required_attrs => [:content],
|
56
|
+
},
|
57
|
+
:link => {
|
58
|
+
:attrs => [:charset, :href, :hreflang, :type, :rel, :rev, :media] + Attrs,
|
59
|
+
:tags => [],
|
60
|
+
:required_attrs => [],
|
61
|
+
},
|
62
|
+
:style => {
|
63
|
+
:attrs => [:id, :type, :media, :title, 'xml:space'.to_sym] + AttrI18n,
|
64
|
+
:tags => [:pcdata],
|
65
|
+
:required_attrs => [:type],
|
66
|
+
},
|
67
|
+
:script => {
|
68
|
+
:attrs => [:id, :charset, :type, :src, :defer, 'xml:space'.to_sym],
|
69
|
+
:tags => [:pcdata],
|
70
|
+
:required_attrs => [:type],
|
71
|
+
},
|
72
|
+
:noscript => {
|
73
|
+
:attrs => Attrs,
|
74
|
+
:tags => TagsBlockAll,
|
75
|
+
:required_attrs => [],
|
76
|
+
},
|
77
|
+
:body => {
|
78
|
+
:attrs => [:onload, :onuload] + Attrs,
|
79
|
+
:tags => TagsBlockAll,
|
80
|
+
:required_attrs => [],
|
81
|
+
},
|
82
|
+
:div => {
|
83
|
+
:attrs => Attrs,
|
84
|
+
:tags => TagsFlow,
|
85
|
+
:required_attrs => [],
|
86
|
+
},
|
87
|
+
:p => {
|
88
|
+
:attrs => Attrs,
|
89
|
+
:tags => TagsInlineAll,
|
90
|
+
:required_attrs => [],
|
91
|
+
},
|
92
|
+
:h1 => {
|
93
|
+
:attrs => Attrs,
|
94
|
+
:tags => TagsInlineAll,
|
95
|
+
:required_attrs => [],
|
96
|
+
},
|
97
|
+
:h2 => {
|
98
|
+
:attrs => Attrs,
|
99
|
+
:tags => TagsInlineAll,
|
100
|
+
:required_attrs => [],
|
101
|
+
},
|
102
|
+
:h3 => {
|
103
|
+
:attrs => Attrs,
|
104
|
+
:tags => TagsInlineAll,
|
105
|
+
:required_attrs => [],
|
106
|
+
},
|
107
|
+
:h4 => {
|
108
|
+
:attrs => Attrs,
|
109
|
+
:tags => TagsInlineAll,
|
110
|
+
:required_attrs => [],
|
111
|
+
},
|
112
|
+
:h5 => {
|
113
|
+
:attrs => Attrs,
|
114
|
+
:tags => TagsInlineAll,
|
115
|
+
:required_attrs => [],
|
116
|
+
},
|
117
|
+
:h6 => {
|
118
|
+
:attrs => Attrs,
|
119
|
+
:tags => TagsInlineAll,
|
120
|
+
:required_attrs => [],
|
121
|
+
},
|
122
|
+
:ul => {
|
123
|
+
:attrs => Attrs,
|
124
|
+
:tags => [:li],
|
125
|
+
:required_attrs => [],
|
126
|
+
},
|
127
|
+
:ol => {
|
128
|
+
:attrs => Attrs,
|
129
|
+
:tags => [:li],
|
130
|
+
:required_attrs => [],
|
131
|
+
},
|
132
|
+
:li => {
|
133
|
+
:attrs => Attrs,
|
134
|
+
:tags => TagsFlow,
|
135
|
+
:required_attrs => [],
|
136
|
+
},
|
137
|
+
:dl => {
|
138
|
+
:attrs => Attrs,
|
139
|
+
:tags => [:dt, :dd],
|
140
|
+
:required_attrs => [],
|
141
|
+
},
|
142
|
+
:dt => {
|
143
|
+
:attrs => Attrs,
|
144
|
+
:tags => TagsInlineAll,
|
145
|
+
:required_attrs => [],
|
146
|
+
},
|
147
|
+
:dd => {
|
148
|
+
:attrs => Attrs,
|
149
|
+
:tags => TagsFlow,
|
150
|
+
:required_attrs => [],
|
151
|
+
},
|
152
|
+
:address => {
|
153
|
+
:attrs => Attrs,
|
154
|
+
:tags => TagsInlineAll,
|
155
|
+
:required_attrs => [],
|
156
|
+
},
|
157
|
+
:hr => {
|
158
|
+
:attrs => Attrs,
|
159
|
+
:tags => [],
|
160
|
+
:required_attrs => [],
|
161
|
+
},
|
162
|
+
:pre => {
|
163
|
+
:attrs => ['xml:space'.to_sym] + Attrs,
|
164
|
+
:tags => TagsPreContent,
|
165
|
+
:required_attrs => [],
|
166
|
+
},
|
167
|
+
:blockquote => {
|
168
|
+
:attrs => [:cite] + Attrs,
|
169
|
+
:tags => TagsBlockAll,
|
170
|
+
:required_attrs => [],
|
171
|
+
},
|
172
|
+
:ins => {
|
173
|
+
:attrs => [:cite, :datetime] + Attrs,
|
174
|
+
:tags => TagsFlow,
|
175
|
+
:required_attrs => [],
|
176
|
+
},
|
177
|
+
:del => {
|
178
|
+
:attrs => [:cite, :datetime] + Attrs,
|
179
|
+
:tags => TagsFlow,
|
180
|
+
:required_attrs => [],
|
181
|
+
},
|
182
|
+
:a => {
|
183
|
+
:attrs => [:charset, :type, :name, :href, :hreflang, :rel, :rev, :shape, :coords] + Attrs + AttrFocus,
|
184
|
+
:tags => TagsAContent,
|
185
|
+
:required_attrs => [],
|
186
|
+
},
|
187
|
+
:span => {
|
188
|
+
:attrs => Attrs,
|
189
|
+
:tags => TagsInlineAll,
|
190
|
+
:required_attrs => [],
|
191
|
+
},
|
192
|
+
:bdo => {
|
193
|
+
:attrs => [:lang, 'xml:lang'.to_sym, :dir] + AttrCore + AttrEvents,
|
194
|
+
:tags => TagsInlineAll,
|
195
|
+
:required_attrs => [:dir],
|
196
|
+
},
|
197
|
+
:br => {
|
198
|
+
:attrs => AttrCore,
|
199
|
+
:tags => [],
|
200
|
+
:required_attrs => [],
|
201
|
+
},
|
202
|
+
:strong => {
|
203
|
+
:attrs => Attrs,
|
204
|
+
:tags => TagsInlineAll,
|
205
|
+
:required_attrs => [],
|
206
|
+
},
|
207
|
+
:dfn => {
|
208
|
+
:attrs => Attrs,
|
209
|
+
:tags => TagsInlineAll,
|
210
|
+
:required_attrs => [],
|
211
|
+
},
|
212
|
+
:em => {
|
213
|
+
:attrs => Attrs,
|
214
|
+
:tags => TagsInlineAll,
|
215
|
+
:required_attrs => [],
|
216
|
+
},
|
217
|
+
:code => {
|
218
|
+
:attrs => Attrs,
|
219
|
+
:tags => TagsInlineAll,
|
220
|
+
:required_attrs => [],
|
221
|
+
},
|
222
|
+
:samp => {
|
223
|
+
:attrs => Attrs,
|
224
|
+
:tags => TagsInlineAll,
|
225
|
+
:required_attrs => [],
|
226
|
+
},
|
227
|
+
:kbd => {
|
228
|
+
:attrs => Attrs,
|
229
|
+
:tags => TagsInlineAll,
|
230
|
+
:required_attrs => [],
|
231
|
+
},
|
232
|
+
:var => {
|
233
|
+
:attrs => Attrs,
|
234
|
+
:tags => TagsInlineAll,
|
235
|
+
:required_attrs => [],
|
236
|
+
},
|
237
|
+
:cite => {
|
238
|
+
:attrs => Attrs,
|
239
|
+
:tags => TagsInlineAll,
|
240
|
+
:required_attrs => [],
|
241
|
+
},
|
242
|
+
:abbr => {
|
243
|
+
:attrs => Attrs,
|
244
|
+
:tags => TagsInlineAll,
|
245
|
+
:required_attrs => [],
|
246
|
+
},
|
247
|
+
:acronym => {
|
248
|
+
:attrs => Attrs,
|
249
|
+
:tags => TagsInlineAll,
|
250
|
+
:required_attrs => [],
|
251
|
+
},
|
252
|
+
:q => {
|
253
|
+
:attrs => [:cite] + Attrs,
|
254
|
+
:tags => TagsInlineAll,
|
255
|
+
:required_attrs => [],
|
256
|
+
},
|
257
|
+
:sub => {
|
258
|
+
:attrs => Attrs,
|
259
|
+
:tags => TagsInlineAll,
|
260
|
+
:required_attrs => [],
|
261
|
+
},
|
262
|
+
:sup => {
|
263
|
+
:attrs => Attrs,
|
264
|
+
:tags => TagsInlineAll,
|
265
|
+
:required_attrs => [],
|
266
|
+
},
|
267
|
+
:tt => {
|
268
|
+
:attrs => Attrs,
|
269
|
+
:tags => TagsInlineAll,
|
270
|
+
:required_attrs => [],
|
271
|
+
},
|
272
|
+
:i => {
|
273
|
+
:attrs => Attrs,
|
274
|
+
:tags => TagsInlineAll,
|
275
|
+
:required_attrs => [],
|
276
|
+
},
|
277
|
+
:b => {
|
278
|
+
:attrs => Attrs,
|
279
|
+
:tags => TagsInlineAll,
|
280
|
+
:required_attrs => [],
|
281
|
+
},
|
282
|
+
:big => {
|
283
|
+
:attrs => Attrs,
|
284
|
+
:tags => TagsInlineAll,
|
285
|
+
:required_attrs => [],
|
286
|
+
},
|
287
|
+
:small => {
|
288
|
+
:attrs => Attrs,
|
289
|
+
:tags => TagsInlineAll,
|
290
|
+
:required_attrs => [],
|
291
|
+
},
|
292
|
+
:object => {
|
293
|
+
:attrs => [:pcdata, :declare, :classid, :codebase, :data, :type, :codetype, :archive, :standby, :height, :width, :usemap, :name, :tabindex] + Attrs,
|
294
|
+
:tags => [:pcdata, :param, :form] + TagsBlock + TagsInline + TagsMisc,
|
295
|
+
:required_attrs => [],
|
296
|
+
},
|
297
|
+
:param => {
|
298
|
+
:attrs => [:id, :name, :value, :valuetype, :type],
|
299
|
+
:tags => [],
|
300
|
+
:required_attrs => [],
|
301
|
+
},
|
302
|
+
:img => {
|
303
|
+
:attrs => [:src, :alt, :longdesc, :height, :width, :usemap, :ismap] + Attrs,
|
304
|
+
:tags => [],
|
305
|
+
:required_attrs => [:src, :alt],
|
306
|
+
},
|
307
|
+
:map => {
|
308
|
+
:attrs => [:id, :class, :style, :title, :name] + AttrI18n + AttrEvents,
|
309
|
+
:tags => [:form, :area] + TagsBlock + TagsMisc,
|
310
|
+
:required_attrs => [:id],
|
311
|
+
},
|
312
|
+
:area => {
|
313
|
+
:attrs => [:shape, :coords, :href, :nohref, :alt] + Attrs + AttrFocus,
|
314
|
+
:tags => [],
|
315
|
+
:required_attrs => [:alt],
|
316
|
+
},
|
317
|
+
:map => {
|
318
|
+
:attrs => [:action, :method, :enctype, :onsubmit, :onreset, :accept, 'accept-charset'.to_sym] + Attrs,
|
319
|
+
:tags => TagsFormContent,
|
320
|
+
:required_attrs => [:action],
|
321
|
+
},
|
322
|
+
:label => {
|
323
|
+
:attrs => [:for, :accesskey, :onfocus, :onblur] + Attrs,
|
324
|
+
:tags => TagsInlineAll,
|
325
|
+
:required_attrs => [],
|
326
|
+
},
|
327
|
+
:input => {
|
328
|
+
:attrs => [:type, :name, :value, :checked, :disabled, :readonly, :size, :maxlength, :src, :alt, :usemap, :onselect, :onchange, :accept] + Attrs + AttrFocus,
|
329
|
+
:tags => [],
|
330
|
+
:required_attrs => [],
|
331
|
+
},
|
332
|
+
:select => {
|
333
|
+
:attrs => [:name, :size, :multiple, :disabled, :tabindex, :onfocus, :onblur, :onchange] + Attrs,
|
334
|
+
:tags => [:optgroup, :option],
|
335
|
+
:required_attrs => [],
|
336
|
+
},
|
337
|
+
:optgroup => {
|
338
|
+
:attrs => [:disable, :label] + Attrs,
|
339
|
+
:tags => [:option],
|
340
|
+
:required_attrs => [],
|
341
|
+
},
|
342
|
+
:option => {
|
343
|
+
:attrs => [:selected, :disabled, :label, :value] + Attrs,
|
344
|
+
:tags => [:pcdata],
|
345
|
+
:required_attrs => [],
|
346
|
+
},
|
347
|
+
:textarea => {
|
348
|
+
:attrs => [:name, :rows, :cols, :disabled, :readonly, :onselect, :onchange] + Attrs + AttrFocus,
|
349
|
+
:tags => [:pcdata],
|
350
|
+
:required_attrs => [:rows, :cols],
|
351
|
+
},
|
352
|
+
:fieldset => {
|
353
|
+
:attrs => Attrs,
|
354
|
+
:tags => [:pcdata, :legend, :form] + TagsBlock + TagsInline + TagsMisc,
|
355
|
+
:required_attrs => [],
|
356
|
+
},
|
357
|
+
:legend => {
|
358
|
+
:attrs => [:acceskey] + Attrs,
|
359
|
+
:tags => TagsInlineAll,
|
360
|
+
:required_attrs => [],
|
361
|
+
},
|
362
|
+
:button => {
|
363
|
+
:attrs => [:name, :value, :type, :disabled] + Attrs + AttrFocus,
|
364
|
+
:tags => TagsButtonContent,
|
365
|
+
:required_attrs => [],
|
366
|
+
},
|
367
|
+
:table => {
|
368
|
+
:attrs => [:summary, :width, :border, :frame, :rules, :cellpadding, :cellspacing] + Attrs,
|
369
|
+
:tags => [:caption, :col, :colgroup, :thead, :tfoot, :tbody, :tr],
|
370
|
+
:required_attrs => [],
|
371
|
+
},
|
372
|
+
:caption => {
|
373
|
+
:attrs => Attrs,
|
374
|
+
:tags => TagsInlineAll,
|
375
|
+
:required_attrs => [],
|
376
|
+
},
|
377
|
+
:thead => {
|
378
|
+
:attrs => AttrCellAlign + Attrs,
|
379
|
+
:tags => [:tr],
|
380
|
+
:required_attrs => [],
|
381
|
+
},
|
382
|
+
:tbody => {
|
383
|
+
:attrs => AttrCellAlign + Attrs,
|
384
|
+
:tags => [:tr],
|
385
|
+
:required_attrs => [],
|
386
|
+
},
|
387
|
+
:tfoot => {
|
388
|
+
:attrs => AttrCellAlign + Attrs,
|
389
|
+
:tags => [:tr],
|
390
|
+
:required_attrs => [],
|
391
|
+
},
|
392
|
+
:tr => {
|
393
|
+
:attrs => AttrCellAlign + Attrs,
|
394
|
+
:tags => [:td,:th],
|
395
|
+
:required_attrs => [],
|
396
|
+
},
|
397
|
+
:colgroup => {
|
398
|
+
:attrs => [:span, :width] + AttrCellAlign + Attrs,
|
399
|
+
:tags => [:col],
|
400
|
+
:required_attrs => [],
|
401
|
+
},
|
402
|
+
:col => {
|
403
|
+
:attrs => [:span, :width] + AttrCellAlign + Attrs,
|
404
|
+
:tags => [],
|
405
|
+
:required_attrs => [],
|
406
|
+
},
|
407
|
+
:th => {
|
408
|
+
:attrs => [:abbr, :axis, :headers, :scope, :rowspan, :ccolspan] + AttrCellAlign + Attrs,
|
409
|
+
:tags => TagsFlow,
|
410
|
+
:required_attrs => [],
|
411
|
+
},
|
412
|
+
:td => {
|
413
|
+
:attrs => [:abbr, :axis, :headers, :scope, :rowspan, :ccolspan] + AttrCellAlign + Attrs,
|
414
|
+
:tags => TagsFlow,
|
415
|
+
:required_attrs => [],
|
416
|
+
}
|
417
|
+
}
|
418
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ivan Sidorov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-10 00:00:00 +08:00
|
13
|
+
default_executable: rml
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: "RML: Ruby Markup Language. Pure ruby xhtml markup, but with one big difference. RML is aimed to provide valid and only valid xhtml 1.0 markup."
|
17
|
+
email: ivansid@gmail.com
|
18
|
+
executables:
|
19
|
+
- rml
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/rml.rb
|
26
|
+
- lib/rsm.rb
|
27
|
+
- lib/tags.rb
|
28
|
+
- bin/rml
|
29
|
+
- lib/rml/sinatra.rb
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://rml.rubyforge.org/
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: "0"
|
42
|
+
version:
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "0"
|
48
|
+
version:
|
49
|
+
requirements: []
|
50
|
+
|
51
|
+
rubyforge_project: rml
|
52
|
+
rubygems_version: 1.2.0
|
53
|
+
signing_key:
|
54
|
+
specification_version: 2
|
55
|
+
summary: "RML: Ruby Markup Language"
|
56
|
+
test_files: []
|
57
|
+
|