mab 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require 'mab/version'
2
+ require 'mab/mixin'
3
+ require 'mab/indentation'
4
+ require 'mab/builder'
5
+
@@ -0,0 +1,45 @@
1
+ module Mab
2
+ class SimpleBuilder
3
+ include Mixin
4
+
5
+ def initialize(assigns = {}, helper = nil, &blk)
6
+ @_helper = helper
7
+ @_result = []
8
+
9
+ assigns.each do |key, value|
10
+ instance_variable_set(:"@#{key}", value)
11
+ end
12
+
13
+ if helper
14
+ helper.instance_variables.each do |var|
15
+ instance_variable_set(var, helper.instance_variable_get(var))
16
+ end
17
+ end
18
+
19
+ capture(&blk) if blk
20
+ end
21
+
22
+ def capture(&blk)
23
+ @_result << mab(&blk)
24
+ end
25
+
26
+ def to_s; @_result.join end
27
+
28
+ def method_missing(name, *args, &blk)
29
+ if @_helper && @_helper.respond_to?(name, true)
30
+ @_helper.send(name, *args, &blk)
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
36
+
37
+ class Builder < SimpleBuilder
38
+ include HTML5
39
+ end
40
+
41
+ class PrettyBuilder < Builder
42
+ include Indentation
43
+ end
44
+ end
45
+
@@ -0,0 +1,33 @@
1
+ module Mab
2
+ module Indentation
3
+ def mab_insert(str)
4
+ if i = @mab_context.options[:indentation]
5
+ super([$/ + " " * i, str])
6
+ else
7
+ @mab_context.options[:indentation] = 0
8
+ super
9
+ end
10
+ end
11
+
12
+ def mab_done(tag)
13
+ if blk = tag.block
14
+ tag.block = proc do
15
+ begin
16
+ @mab_context.options[:indentation] += 1
17
+ blk.call
18
+ ensure
19
+ @mab_context.options[:indentation] -= 1
20
+ end
21
+ end
22
+ end
23
+ super
24
+ end
25
+
26
+ def reindent!(str)
27
+ str.split(/\r?\n/).each do |s|
28
+ text! s
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,6 @@
1
+ require 'mab'
2
+
3
+ def mab(&blk)
4
+ Mab::PrettyBuilder.new({}, self, &blk).to_s
5
+ end
6
+
@@ -0,0 +1,246 @@
1
+ require 'cgi'
2
+
3
+ module Mab
4
+ module Mixin
5
+ class Error < StandardError; end
6
+ class Tag
7
+ attr_accessor :name, :content, :block
8
+ attr_reader :options, :context, :instance
9
+ attr_writer :attributes, :pos
10
+
11
+ def initialize(name, options, context, instance = nil)
12
+ @name = name
13
+ @options = options
14
+ @context = context
15
+ @instance = instance
16
+ @done = false
17
+ @content = false
18
+ @pos = @context.size
19
+ end
20
+
21
+ def attributes
22
+ @attributes ||= {}
23
+ end
24
+
25
+ def merge_attributes(attrs)
26
+ if defined?(@attributes)
27
+ @attributes.merge!(attrs)
28
+ else
29
+ @attributes = attrs
30
+ end
31
+ end
32
+
33
+ def method_missing(name, content = nil, attrs = nil, &blk)
34
+ name = name.to_s
35
+
36
+ if name[-1] == ?!
37
+ attributes[:id] = name[0..-2]
38
+ else
39
+ if attributes.has_key?(:class)
40
+ attributes[:class] += " #{name}"
41
+ else
42
+ attributes[:class] = name
43
+ end
44
+ end
45
+
46
+ insert(content, attrs, &blk)
47
+ end
48
+
49
+ def insert(content = nil, attrs = nil, &blk)
50
+ raise Error, "This tag is already closed" if @done
51
+
52
+ if content.is_a?(Hash)
53
+ attrs = content
54
+ content = nil
55
+ end
56
+
57
+ merge_attributes(attrs) if attrs
58
+
59
+ if block_given?
60
+ @block = blk
61
+ @done = true
62
+ elsif content
63
+ content = content.to_s
64
+ @content = CGI.escapeHTML(content)
65
+ @done = !content.empty?
66
+ elsif attrs
67
+ @done = true
68
+ end
69
+
70
+ @instance.mab_done(self) if @done
71
+
72
+ if @block
73
+ before = @context.children
74
+ res = @block.call
75
+
76
+ if before >= @context.children
77
+ @content = res.to_s
78
+ else
79
+ @content = nil
80
+ @instance.mab_insert("</#{@name}>")
81
+ end
82
+ end
83
+
84
+ self
85
+ end
86
+
87
+ def to_ary() nil end
88
+ def to_str() to_s end
89
+
90
+ def attrs_to_s
91
+ attributes.inject("") do |res, (name, value)|
92
+ if value
93
+ value = (value == true) ? name : CGI.escapeHTML(value.to_s)
94
+ res << " #{name}=\"#{value}\""
95
+ end
96
+ res
97
+ end
98
+ end
99
+
100
+ def to_s
101
+ if !@context.joining? && @context[@pos]
102
+ @context[@pos] = nil
103
+ @context.children -= 1
104
+ end
105
+ res = "<#{@name}#{attrs_to_s}"
106
+ res << (@options[:xml] && @content == false ? ' />' : '>')
107
+ res << "#{@content}</#{@name}>" if @content
108
+ res
109
+ end
110
+ end
111
+
112
+ class Context < Array
113
+ attr_accessor :children, :options
114
+
115
+ def initialize
116
+ @children = 0
117
+ @joining = false
118
+ @options = {}
119
+ end
120
+
121
+ def <<(str)
122
+ @children += 1
123
+ super(str)
124
+ end
125
+
126
+ def join(*)
127
+ @joining = true
128
+ super
129
+ end
130
+
131
+ def joining?
132
+ @joining
133
+ end
134
+ end
135
+
136
+ def tag!(name, content = nil, attrs = nil, &blk)
137
+ ctx = @mab_context || raise(Error, "Tags can only be written within a `mab { }`-block")
138
+ tag = Tag.new(name, mab_options, ctx, self)
139
+ mab_insert(tag)
140
+ tag.insert(content, attrs, &blk)
141
+ end
142
+
143
+ def text!(str)
144
+ mab_insert(str)
145
+ end
146
+
147
+ def text(str)
148
+ text! CGI.escapeHTML(str.to_s)
149
+ end
150
+
151
+ def mab(&blk)
152
+ prev = defined?(@mab_context) && @mab_context
153
+ ctx = @mab_context = Context.new
154
+ res = instance_eval(&blk)
155
+ ctx.empty? ? res : ctx.join
156
+ ensure
157
+ @mab_context = prev
158
+ end
159
+
160
+ def mab_insert(tag)
161
+ ctx = @mab_context || raise(Error, 'mab { }-block required')
162
+ ctx << tag
163
+ end
164
+
165
+ def mab_done(tag)
166
+ end
167
+
168
+ def mab_options
169
+ @mab_options ||= {}
170
+ end
171
+
172
+ module XML
173
+ include Mixin
174
+
175
+ def mab_options
176
+ @mab_options ||= super.update(:xml => true)
177
+ end
178
+ end
179
+
180
+ module HTMLDefiners
181
+ def define_tag(meth, tag)
182
+ class_eval <<-EOF
183
+ def #{meth}(content = "", attrs = nil, &blk)
184
+ if content.is_a?(Hash)
185
+ attrs = content
186
+ content = ""
187
+ end
188
+ tag!(:#{tag}, content, attrs, &blk)
189
+ end
190
+ EOF
191
+ end
192
+
193
+ def define_tags(*tags)
194
+ tags.flatten.each do |tag|
195
+ define_tag(tag, tag)
196
+ end
197
+ end
198
+
199
+ def define_empty_tag(meth, tag)
200
+ class_eval <<-EOF
201
+ def #{meth}(attrs = nil)
202
+ if (!attrs.nil? && !attrs.is_a?(Hash)) || block_given?
203
+ raise Error, "#{meth} doesn't allow content"
204
+ end
205
+ tag!(:#{tag}, attrs)
206
+ end
207
+ EOF
208
+ end
209
+
210
+ def define_empty_tags(*tags)
211
+ tags.flatten.each do |tag|
212
+ define_empty_tag(tag, tag)
213
+ end
214
+ end
215
+ end
216
+
217
+ module HTML5
218
+ extend HTMLDefiners
219
+ include Mixin
220
+
221
+ define_tags %w[a abbr acronym address applet article aside audio b
222
+ basefont bdi bdo big blockquote body button canvas caption
223
+ center cite code colgroup datalist dd del details dfn dir div dl
224
+ dt em fieldset figcaption figure font footer form frame frameset
225
+ h1 h2 h3 h4 h5 h6 head header hgroup html i iframe ins kbd label
226
+ legend li link map mark math menu meter nav noframes noscript
227
+ object ol optgroup option output p pre progress q rp rt ruby s
228
+ samp script section select small span strike strong style sub
229
+ summary sup svg table tbody td textarea tfoot th thead time
230
+ title tr tt u ul var video xmp]
231
+
232
+ define_empty_tags %w[base link meta hr br wbr img embed param source
233
+ track area col input keygen command]
234
+
235
+ def doctype!
236
+ text! '<!DOCTYPE html>'
237
+ end
238
+ end
239
+
240
+ module XHTML5
241
+ include HTML5
242
+ include XML
243
+ end
244
+ end
245
+ end
246
+
@@ -0,0 +1,4 @@
1
+ module Mab
2
+ VERSION = "0.0.1"
3
+ end
4
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mab
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Magnus Holm
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70107192708940 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70107192708940
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &70107192708280 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70107192708280
36
+ description:
37
+ email:
38
+ - judofyr@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - lib/mab/builder.rb
44
+ - lib/mab/indentation.rb
45
+ - lib/mab/kernel_method.rb
46
+ - lib/mab/mixin.rb
47
+ - lib/mab/version.rb
48
+ - lib/mab.rb
49
+ homepage:
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.10
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Markup as Ruby
73
+ test_files: []