paggio 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -0
- data/README.md +82 -3
- data/Rakefile +16 -0
- data/lib/paggio.rb +18 -7
- data/lib/paggio/css.rb +6 -0
- data/lib/paggio/css/definition.rb +0 -4
- data/lib/paggio/formatter.rb +183 -0
- data/lib/paggio/html.rb +3 -11
- data/lib/paggio/html/element.rb +48 -21
- data/lib/paggio/markdown.rb +26 -0
- data/lib/paggio/script.rb +50 -0
- data/lib/paggio/utils.rb +46 -0
- data/paggio.gemspec +1 -1
- data/spec/css_spec.rb +41 -0
- metadata +11 -4
- data/lib/paggio/format.rb +0 -117
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f45cce4c5e22a829c92ab432750b660ccbb3c5ce
|
4
|
+
data.tar.gz: b35cfc68c4599a09d058b58d30561faad7088127
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f09353b8bf0a32cf35ec40ba71fbb0a7054068ed9c854597ca7dd567a2d19541a5bcda03fea9bacef434b4a36ddd3e0a58187ca0b467b8f8a9fd34ebf359fba0
|
7
|
+
data.tar.gz: 462b363f533688c41e2b799a7e246c736cd69fe99579f89c3122fbaad3f1327567d885a6ab870c5f485d3feb57ee2bd89553ee583d4ccff39f680aadaa721fb1
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -8,6 +8,8 @@ Inspired by markaby with some specialized additions for certain kinds of
|
|
8
8
|
elements.
|
9
9
|
|
10
10
|
```ruby
|
11
|
+
require 'paggio/now'
|
12
|
+
|
11
13
|
# html! avoids outputting the doctype and <html> tags
|
12
14
|
html! do
|
13
15
|
div.content! do
|
@@ -22,7 +24,9 @@ This will output:
|
|
22
24
|
|
23
25
|
```html
|
24
26
|
<div id="content">
|
25
|
-
|
27
|
+
<p>
|
28
|
+
I like trains.
|
29
|
+
</p>
|
26
30
|
</div>
|
27
31
|
```
|
28
32
|
|
@@ -31,6 +35,8 @@ CSS
|
|
31
35
|
Inspired by SCSS with some nice CSS unit handling monkey-patching.
|
32
36
|
|
33
37
|
```ruby
|
38
|
+
require 'paggio/now'
|
39
|
+
|
34
40
|
css do
|
35
41
|
rule '.content' do
|
36
42
|
background :black
|
@@ -121,7 +127,80 @@ get '/' do
|
|
121
127
|
end
|
122
128
|
```
|
123
129
|
|
130
|
+
With Markdown
|
131
|
+
-------------
|
132
|
+
You'll need the `kramdown` gem.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
require 'paggio/now'
|
136
|
+
require 'paggio/markdown'
|
137
|
+
|
138
|
+
html do
|
139
|
+
markdown <<-MD
|
140
|
+
Here comes a bunch of **shitty** markdown.
|
141
|
+
MD
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
Since *paggio* does internal heredoc indentation pruning, you don't have to
|
146
|
+
worry about that.
|
147
|
+
|
148
|
+
With Opal
|
149
|
+
---------
|
150
|
+
You'll need the `--pre sourcify` gem and the `opal` gem.
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
require 'paggio/now'
|
154
|
+
require 'paggio/script'
|
155
|
+
|
156
|
+
html do
|
157
|
+
head do
|
158
|
+
script src: 'js/opal.js'
|
159
|
+
script src: 'js/browser.js'
|
160
|
+
|
161
|
+
script do
|
162
|
+
alert 'Yo dawg'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
Calling local methods inside the DSLs
|
169
|
+
-------------------------------------
|
170
|
+
Don't you just love `instance_eval`? Well, I do, but sometimes it's not the
|
171
|
+
best tool for the job, in fact you cannot call local methods or access instance
|
172
|
+
variables inside the DSLs since they're evaluated in another context.
|
173
|
+
|
174
|
+
Well, fear not, doing that is as easy as adding a parameter to the DSL block.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
class Page
|
178
|
+
def initialize(title, content)
|
179
|
+
@title = title
|
180
|
+
@content = content
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_html
|
184
|
+
Paggio.html do |_|
|
185
|
+
_.html do
|
186
|
+
_.head do
|
187
|
+
title @title
|
188
|
+
end
|
189
|
+
|
190
|
+
_.body do
|
191
|
+
@content
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
puts Page.new("foo", "bar").to_html
|
199
|
+
```
|
200
|
+
|
124
201
|
Why?
|
125
202
|
----
|
126
|
-
Because HAML and
|
127
|
-
|
203
|
+
Because HAML, SCSS and CoffeeScript are too mainstream.
|
204
|
+
|
205
|
+
On a serious note, why have templating systems and syntax sugar when you can
|
206
|
+
just write Ruby?
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
task :default => [:install, :test]
|
5
|
+
|
6
|
+
task :install do
|
7
|
+
sh 'gem install --no-force rspec'
|
8
|
+
sh 'gem build *.gemspec'
|
9
|
+
sh 'gem install *.gem'
|
10
|
+
end
|
11
|
+
|
12
|
+
task :test do
|
13
|
+
FileUtils.cd 'spec' do
|
14
|
+
sh 'rspec css_spec.rb --backtrace --color --format doc'
|
15
|
+
end
|
16
|
+
end
|
data/lib/paggio.rb
CHANGED
@@ -8,22 +8,33 @@
|
|
8
8
|
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
9
|
#++
|
10
10
|
|
11
|
-
require '
|
12
|
-
|
13
|
-
require 'paggio/css'
|
11
|
+
require 'paggio/utils'
|
14
12
|
require 'paggio/html'
|
15
|
-
require 'paggio/
|
13
|
+
require 'paggio/css'
|
14
|
+
require 'paggio/formatter'
|
16
15
|
|
17
16
|
class Paggio
|
17
|
+
def self.options(options, &block)
|
18
|
+
Formatter.options(options, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.indent(options, &block)
|
22
|
+
options(indent: options, &block)
|
23
|
+
end
|
24
|
+
|
18
25
|
def self.css(*args, &block)
|
19
|
-
CSS.new(*args, &block).
|
26
|
+
Formatter.new.format(CSS.new(*args, &block)).to_s
|
20
27
|
end
|
21
28
|
|
22
29
|
def self.html(*args, &block)
|
23
|
-
HTML.new(*args, &block).
|
30
|
+
Formatter.new.format(HTML.new(*args, &block)).to_s
|
24
31
|
end
|
25
32
|
|
26
33
|
def self.html!(&block)
|
27
|
-
|
34
|
+
Formatter.new.tap {|f|
|
35
|
+
HTML.new(&block).each {|root|
|
36
|
+
f.format root
|
37
|
+
}
|
38
|
+
}.to_s
|
28
39
|
end
|
29
40
|
end
|
data/lib/paggio/css.rb
CHANGED
@@ -0,0 +1,183 @@
|
|
1
|
+
#--
|
2
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
3
|
+
# Version 2, December 2004
|
4
|
+
#
|
5
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
6
|
+
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
7
|
+
#
|
8
|
+
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
|
+
#++
|
10
|
+
|
11
|
+
require 'stringio'
|
12
|
+
|
13
|
+
class Paggio
|
14
|
+
|
15
|
+
class Formatter
|
16
|
+
def self.to_h
|
17
|
+
@formatters ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.for(klass, &block)
|
21
|
+
if block
|
22
|
+
to_h[klass] = block
|
23
|
+
else
|
24
|
+
to_h[klass]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.options(options, &block)
|
29
|
+
old = OPTIONS.dup
|
30
|
+
Utils.deep_merge!(OPTIONS, options)
|
31
|
+
|
32
|
+
result = block.call
|
33
|
+
|
34
|
+
OPTIONS.replace(old)
|
35
|
+
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
OPTIONS = {
|
40
|
+
indent: {
|
41
|
+
level: 0,
|
42
|
+
with: "\t"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
def initialize(io = nil, options = {})
|
47
|
+
if Hash === io
|
48
|
+
@io = StringIO.new
|
49
|
+
@options = io
|
50
|
+
else
|
51
|
+
@io = io || StringIO.new
|
52
|
+
@options = options
|
53
|
+
end
|
54
|
+
|
55
|
+
@options = OPTIONS.merge(@options)
|
56
|
+
end
|
57
|
+
|
58
|
+
def format(item)
|
59
|
+
Formatter.to_h.each {|klass, block|
|
60
|
+
if klass === item
|
61
|
+
block.call(self, item)
|
62
|
+
break
|
63
|
+
end
|
64
|
+
}
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
@io.string
|
71
|
+
end
|
72
|
+
|
73
|
+
def indent?(&block)
|
74
|
+
@options[:indent][:level]
|
75
|
+
rescue
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def indent(&block)
|
80
|
+
if indent?
|
81
|
+
@options[:indent][:level] += 1
|
82
|
+
block.call
|
83
|
+
@options[:indent][:level] -= 1
|
84
|
+
else
|
85
|
+
block.call
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def print(text)
|
90
|
+
if level = indent?
|
91
|
+
text.lines.each {|line|
|
92
|
+
@io.puts "#{@options[:indent][:with] * level}#{line.chomp}"
|
93
|
+
}
|
94
|
+
else
|
95
|
+
@io.print text
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def escape(string)
|
100
|
+
string.to_s.gsub(/["><']|&(?!([a-zA-Z]+|(#\d+));)/, {
|
101
|
+
'&' => '&',
|
102
|
+
'>' => '>',
|
103
|
+
'<' => '<',
|
104
|
+
'"' => '"',
|
105
|
+
"'" => ''' })
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Formatter.for HTML do |f, item|
|
110
|
+
case item.version
|
111
|
+
when 5
|
112
|
+
f.print '<!DOCTYPE html>'
|
113
|
+
end
|
114
|
+
|
115
|
+
f.print '<html>'
|
116
|
+
f.indent {
|
117
|
+
item.each {|root|
|
118
|
+
f.format(root)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
f.print '</html>'
|
122
|
+
end
|
123
|
+
|
124
|
+
Formatter.for HTML::Element do |f, item|
|
125
|
+
name, attributes, class_names = item.instance_eval {
|
126
|
+
[@name, @attributes, @class_names]
|
127
|
+
}
|
128
|
+
|
129
|
+
if attributes.empty? && class_names.empty?
|
130
|
+
f.print "<#{name}>"
|
131
|
+
else
|
132
|
+
attrs = attributes.map {|key, value|
|
133
|
+
%Q{#{f.escape(key)}="#{f.escape(value)}"}
|
134
|
+
}
|
135
|
+
|
136
|
+
unless class_names.empty?
|
137
|
+
attrs << %Q{class="#{f.escape(class_names.join(' '))}"}
|
138
|
+
end
|
139
|
+
|
140
|
+
f.print "<#{name} #{attrs.join(' ')}>"
|
141
|
+
end
|
142
|
+
|
143
|
+
f.indent {
|
144
|
+
if inner = item.instance_eval { @inner_html }
|
145
|
+
f.print inner
|
146
|
+
else
|
147
|
+
item.each {|child|
|
148
|
+
case child
|
149
|
+
when String
|
150
|
+
f.print f.escape(child)
|
151
|
+
|
152
|
+
when CSS
|
153
|
+
f.print '<style>'
|
154
|
+
f.indent {
|
155
|
+
f.format(child)
|
156
|
+
}
|
157
|
+
f.print '</style>'
|
158
|
+
|
159
|
+
else
|
160
|
+
f.format(child)
|
161
|
+
end
|
162
|
+
}
|
163
|
+
end
|
164
|
+
}
|
165
|
+
|
166
|
+
f.print "</#{name}>"
|
167
|
+
end
|
168
|
+
|
169
|
+
Formatter.for CSS do |f, item|
|
170
|
+
item.rules.reverse.each {|rule|
|
171
|
+
next if rule.definition.empty?
|
172
|
+
|
173
|
+
f.print "#{rule.selector} {"
|
174
|
+
f.indent {
|
175
|
+
rule.definition.each {|style|
|
176
|
+
f.print "#{style.name}: #{style.value}#{' !important' if style.important?};"
|
177
|
+
}
|
178
|
+
}
|
179
|
+
f.print '}'
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
data/lib/paggio/html.rb
CHANGED
@@ -51,7 +51,7 @@ class HTML < BasicObject
|
|
51
51
|
result = block.call(self)
|
52
52
|
|
53
53
|
if ::String === result
|
54
|
-
@current.inner_html = result
|
54
|
+
@current.instance_eval { @inner_html = result }
|
55
55
|
end
|
56
56
|
|
57
57
|
@current = old
|
@@ -60,15 +60,7 @@ class HTML < BasicObject
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def each(&block)
|
63
|
-
return enum_for :each unless block
|
64
|
-
|
65
63
|
@roots.each(&block)
|
66
|
-
|
67
|
-
self
|
68
|
-
end
|
69
|
-
|
70
|
-
def style(&block)
|
71
|
-
(@current || @roots) << CSS.new(&block)
|
72
64
|
end
|
73
65
|
|
74
66
|
def method_missing(name, *args, &block)
|
@@ -77,7 +69,7 @@ class HTML < BasicObject
|
|
77
69
|
end
|
78
70
|
|
79
71
|
if ::String === args.first
|
80
|
-
content = args.shift
|
72
|
+
content = ::Paggio::Utils.heredoc(args.shift)
|
81
73
|
end
|
82
74
|
|
83
75
|
element = Element.new(self, name, *args)
|
@@ -90,7 +82,7 @@ class HTML < BasicObject
|
|
90
82
|
@current = parent
|
91
83
|
|
92
84
|
if ::String === result
|
93
|
-
element.inner_html = result
|
85
|
+
element.instance_eval { @inner_html = result }
|
94
86
|
end
|
95
87
|
end
|
96
88
|
|
data/lib/paggio/html/element.rb
CHANGED
@@ -23,23 +23,25 @@ class Element < BasicObject
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
def self.defhelper(name, &block)
|
27
|
+
define_method name do |*args, &body|
|
28
|
+
instance_exec(*args, &block)
|
29
|
+
|
30
|
+
self.do(&block) if body
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
28
34
|
|
29
35
|
def initialize(owner, name, attributes = {})
|
30
|
-
@owner
|
31
|
-
@name
|
32
|
-
@attributes
|
33
|
-
@children
|
34
|
-
@
|
36
|
+
@owner = owner
|
37
|
+
@name = name
|
38
|
+
@attributes = attributes
|
39
|
+
@children = []
|
40
|
+
@class_names = []
|
35
41
|
end
|
36
42
|
|
37
43
|
def each(&block)
|
38
|
-
return enum_for :each unless block
|
39
|
-
|
40
44
|
@children.each(&block)
|
41
|
-
|
42
|
-
self
|
43
45
|
end
|
44
46
|
|
45
47
|
def <<(what)
|
@@ -48,22 +50,16 @@ class Element < BasicObject
|
|
48
50
|
self
|
49
51
|
end
|
50
52
|
|
51
|
-
def text(text)
|
52
|
-
@children << text.to_s
|
53
|
-
|
54
|
-
self
|
55
|
-
end
|
56
|
-
|
57
53
|
def method_missing(name, content = nil, &block)
|
58
54
|
if content
|
59
|
-
self << content
|
55
|
+
self << ::Paggio::Utils.heredoc(content)
|
60
56
|
end
|
61
57
|
|
62
58
|
if name.to_s.end_with? ?!
|
63
59
|
@attributes[:id] = name[0 .. -2]
|
64
60
|
else
|
65
61
|
@last = name
|
66
|
-
@
|
62
|
+
@class_names.push(name)
|
67
63
|
end
|
68
64
|
|
69
65
|
@owner.extend!(self, &block) if block
|
@@ -74,8 +70,8 @@ class Element < BasicObject
|
|
74
70
|
def [](*names)
|
75
71
|
return unless @last
|
76
72
|
|
77
|
-
@
|
78
|
-
@
|
73
|
+
@class_names.pop
|
74
|
+
@class_names.push([@last, *names].join('-'))
|
79
75
|
|
80
76
|
self
|
81
77
|
end
|
@@ -93,6 +89,37 @@ class Element < BasicObject
|
|
93
89
|
"#<HTML::Element(#{@name.upcase}): #{@children.inspect[1 .. -2]}>"
|
94
90
|
end
|
95
91
|
end
|
92
|
+
|
93
|
+
class Img < self
|
94
|
+
defhelper :src do |url|
|
95
|
+
@attributes[:src] = url.to_s
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class A < self
|
100
|
+
defhelper :href do |url|
|
101
|
+
@attributes[:href] = url.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
defhelper :text do |string|
|
105
|
+
self << string
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Input < self
|
110
|
+
{ type: :type,
|
111
|
+
name: :name,
|
112
|
+
value: :value,
|
113
|
+
size: :size,
|
114
|
+
place_holder: :placeholder,
|
115
|
+
read_only: :readonly,
|
116
|
+
required: :required
|
117
|
+
}.each {|name, attribute|
|
118
|
+
defhelper name do |value|
|
119
|
+
@element[attribute] = value
|
120
|
+
end
|
121
|
+
}
|
122
|
+
end
|
96
123
|
end
|
97
124
|
|
98
125
|
end; end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#--
|
2
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
3
|
+
# Version 2, December 2004
|
4
|
+
#
|
5
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
6
|
+
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
7
|
+
#
|
8
|
+
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
|
+
#++
|
10
|
+
|
11
|
+
require 'kramdown'
|
12
|
+
|
13
|
+
class Paggio
|
14
|
+
|
15
|
+
class HTML < BasicObject
|
16
|
+
def markdown(string)
|
17
|
+
(@current || @roots) << ::Kramdown::Document.new(
|
18
|
+
::Paggio::Utils.heredoc(string))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Formatter.for Kramdown::Document do |f, item|
|
23
|
+
f.print item.to_html
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#--
|
2
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
3
|
+
# Version 2, December 2004
|
4
|
+
#
|
5
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
6
|
+
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
7
|
+
#
|
8
|
+
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
|
+
#++
|
10
|
+
|
11
|
+
require 'opal'
|
12
|
+
require 'sourcify'
|
13
|
+
|
14
|
+
class Paggio
|
15
|
+
|
16
|
+
class Script
|
17
|
+
def initialize(options = {}, &block)
|
18
|
+
@options = options
|
19
|
+
@block = block
|
20
|
+
end
|
21
|
+
|
22
|
+
def build
|
23
|
+
Opal.compile(@block.to_source['proc { '.length .. -' }'.length],
|
24
|
+
@options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class HTML < BasicObject
|
29
|
+
def script(*args, &block)
|
30
|
+
if block
|
31
|
+
(@current || @roots) << Script.new(*args, &block)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def local_variables(*)
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Formatter.for Script do |f, item|
|
43
|
+
f.print '<script><![CDATA['
|
44
|
+
f.indent {
|
45
|
+
f.print item.build
|
46
|
+
}
|
47
|
+
f.print ']]></script>'
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/lib/paggio/utils.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#--
|
2
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
3
|
+
# Version 2, December 2004
|
4
|
+
#
|
5
|
+
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
6
|
+
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
7
|
+
#
|
8
|
+
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
|
+
#++
|
10
|
+
|
11
|
+
class Paggio
|
12
|
+
|
13
|
+
module Utils
|
14
|
+
def self.heredoc(string)
|
15
|
+
indent = string.scan(/^[ \t]*(?=\S)/).min.size rescue 0
|
16
|
+
|
17
|
+
string.gsub(/^[ \t]{#{indent}}/, '')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.deep_merge(a, b)
|
21
|
+
merger = proc {|key, v1, v2|
|
22
|
+
if Hash === v1 && Hash === v2
|
23
|
+
v1.merge(v2, &merger)
|
24
|
+
else
|
25
|
+
v2
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
a.merge(b, &merger)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.deep_merge!(a, b)
|
33
|
+
merger = proc {|key, v1, v2|
|
34
|
+
if Hash === v1 && Hash === v2
|
35
|
+
v1.merge!(v2, &merger)
|
36
|
+
v1
|
37
|
+
else
|
38
|
+
v2
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
a.merge!(b, &merger)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/paggio.gemspec
CHANGED
data/spec/css_spec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'paggio'
|
2
|
+
|
3
|
+
describe Paggio::CSS do
|
4
|
+
it 'builds a rule' do
|
5
|
+
css = Paggio.css do
|
6
|
+
rule '#lol' do
|
7
|
+
color 'black'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
css.to_s.should == "#lol {\n\tcolor: black;\n}\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'builds border-radius correctly' do
|
15
|
+
css = Paggio.css do
|
16
|
+
rule '#lol' do
|
17
|
+
border radius: '5px'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
css.to_s.should == "#lol {\n\t-moz-border-radius: 5px;\n\t-webkit-border-radius: 5px;\n\tborder-radius: 5px;\n}\n"
|
22
|
+
|
23
|
+
css = Paggio.css do
|
24
|
+
rule '#lol' do
|
25
|
+
border radius: { top: { left: '5px' } }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
css.to_s.should == "#lol {\n\t-moz-border-radius-topleft: 5px;\n\t-webkit-border-top-left-radius: 5px;\n\tborder-top-left-radius: 5px;\n}\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'builds box-shadow correctly' do
|
33
|
+
css = Paggio.css do
|
34
|
+
rule '#lol' do
|
35
|
+
box shadow: '0 0 5px black'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
css.to_s.should == "#lol {\n\t-moz-box-shadow: 0 0 5px black;\n\t-webkit-box-shadow: 0 0 5px black;\n\tbox-shadow: 0 0 5px black;\n}\n"
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paggio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- meh.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: meh@schizofreni.co
|
@@ -16,16 +16,22 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- ".travis.yml"
|
19
20
|
- README.md
|
21
|
+
- Rakefile
|
20
22
|
- lib/paggio.rb
|
21
23
|
- lib/paggio/css.rb
|
22
24
|
- lib/paggio/css/definition.rb
|
23
25
|
- lib/paggio/css/unit.rb
|
24
|
-
- lib/paggio/
|
26
|
+
- lib/paggio/formatter.rb
|
25
27
|
- lib/paggio/html.rb
|
26
28
|
- lib/paggio/html/element.rb
|
29
|
+
- lib/paggio/markdown.rb
|
27
30
|
- lib/paggio/now.rb
|
31
|
+
- lib/paggio/script.rb
|
32
|
+
- lib/paggio/utils.rb
|
28
33
|
- paggio.gemspec
|
34
|
+
- spec/css_spec.rb
|
29
35
|
homepage: http://github.com/meh/paggio
|
30
36
|
licenses: []
|
31
37
|
metadata: {}
|
@@ -49,4 +55,5 @@ rubygems_version: 2.1.5
|
|
49
55
|
signing_key:
|
50
56
|
specification_version: 4
|
51
57
|
summary: Ruby, HTML and CSS at war.
|
52
|
-
test_files:
|
58
|
+
test_files:
|
59
|
+
- spec/css_spec.rb
|
data/lib/paggio/format.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
3
|
-
# Version 2, December 2004
|
4
|
-
#
|
5
|
-
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
6
|
-
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
7
|
-
#
|
8
|
-
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
9
|
-
#++
|
10
|
-
|
11
|
-
class Paggio
|
12
|
-
|
13
|
-
module Format
|
14
|
-
def self.puts(io, text, level = 0)
|
15
|
-
io.puts "#{"\t" * level}#{text}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.print(io, text, level = 0)
|
19
|
-
io.print "#{"\t" * level}#{text}"
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.escape(string)
|
23
|
-
string.to_s
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class HTML < BasicObject
|
28
|
-
Format = ::Paggio::Format
|
29
|
-
|
30
|
-
def format(io = ::StringIO.new, options = { indent: 0 })
|
31
|
-
case @version
|
32
|
-
when 5
|
33
|
-
Format.puts io, "<!DOCTYPE html>", options[:indent]
|
34
|
-
end
|
35
|
-
|
36
|
-
Format.puts io, "<html>", options[:indent]
|
37
|
-
|
38
|
-
each {|root|
|
39
|
-
root.format(io, indent: options[:indent] + 1)
|
40
|
-
}
|
41
|
-
|
42
|
-
Format.puts io, "</html>", options[:indent]
|
43
|
-
|
44
|
-
io
|
45
|
-
end
|
46
|
-
|
47
|
-
class Element < BasicObject
|
48
|
-
Format = ::Paggio::Format
|
49
|
-
|
50
|
-
def format(io = ::StringIO.new, options = { indent: 0 })
|
51
|
-
if @attributes.empty? && @class.empty?
|
52
|
-
Format.puts io, "<#{name}>", options[:indent]
|
53
|
-
else
|
54
|
-
attrs = @attributes.map {|name, value|
|
55
|
-
"#{Format.escape(name)}=\"#{Format.escape(value)}\""
|
56
|
-
}
|
57
|
-
|
58
|
-
unless @class.empty?
|
59
|
-
attrs << "class=\"#{Format.escape(@class.join(' '))}\""
|
60
|
-
end
|
61
|
-
|
62
|
-
Format.puts io, "<#{name} #{attrs.join(' ')}>", options[:indent]
|
63
|
-
end
|
64
|
-
|
65
|
-
each {|child|
|
66
|
-
case child
|
67
|
-
when ::String
|
68
|
-
child.lines.each {|line|
|
69
|
-
Format.puts io, line.strip, options[:indent] + 1
|
70
|
-
}
|
71
|
-
|
72
|
-
when CSS
|
73
|
-
Format.puts io, "<style>", options[:indent] + 1
|
74
|
-
child.format(io, indent: options[:indent] + 2)
|
75
|
-
Format.puts io, "</style>", options[:indent] + 1
|
76
|
-
|
77
|
-
else
|
78
|
-
child.format(io, indent: options[:indent] + 1)
|
79
|
-
end
|
80
|
-
|
81
|
-
io.puts
|
82
|
-
}
|
83
|
-
|
84
|
-
io.seek(-1, ::IO::SEEK_CUR)
|
85
|
-
|
86
|
-
Format.puts io, "</#{name}>", @children.empty? ? 0 : options[:indent]
|
87
|
-
|
88
|
-
io
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
class CSS < BasicObject
|
94
|
-
Format = ::Paggio::Format
|
95
|
-
|
96
|
-
def format(io = ::StringIO.new, options = { indent: 0 })
|
97
|
-
rules.reverse.each {|rule|
|
98
|
-
next if rule.definition.empty?
|
99
|
-
|
100
|
-
Format.puts io, "#{rule.selector} {", options[:indent]
|
101
|
-
|
102
|
-
rule.definition.each {|style|
|
103
|
-
Format.puts io, "#{style.name}: #{style.value}#{' !important' if style.important?};",
|
104
|
-
options[:indent] + 1
|
105
|
-
}
|
106
|
-
|
107
|
-
Format.puts io, "}", options[:indent]
|
108
|
-
io.puts
|
109
|
-
}
|
110
|
-
|
111
|
-
io.seek(-1, ::IO::SEEK_CUR)
|
112
|
-
|
113
|
-
io
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
end
|