Remarkably 0.5.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README +89 -0
- data/Rakefile +9 -0
- data/examples/basic_css.rb +38 -0
- data/examples/basic_html.rb +95 -0
- data/examples/basic_xml.rb +51 -0
- data/examples/bookmarklets.rb +62 -0
- data/examples/headerfooter.rb +38 -0
- data/examples/pages.rb +54 -0
- data/lib/remarkably.rb +17 -3
- data/lib/remarkably/engines/css.rb +29 -4
- data/lib/remarkably/engines/css/helpers.rb +8 -0
- data/lib/remarkably/engines/html.rb +4 -3
- data/lib/remarkably/engines/html/helpers.rb +19 -0
- data/lib/remarkably/engines/xml.rb +4 -3
- data/lib/remarkably/version.rb +3 -0
- data/loadpath.rb +1 -0
- data/remarkably.gemspec +24 -0
- data/spec/engines/css.rb +62 -0
- data/spec/engines/css/helpers.rb +32 -0
- data/spec/engines/html.rb +81 -0
- data/spec/engines/xml.rb +92 -0
- data/utility/html2rem.rb +55 -0
- metadata +106 -45
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2e7816c6ce5b2d78644b586785f8ac1cd4264c80ffe2effaa9dff9b3189f45c8
|
4
|
+
data.tar.gz: e7851ae2c5c0c1c765165a4d83b868dd61879a133353ef54f43f221e062c7292
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7ae4da12943f7b6727b8df67ad20b115a88a58cc7f6a653a1c8e4d61403d02582cc568cae584313a4e94e3cd9fca644bab8d5166d4080eee7c231f69427a90c
|
7
|
+
data.tar.gz: 2f3041cf4e85dd070bb70217a885b63b98c0ddd1e5cd36423942be0479f87252dfa0f3991cd79cf5fc2b95d52eb9ed6b4638e7c0524cd6f375610106c54f17c0
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2007- Clive Crous
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
Remarkably can be used as template enginge generating HTML pages by
|
2
|
+
calling "pure" ruby methods, e.g.:
|
3
|
+
html do
|
4
|
+
header do
|
5
|
+
title "my header"
|
6
|
+
end
|
7
|
+
body do
|
8
|
+
h1 "big header"
|
9
|
+
ul do
|
10
|
+
(1..2).each do |n|
|
11
|
+
li "line #{n}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
This beautiful approach allows ruby control statements while generating
|
18
|
+
the desired page without the hassle other template engines have when
|
19
|
+
mixing HTML tags and ruby control.
|
20
|
+
|
21
|
+
A remarkably fact about Remarkably is, that is does not know anything
|
22
|
+
about HTML tags. It handles the generating of the desired page source by
|
23
|
+
using the ruby mechanism of the "method_missing" message: every(!) unkown
|
24
|
+
method will be recovered by generating appropriate HTML statements.
|
25
|
+
|
26
|
+
One of the consequences of approach is, that the parameters of such a "tag"
|
27
|
+
must follow some rules: it have to look like
|
28
|
+
sym(args, hash, &block)
|
29
|
+
that means, eventual arguments must be set before an eventual hash, which
|
30
|
+
sets the tag attributes, followed by an eventual block, which contains included
|
31
|
+
other tags.
|
32
|
+
|
33
|
+
Sounds terrible complicated, but it is not, e.g.: the ruby statement
|
34
|
+
a('Home', :href => "#{rs(:index)}")
|
35
|
+
will generate after the ruby interpolation
|
36
|
+
<a href="/index">Home</a>
|
37
|
+
|
38
|
+
To generate an anchor with a graphic icon like
|
39
|
+
<a href="/help" title="Help">
|
40
|
+
<img src="icons/help.png" border="0" alt="Help"/>
|
41
|
+
</a>
|
42
|
+
can be produced e.g. by
|
43
|
+
def gen_link(txt, href, icon)
|
44
|
+
a(:href => href, :title => txt) do
|
45
|
+
img(:src => icon, :border => 0, :alt => txt)
|
46
|
+
end # a
|
47
|
+
end # genlink
|
48
|
+
gen_link('Help', "#{rs(:help)}", 'icons/help.png')
|
49
|
+
You see, it is also possible to call methods when generating the page.
|
50
|
+
|
51
|
+
This shows another challenge: you can not generate a tag, which name
|
52
|
+
conflicts with a well known ruby method, e.g.:
|
53
|
+
p "this is some text"
|
54
|
+
will use the kernel method p to print the message to the console. To
|
55
|
+
generate a paragraph, you can use an upcase P like
|
56
|
+
P "this is another paragraph"
|
57
|
+
Dont worry, Remarkably uses .downcase when generating the code:
|
58
|
+
<p>this is another paragraph</p>
|
59
|
+
which keeps it XHTML conform.
|
60
|
+
|
61
|
+
The missing_method approach also has the consequence, that Reamrkably
|
62
|
+
can not check for valid HTML tags, e.g.:
|
63
|
+
xyz(:abc => "nonsens")
|
64
|
+
generates a syntatic correct, but semantic wrong output
|
65
|
+
<xyz abc="nonsens">
|
66
|
+
So check careful the page source offered from your browser.
|
67
|
+
|
68
|
+
There are at least two differences to Markaby: the "syntactic" sugar
|
69
|
+
for .class and .id! is not supported, e.g.:
|
70
|
+
div.myclass
|
71
|
+
must be edited to
|
72
|
+
div(:class => 'myclass')
|
73
|
+
and
|
74
|
+
div.myid!
|
75
|
+
must be edited to
|
76
|
+
div(:id => 'myid')
|
77
|
+
|
78
|
+
To insert some (eventual ruby interpolated) text in the page use text(), e.g.:
|
79
|
+
text("#{@content}")
|
80
|
+
|
81
|
+
To use Remarkably within Ramaze just set in your controller:
|
82
|
+
class Controller < Ramaze::Controller
|
83
|
+
helper :remarkably
|
84
|
+
engine :Remarkably
|
85
|
+
end # controller
|
86
|
+
and put your Remarkably files named *.rem into the view/ directory
|
87
|
+
|
88
|
+
To keep Ramaze happy, you should terminate your .rem files with the line:
|
89
|
+
remarkably_engine
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/css'
|
3
|
+
require 'remarkably/engines/css/helpers'
|
4
|
+
|
5
|
+
class Page
|
6
|
+
include Remarkably::Common
|
7
|
+
|
8
|
+
def style
|
9
|
+
body do
|
10
|
+
background_color :white
|
11
|
+
color :black
|
12
|
+
|
13
|
+
div( "#header" ) do
|
14
|
+
ul do
|
15
|
+
margin 0
|
16
|
+
padding 8.px, 2.px, 4.px, 1.5.em
|
17
|
+
li do
|
18
|
+
padding_left 2.em
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
P do
|
24
|
+
color :black
|
25
|
+
font_size 12.pt
|
26
|
+
end
|
27
|
+
|
28
|
+
P(".special") do
|
29
|
+
color :blue
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
page = Page.new
|
38
|
+
puts page.style.to_s
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/html'
|
3
|
+
require 'remarkably/engines/css/helpers'
|
4
|
+
|
5
|
+
class Site
|
6
|
+
include Remarkably::Common
|
7
|
+
|
8
|
+
def index
|
9
|
+
page do
|
10
|
+
P "Hello World!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def exit
|
15
|
+
page do
|
16
|
+
P "Goodbye cruel world"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def page
|
23
|
+
html do
|
24
|
+
head do
|
25
|
+
title "A basic Remarkably HTML example"
|
26
|
+
style do
|
27
|
+
body {
|
28
|
+
margin 0
|
29
|
+
padding 0
|
30
|
+
font_size 12.pt
|
31
|
+
background_color :white
|
32
|
+
}
|
33
|
+
div("#header") {
|
34
|
+
margin 0
|
35
|
+
padding 0
|
36
|
+
background_color "#ffd"
|
37
|
+
border_bottom 1.px, :dashed, :black
|
38
|
+
h1 {
|
39
|
+
margin 0
|
40
|
+
padding 0, 0, 4.px, 0
|
41
|
+
text_align :center
|
42
|
+
font_size 24.pt
|
43
|
+
font_weight :normal
|
44
|
+
a {
|
45
|
+
color :black
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
div("#footer") {
|
50
|
+
text_align :right
|
51
|
+
font_size 9.pt
|
52
|
+
margin 16.px, 0, 0, 0
|
53
|
+
padding 0
|
54
|
+
border_top 1.px, :solid, :black
|
55
|
+
}
|
56
|
+
div("#content") {
|
57
|
+
margin 16.px
|
58
|
+
}
|
59
|
+
a {
|
60
|
+
color :blue
|
61
|
+
}
|
62
|
+
a(":hover") {
|
63
|
+
color :red
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
body do
|
68
|
+
div :id => "header" do
|
69
|
+
h1 do
|
70
|
+
text "A basic "
|
71
|
+
a "Remarkably", :href => "http://www.darkarts.co.za/project/remarkably"
|
72
|
+
text " HTML example"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
div :id => "content" do
|
76
|
+
yield
|
77
|
+
end
|
78
|
+
div :id => "footer" do
|
79
|
+
text "This was a "
|
80
|
+
a "Remarkably", :href => "http://www.darkarts.co.za/project/remarkably"
|
81
|
+
text " example."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
site = Site.new
|
90
|
+
|
91
|
+
puts "\n== Index Page ==\n"
|
92
|
+
puts site.index.to_s
|
93
|
+
|
94
|
+
puts "\n== Exit Page ==\n"
|
95
|
+
puts site.exit.to_s
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/xml'
|
3
|
+
|
4
|
+
class Products
|
5
|
+
include Remarkably::Common
|
6
|
+
|
7
|
+
def range
|
8
|
+
products do
|
9
|
+
(1...10).each do |product_number|
|
10
|
+
product :id => product_number do
|
11
|
+
colour %w{red green blue yellow black}[product_number%5]
|
12
|
+
description "This is the description for product No #{product_number}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def range_page
|
19
|
+
html do
|
20
|
+
head do
|
21
|
+
title "Our product range"
|
22
|
+
end
|
23
|
+
body do
|
24
|
+
h1 "Our product range"
|
25
|
+
table do
|
26
|
+
tr do
|
27
|
+
th "Product ID"
|
28
|
+
th "Product Description"
|
29
|
+
th "Colour"
|
30
|
+
end
|
31
|
+
(1...10).each do |product_number|
|
32
|
+
tr do
|
33
|
+
td product_number
|
34
|
+
td "This is the description for product No #{product_number}"
|
35
|
+
td %w{red green blue yellow black}[product_number%5]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
our_products = Products.new
|
46
|
+
|
47
|
+
puts "\n== Product Range ==\n"
|
48
|
+
puts our_products.range.to_s
|
49
|
+
|
50
|
+
puts "\n== Product Range web page ==\n"
|
51
|
+
puts our_products.range_page.to_s
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/html'
|
3
|
+
require 'remarkably/engines/html/helpers'
|
4
|
+
|
5
|
+
class Site
|
6
|
+
include Remarkably::Common
|
7
|
+
|
8
|
+
def index
|
9
|
+
html do
|
10
|
+
head do
|
11
|
+
title "A Remarkably bookmarklet example"
|
12
|
+
end
|
13
|
+
body do
|
14
|
+
h1 "The bookmarklet"
|
15
|
+
P do
|
16
|
+
text "Simply click \""
|
17
|
+
java_script = %w{h1 h2 h3 h4 p a}.inject('') do |result,tag|
|
18
|
+
result+= <<-EOS
|
19
|
+
|
20
|
+
tags = document.getElementsByTagName("#{tag}");
|
21
|
+
for (i=0;i<tags.length;i++) {
|
22
|
+
header_content = tags[i].innerHTML;
|
23
|
+
tags[i].innerHTML =
|
24
|
+
'<span style="border:1px solid black;color:black;background-color:#FFA"><#{tag}></span>' + header_content +
|
25
|
+
'<span style="border:1px solid black;color:black;background-color:#FFA"></#{tag}></span>';
|
26
|
+
}
|
27
|
+
|
28
|
+
EOS
|
29
|
+
end
|
30
|
+
bookmarklet java_script, "Show some tags"
|
31
|
+
text "\", or drag it and drop it on your toolbar to use it on any site."
|
32
|
+
end
|
33
|
+
h1 "Header 1"
|
34
|
+
lorum_ipsum
|
35
|
+
h2 "Header 2"
|
36
|
+
lorum_ipsum
|
37
|
+
h3 "Header 3"
|
38
|
+
lorum_ipsum
|
39
|
+
h3 "Header 3"
|
40
|
+
lorum_ipsum
|
41
|
+
h2 "Header 2"
|
42
|
+
lorum_ipsum
|
43
|
+
h3 "Header 3"
|
44
|
+
lorum_ipsum
|
45
|
+
h1 "Header 1"
|
46
|
+
lorum_ipsum
|
47
|
+
h2 "Header 2"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def lorum_ipsum
|
55
|
+
P <<-EOS
|
56
|
+
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum vehicula lectus vitae sapien. Nam quis lorem id velit tempor convallis. Nullam est orci, placerat a, hendrerit rutrum, dictum quis, magna. Nulla pharetra libero ac risus. Fusce in elit. Cras vel nisl nec enim tincidunt vehicula. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent sollicitudin, libero sit amet hendrerit fermentum, odio nisl mollis enim, quis faucibus nisi nisi eu erat. Vivamus eu urna at velit mattis congue. Morbi feugiat erat vel libero.
|
57
|
+
EOS
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
puts Site.new.index.to_s
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/html'
|
3
|
+
|
4
|
+
class Page
|
5
|
+
include Remarkably::Common
|
6
|
+
|
7
|
+
def header
|
8
|
+
h1 "A Header and Footer example with Remarkably"
|
9
|
+
hr
|
10
|
+
end
|
11
|
+
|
12
|
+
def footer
|
13
|
+
hr
|
14
|
+
text "Find out more about Remarkably "
|
15
|
+
a "here", :href=>"http://www.darkarts.co.za"
|
16
|
+
text "."
|
17
|
+
end
|
18
|
+
|
19
|
+
def entire_page
|
20
|
+
html do
|
21
|
+
head do
|
22
|
+
title "Remarkably: Headers and Footers"
|
23
|
+
end
|
24
|
+
body do
|
25
|
+
header
|
26
|
+
P "This is some page content"
|
27
|
+
footer
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
page = Page.new
|
35
|
+
|
36
|
+
puts "Just the header => #{page.header}"
|
37
|
+
puts "Just the footer => #{page.footer}"
|
38
|
+
puts "The entire page => #{page.entire_page}"
|
data/examples/pages.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require '../loadpath'
|
2
|
+
require 'remarkably/engines/html'
|
3
|
+
|
4
|
+
class Page
|
5
|
+
include Remarkably::Common
|
6
|
+
|
7
|
+
def main_page
|
8
|
+
page do
|
9
|
+
P "Hello World!"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def exit_page
|
14
|
+
page do
|
15
|
+
P "Goodbye World!"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def menu
|
22
|
+
div :id=>"menu" do
|
23
|
+
ul do
|
24
|
+
li 'foo'
|
25
|
+
li 'bar'
|
26
|
+
li 'baz'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def footer
|
32
|
+
div "This is a footer", :id=>"footer"
|
33
|
+
end
|
34
|
+
|
35
|
+
def page
|
36
|
+
html do
|
37
|
+
head do
|
38
|
+
title "Test Page"
|
39
|
+
end
|
40
|
+
body do
|
41
|
+
menu
|
42
|
+
div :id => "content" do
|
43
|
+
yield
|
44
|
+
end
|
45
|
+
footer
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
page = Page.new
|
53
|
+
puts "Main Page => #{page.main_page}"
|
54
|
+
puts "Exit Page => #{page.exit_page}"
|
data/lib/remarkably.rb
CHANGED
@@ -1,18 +1,32 @@
|
|
1
|
+
require 'remarkably/version'
|
2
|
+
|
1
3
|
module Remarkably
|
2
4
|
|
5
|
+
module Config
|
6
|
+
class << self
|
7
|
+
attr_accessor :default_engine
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
3
11
|
module Base
|
4
12
|
|
5
13
|
class Engine
|
14
|
+
|
15
|
+
attr_reader :remarkably_engine
|
16
|
+
|
6
17
|
def initialize *args, &block
|
7
18
|
clear!
|
19
|
+
@remarkably_engine = self
|
8
20
|
self.instance_eval( &block ) if block_given?
|
9
21
|
end
|
10
22
|
|
11
23
|
def missing_method(sym, context, *args, &block)
|
12
24
|
@context = context
|
13
25
|
hash = args.last.is_a?(Hash) ? args.pop : {}
|
14
|
-
if
|
15
|
-
|
26
|
+
responder ||= context.remarkably_engine if context.remarkably_engine.respond_to?( sym )
|
27
|
+
responder ||= self if self.respond_to?( sym )
|
28
|
+
if responder
|
29
|
+
responder.send( sym, args, hash, &block )
|
16
30
|
else
|
17
31
|
method!(sym, args, hash, &block)
|
18
32
|
end
|
@@ -42,7 +56,7 @@ module Remarkably
|
|
42
56
|
module Common
|
43
57
|
|
44
58
|
def method_missing(sym, *args, &block)
|
45
|
-
@remarkably_engine ||=
|
59
|
+
@remarkably_engine ||= Config.default_engine.new
|
46
60
|
@remarkably_engine.send( :missing_method, sym, self, *args, &block )
|
47
61
|
end
|
48
62
|
|
@@ -1,14 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require 'remarkably'
|
2
2
|
|
3
3
|
module Remarkably
|
4
4
|
module Engines
|
5
5
|
class CSS < Base::Engine
|
6
6
|
def method! sym, args, hash, &block
|
7
7
|
sym = sym.to_s.downcase
|
8
|
+
sym = "##{sym}".chop if sym[-1].chr == '!'
|
9
|
+
sym = ".#{sym}".chop if sym[-1].chr == '?'
|
8
10
|
|
9
11
|
if block_given?
|
10
12
|
current_prefix = @css_prefix
|
11
|
-
@css_prefix = (@css_prefix+"
|
13
|
+
@css_prefix = (@css_prefix+"#{sym}#{args.map{|a|a.to_s}.join} ")
|
12
14
|
@css_depth+=1
|
13
15
|
@css_prefix_rendered=false
|
14
16
|
block.call
|
@@ -20,15 +22,37 @@ module Remarkably
|
|
20
22
|
@output.chop!
|
21
23
|
@output << "}"
|
22
24
|
end
|
23
|
-
@output << "\n#{@css_prefix}
|
25
|
+
@output << "\n#{@css_prefix}{"
|
24
26
|
@css_prefix_rendered = true
|
25
27
|
@css_first_use = false
|
26
28
|
end
|
27
|
-
|
29
|
+
# XXX This line below is more complex than it needs to be, for some
|
30
|
+
# reason gsub in ruby 1.9.2 throws a method_missing breaking
|
31
|
+
# everything :(
|
32
|
+
@output << "#{sym.to_s.split('').map{|n|n=='_' ? '-' : n}.join('')}:#{args.map{|a|a.to_s}.join(' ')};"
|
28
33
|
end
|
29
34
|
self
|
30
35
|
end
|
31
36
|
|
37
|
+
def css_prefix prefix, &block
|
38
|
+
@css_prefix << prefix
|
39
|
+
block.call
|
40
|
+
@css_prefix.chop!
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def css_class args, hash, &block
|
45
|
+
css_prefix ".", &block
|
46
|
+
end
|
47
|
+
|
48
|
+
def css_id args, hash, &block
|
49
|
+
css_prefix "#", &block
|
50
|
+
end
|
51
|
+
|
52
|
+
def css_pseudo args, hash, &block
|
53
|
+
css_prefix ":", &block
|
54
|
+
end
|
55
|
+
|
32
56
|
def to_s
|
33
57
|
"#{super.chop}}".strip+"\n"
|
34
58
|
end
|
@@ -42,6 +66,7 @@ module Remarkably
|
|
42
66
|
end
|
43
67
|
|
44
68
|
end
|
69
|
+
Config.default_engine = CSS
|
45
70
|
end
|
46
71
|
end
|
47
72
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'remarkably'
|
2
|
+
require 'remarkably/engines/xml'
|
3
|
+
require 'remarkably/engines/css'
|
4
4
|
|
5
5
|
module Remarkably
|
6
6
|
module Engines
|
@@ -20,5 +20,6 @@ module Remarkably
|
|
20
20
|
method!( :style, args, hash )
|
21
21
|
end
|
22
22
|
end
|
23
|
+
Config.default_engine = HTML
|
23
24
|
end
|
24
25
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Remarkably
|
2
|
+
module Engines
|
3
|
+
class HTML < XML
|
4
|
+
def bookmarklet args, hash, &block
|
5
|
+
inline_javascript = args.shift.split("\n").map{|l|l.strip}.join('')
|
6
|
+
inline_javascript.gsub!( '%', '%25' )
|
7
|
+
{ "'" => "%27",
|
8
|
+
'"' => "%22",
|
9
|
+
'&' => "%26",
|
10
|
+
'/' => "%2F",
|
11
|
+
}.each_pair do |key,value|
|
12
|
+
inline_javascript.gsub!( key, value )
|
13
|
+
end
|
14
|
+
hash[:href]=%|javascript:(function(){#{inline_javascript}})();|
|
15
|
+
method!( :a, args, hash, &block )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'remarkably'
|
2
2
|
|
3
3
|
module Remarkably
|
4
4
|
module Engines
|
@@ -10,7 +10,7 @@ module Remarkably
|
|
10
10
|
tag_attributes =
|
11
11
|
hash.inject([]){|s,(k,v)| s << %{#{k.to_s.downcase}="#{v}"} }
|
12
12
|
|
13
|
-
@output << ["<#{sym}"
|
13
|
+
@output << ( ["<#{sym}"] + tag_attributes).join(' ')
|
14
14
|
|
15
15
|
if block_given? or not args.empty?
|
16
16
|
@output << ">"
|
@@ -23,11 +23,12 @@ module Remarkably
|
|
23
23
|
self
|
24
24
|
end
|
25
25
|
|
26
|
-
def text args, hash
|
26
|
+
def text args, hash
|
27
27
|
@output << args.join
|
28
28
|
self
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
32
|
+
Config.default_engine = XML
|
32
33
|
end
|
33
34
|
end
|
data/loadpath.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$:.unshift "#{File::dirname(__FILE__)}/lib/"
|
data/remarkably.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "remarkably/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "Remarkably"
|
7
|
+
s.version = Remarkably::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Clive Crous"]
|
10
|
+
s.email = ["clive@crous.co.za"]
|
11
|
+
s.homepage = 'https://github.com/clivecrous/Remarkably'
|
12
|
+
s.summary = %q{A very tiny Markaby-like XML,HTML and CSS builder}
|
13
|
+
s.description = %q{Remarkably is a very tiny Markaby-like XML,HTML and CSS builder}
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
17
|
+
s.add_development_dependency "rake", ">= 0.8.7"
|
18
|
+
s.add_development_dependency "rspec", ">= 1.3.0"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
data/spec/engines/css.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'remarkably/engines/css'
|
2
|
+
|
3
|
+
describe Remarkably::Engines::CSS do
|
4
|
+
include Remarkably::Common
|
5
|
+
|
6
|
+
before( :all ) do
|
7
|
+
@remarkably_engine = Remarkably::Engines::CSS.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "Does basic styling" do
|
11
|
+
body do
|
12
|
+
P do
|
13
|
+
background_color :white
|
14
|
+
border "1px", :solid, :black
|
15
|
+
end
|
16
|
+
div do
|
17
|
+
color :blue
|
18
|
+
end
|
19
|
+
end.to_s.should == "body p {background-color:white;border:1px solid black}\nbody div {color:blue}\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "uses css class" do
|
23
|
+
div do
|
24
|
+
css_class do
|
25
|
+
foo do
|
26
|
+
color :red
|
27
|
+
end
|
28
|
+
end
|
29
|
+
bar? do
|
30
|
+
color :blue
|
31
|
+
end
|
32
|
+
P do
|
33
|
+
color :green
|
34
|
+
end
|
35
|
+
end.to_s.should == "div .foo {color:red}\ndiv .bar {color:blue}\ndiv p {color:green}\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "uses css id" do
|
39
|
+
div do
|
40
|
+
css_id do
|
41
|
+
foo do
|
42
|
+
color :red
|
43
|
+
end
|
44
|
+
bar do
|
45
|
+
color :blue
|
46
|
+
end
|
47
|
+
end
|
48
|
+
baz! do
|
49
|
+
color :green
|
50
|
+
end
|
51
|
+
end.to_s.should == "div #foo {color:red}\ndiv #bar {color:blue}\ndiv #baz {color:green}\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "uses css pseudo" do
|
55
|
+
css_pseudo do
|
56
|
+
hover do
|
57
|
+
color :red
|
58
|
+
end
|
59
|
+
end.to_s.should == ":hover {color:red}\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'remarkably/engines/css'
|
2
|
+
require 'remarkably/engines/css/helpers'
|
3
|
+
|
4
|
+
describe "Remarkably::Engines::CSS Helpers" do
|
5
|
+
include Remarkably::Common
|
6
|
+
|
7
|
+
before( :all ) do
|
8
|
+
@remarkably_engine = Remarkably::Engines::CSS.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "Uses numbers correctly" do
|
12
|
+
body do
|
13
|
+
P do
|
14
|
+
background_color :white
|
15
|
+
border 1.px, :solid, :black
|
16
|
+
font_size 2.5.em
|
17
|
+
end
|
18
|
+
div do
|
19
|
+
color :blue
|
20
|
+
end
|
21
|
+
end.to_s.should == "body p {background-color:white;border:1px solid black;font-size:2.5em}\nbody div {color:blue}\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "uses arrays" do
|
25
|
+
body do
|
26
|
+
%w{h1 h2 h3}.css do
|
27
|
+
color :blue
|
28
|
+
end
|
29
|
+
end.to_s.should == "body h1 {color:blue}\nbody h2 {color:blue}\nbody h3 {color:blue}\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'remarkably/engines/html'
|
2
|
+
|
3
|
+
describe "Remarkably::Engine::HTML instance_eval" do
|
4
|
+
it "performs an instance_eval when a block is given to new" do
|
5
|
+
Remarkably::Engines::HTML.new do
|
6
|
+
html do
|
7
|
+
body do
|
8
|
+
P "Hello World!"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end.to_s.should == "<html><body><p>Hello World!</p></body></html>"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Remarkably::Engines::HTML do
|
16
|
+
include Remarkably::Common
|
17
|
+
|
18
|
+
before( :all ) do
|
19
|
+
@remarkably_engine = Remarkably::Engines::HTML.new
|
20
|
+
end
|
21
|
+
|
22
|
+
it "Accepts a string as a paramater" do
|
23
|
+
testing( "Hello World" ).to_s.should ==
|
24
|
+
"<testing>Hello World</testing>"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Accepts a block as a paramater" do
|
28
|
+
testing do
|
29
|
+
text "Hello World"
|
30
|
+
end.to_s.should ==
|
31
|
+
"<testing>Hello World</testing>"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "Accepts multiple strings as paramaters" do
|
35
|
+
testing( "Hello", "World" ).to_s.should ==
|
36
|
+
"<testing>HelloWorld</testing>"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Closes empty tags neatly" do
|
40
|
+
testing.to_s.should ==
|
41
|
+
"<testing/>"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "Accepts only attributes" do
|
45
|
+
testing( :id => "attributes" ).to_s.should ==
|
46
|
+
'<testing id="attributes"/>'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "Accepts strings and attributes" do
|
50
|
+
testing( "Hello ", "World",
|
51
|
+
:id => "attributes", :class => "test" ).to_s.should ==
|
52
|
+
'<testing id="attributes" class="test">Hello World</testing>'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "Allows yielding for internal content" do
|
56
|
+
def page
|
57
|
+
html do
|
58
|
+
body do
|
59
|
+
yield
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
page do
|
65
|
+
P "Internal Content"
|
66
|
+
end.to_s.should == "<html><body><p>Internal Content</p></body></html>"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "Does auto-style" do
|
70
|
+
html do
|
71
|
+
head do
|
72
|
+
style do
|
73
|
+
body do
|
74
|
+
color :blue
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end.to_s.should == "<html><head><style>\nbody {color:blue}\n</style></head></html>"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/spec/engines/xml.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'remarkably/engines/xml'
|
2
|
+
|
3
|
+
describe "Remarkably::Engine::XML explicit engine usage" do
|
4
|
+
it "performs an instance_eval when a block is given to new" do
|
5
|
+
xml = Remarkably::Engines::XML.new
|
6
|
+
xml.html do
|
7
|
+
xml.body do
|
8
|
+
xml.P "Hello World!"
|
9
|
+
end
|
10
|
+
end.to_s.should == "<html><body><p>Hello World!</p></body></html>"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Remarkably::Engine::XML instance_eval" do
|
15
|
+
it "performs an instance_eval when a block is given to new" do
|
16
|
+
Remarkably::Engines::XML.new do
|
17
|
+
html do
|
18
|
+
body do
|
19
|
+
P "Hello World!"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end.to_s.should == "<html><body><p>Hello World!</p></body></html>"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Remarkably::Engines::XML do
|
27
|
+
include Remarkably::Common
|
28
|
+
|
29
|
+
before( :all ) do
|
30
|
+
@remarkably_engine = Remarkably::Engines::XML.new
|
31
|
+
end
|
32
|
+
|
33
|
+
it "Accepts a string as a paramater" do
|
34
|
+
testing( "Hello World" ).to_s.should ==
|
35
|
+
"<testing>Hello World</testing>"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "Accepts a block as a paramater" do
|
39
|
+
testing do
|
40
|
+
text "Hello World"
|
41
|
+
end.to_s.should ==
|
42
|
+
"<testing>Hello World</testing>"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "Accepts multiple strings as paramaters" do
|
46
|
+
testing( "Hello", "World" ).to_s.should ==
|
47
|
+
"<testing>HelloWorld</testing>"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "Closes empty tags neatly" do
|
51
|
+
testing.to_s.should ==
|
52
|
+
"<testing/>"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "Accepts only attributes" do
|
56
|
+
testing( :id => "attributes" ).to_s.should ==
|
57
|
+
'<testing id="attributes"/>'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "Accepts strings and attributes" do
|
61
|
+
testing( "Hello ", "World",
|
62
|
+
:id => "attributes", :class => "test" ).to_s.should ==
|
63
|
+
'<testing id="attributes" class="test">Hello World</testing>'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "Allows yielding for internal content" do
|
67
|
+
def page
|
68
|
+
html do
|
69
|
+
body do
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
page do
|
76
|
+
P "Internal Content"
|
77
|
+
end.to_s.should == "<html><body><p>Internal Content</p></body></html>"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "Does not auto-style" do
|
81
|
+
html do
|
82
|
+
head do
|
83
|
+
style do
|
84
|
+
body do
|
85
|
+
color :blue
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end.to_s.should == "<html><head><style><body><color>blue</color></body></style></head></html>"
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/utility/html2rem.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'xml/libxml'
|
3
|
+
|
4
|
+
def process_element( element, level = 0)
|
5
|
+
children = 0
|
6
|
+
element.each_child { children+=1 }
|
7
|
+
|
8
|
+
if element.text?
|
9
|
+
text = element.to_s.strip
|
10
|
+
return if text.size == 0
|
11
|
+
else
|
12
|
+
if children == 1 and element.child.name == "text"
|
13
|
+
text = element.child.to_s.strip
|
14
|
+
else
|
15
|
+
text = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
element.name = "P" if element.name == "p"
|
20
|
+
|
21
|
+
indentation = ' '*level
|
22
|
+
print indentation + "#{element.name.strip}"
|
23
|
+
|
24
|
+
if text and element.name != "text"
|
25
|
+
print " \"#{text}\""
|
26
|
+
end
|
27
|
+
|
28
|
+
attributes=[]
|
29
|
+
element.each_attr do |attribute|
|
30
|
+
if attribute.name.grep( /-/ ).size > 0
|
31
|
+
attributes << "\"#{attribute.name}\" => \"#{attribute.value}\""
|
32
|
+
else
|
33
|
+
attributes << ":#{attribute.name} => \"#{attribute.value}\""
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if not attributes.empty?
|
37
|
+
print "," if text and element.name != "text"
|
38
|
+
print " "+attributes.join(', ').strip
|
39
|
+
end
|
40
|
+
if not (text and element.name != "text")
|
41
|
+
if element.children?
|
42
|
+
puts " do"
|
43
|
+
element.each do |inner_element|
|
44
|
+
process_element( inner_element, level + 2 )
|
45
|
+
end
|
46
|
+
print indentation + "end" if element.children?
|
47
|
+
else
|
48
|
+
print " \"#{text}\"" if text
|
49
|
+
end
|
50
|
+
end
|
51
|
+
print "\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
html = XML::Document.file( ARGV[0] )
|
55
|
+
process_element( html.root )
|
metadata
CHANGED
@@ -1,53 +1,114 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.3
|
3
|
-
specification_version: 1
|
1
|
+
--- !ruby/object:Gem::Specification
|
4
2
|
name: Remarkably
|
5
|
-
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-05-24 00:00:00 +02:00
|
8
|
-
summary: Remarkably is a very tiny Markaby-like XML builder
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: clive@darkarts.co.za
|
12
|
-
homepage: http://www.darkarts.co.za/
|
13
|
-
rubyforge_project:
|
14
|
-
description:
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: false
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.2
|
25
5
|
platform: ruby
|
26
|
-
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
|
-
authors:
|
6
|
+
authors:
|
30
7
|
- Clive Crous
|
31
|
-
|
32
|
-
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.7
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.8.7
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.0
|
55
|
+
description: Remarkably is a very tiny Markaby-like XML,HTML and CSS builder
|
56
|
+
email:
|
57
|
+
- clive@crous.co.za
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE
|
65
|
+
- README
|
66
|
+
- Rakefile
|
67
|
+
- examples/basic_css.rb
|
68
|
+
- examples/basic_html.rb
|
69
|
+
- examples/basic_xml.rb
|
70
|
+
- examples/bookmarklets.rb
|
71
|
+
- examples/headerfooter.rb
|
72
|
+
- examples/pages.rb
|
33
73
|
- lib/remarkably.rb
|
34
|
-
- lib/remarkably/engines
|
35
|
-
- lib/remarkably/engines/css
|
36
|
-
- lib/remarkably/engines/xml.rb
|
37
|
-
- lib/remarkably/engines/html.rb
|
38
74
|
- lib/remarkably/engines/css.rb
|
39
75
|
- lib/remarkably/engines/css/helpers.rb
|
40
|
-
|
41
|
-
|
76
|
+
- lib/remarkably/engines/html.rb
|
77
|
+
- lib/remarkably/engines/html/helpers.rb
|
78
|
+
- lib/remarkably/engines/xml.rb
|
79
|
+
- lib/remarkably/version.rb
|
80
|
+
- loadpath.rb
|
81
|
+
- remarkably.gemspec
|
82
|
+
- spec/engines/css.rb
|
83
|
+
- spec/engines/css/helpers.rb
|
84
|
+
- spec/engines/html.rb
|
85
|
+
- spec/engines/xml.rb
|
86
|
+
- utility/html2rem.rb
|
87
|
+
homepage: https://github.com/clivecrous/Remarkably
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
42
92
|
rdoc_options: []
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
50
105
|
requirements: []
|
51
|
-
|
52
|
-
|
53
|
-
|
106
|
+
rubygems_version: 3.1.4
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: A very tiny Markaby-like XML,HTML and CSS builder
|
110
|
+
test_files:
|
111
|
+
- spec/engines/css.rb
|
112
|
+
- spec/engines/css/helpers.rb
|
113
|
+
- spec/engines/html.rb
|
114
|
+
- spec/engines/xml.rb
|