mab 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []