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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5cd310cbe256ffe70545ac23588ee479889fe91
4
- data.tar.gz: 188cb2e8cc974b8f3742cf0c48b4f91f207e5009
3
+ metadata.gz: f45cce4c5e22a829c92ab432750b660ccbb3c5ce
4
+ data.tar.gz: b35cfc68c4599a09d058b58d30561faad7088127
5
5
  SHA512:
6
- metadata.gz: ac2680077e63109eef45e47dde0c8b0ca8c15c16328e3c66a064868e2e8af45f72a5b52b4bc4c6eb5475a00f1d736ed51b7fd5387b5ea5f796664100def2c24f
7
- data.tar.gz: 569b5c556e145aa41323f09fe470dcd5a6a4daa67c8b30e1d38c9bc7f582ed506b84ac1fb5926033eb6815ee95b09083737572b726bc136a74a856b3645eaec6
6
+ metadata.gz: f09353b8bf0a32cf35ec40ba71fbb0a7054068ed9c854597ca7dd567a2d19541a5bcda03fea9bacef434b4a36ddd3e0a58187ca0b467b8f8a9fd34ebf359fba0
7
+ data.tar.gz: 462b363f533688c41e2b799a7e246c736cd69fe99579f89c3122fbaad3f1327567d885a6ab870c5f485d3feb57ee2bd89553ee583d4ccff39f680aadaa721fb1
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - "2.0.0"
6
+ - jruby
7
+ - rbx
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
- I like trains.
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 SCSS are too mainstream. On a serious note, why have
127
- templating systems when you can just write Ruby?
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 'stringio'
12
-
13
- require 'paggio/css'
11
+ require 'paggio/utils'
14
12
  require 'paggio/html'
15
- require 'paggio/format'
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).format.string
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).format.string
30
+ Formatter.new.format(HTML.new(*args, &block)).to_s
24
31
  end
25
32
 
26
33
  def self.html!(&block)
27
- HTML.new(&block).root!.format.string
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
@@ -75,4 +75,10 @@ class CSS < BasicObject
75
75
  end
76
76
  end
77
77
 
78
+ class HTML < BasicObject
79
+ def style(&block)
80
+ (@current || @roots) << CSS.new(&block)
81
+ end
82
+ end
83
+
78
84
  end
@@ -28,11 +28,7 @@ class Definition < BasicObject
28
28
  end
29
29
 
30
30
  def each(&block)
31
- return enum_for :each unless block
32
-
33
31
  @style.each(&block)
34
-
35
- self
36
32
  end
37
33
 
38
34
  def gradient(*args)
@@ -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
+ '&' => '&amp;',
102
+ '>' => '&gt;',
103
+ '<' => '&lt;',
104
+ '"' => '&quot;',
105
+ "'" => '&#39;' })
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
 
@@ -23,23 +23,25 @@ class Element < BasicObject
23
23
  end
24
24
  end
25
25
 
26
- attr_reader :name, :attributes
27
- attr_accessor :inner_html
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 = owner
31
- @name = name
32
- @attributes = attributes
33
- @children = []
34
- @class = []
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
- @class.push(name)
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
- @class.delete(@last)
78
- @class.push([@last, *names].join('-'))
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
@@ -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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new {|s|
2
2
  s.name = 'paggio'
3
- s.version = '0.1.0'
3
+ s.version = '0.2.0'
4
4
  s.author = 'meh.'
5
5
  s.email = 'meh@schizofreni.co'
6
6
  s.homepage = 'http://github.com/meh/paggio'
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.1.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-12 00:00:00.000000000 Z
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/format.rb
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