sinatra-tags 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ doc
21
+
22
+ ## PROJECT::SPECIFIC
data/CHANGES ADDED
@@ -0,0 +1,5 @@
1
+
2
+ rel 0.1.0 (2010-03-02)
3
+
4
+ * intial release of gem / code
5
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 kematzy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,284 @@
1
+ = Sinatra::Tags
2
+
3
+ A Sinatra Extension that provides easy creation of flexible HTML tags.
4
+
5
+ == Why was this gem created ?
6
+
7
+ To enable the Sinatra community to quickly and easily add this functionality to any
8
+ app / extension they wish to create. ie: preventing time waste or the 're-invention of the wheel'.
9
+
10
+
11
+
12
+ == Installation
13
+
14
+ # Add RubyGems.org (former Gemcutter) to your RubyGems sources
15
+ $ gem sources -a http://rubygems.org
16
+
17
+ $ (sudo)? gem install sinatra-tags
18
+
19
+ == Dependencies
20
+
21
+ This Gem depends upon the following:
22
+
23
+ === Runtime:
24
+
25
+ * sinatra ( >= 1.0.a )
26
+ * sinatra-outputbuffer[http://github.com/kematzy/sinatra-outputbuffer] (>= 0.1.0)
27
+
28
+ Optionals:
29
+
30
+ * sinatra-settings[http://github.com/kematzy/sinatra-settings] (>= 0.1.1) # to view default settings in a browser display.
31
+
32
+
33
+ === Development & Tests:
34
+
35
+ * sinatra-tests (>= 0.1.6)
36
+ * rspec (>= 1.3.0 )
37
+ * rack-test (>= 0.5.3)
38
+ * rspec_hpricot_matchers (>= 0.1.0)
39
+
40
+ == Getting Started
41
+
42
+ To start using Sinatra::Tags, just require and register the extension
43
+
44
+ ...in your App...
45
+
46
+ require 'sinatra/tags'
47
+
48
+ class YourApp < Sinatra::Base
49
+ register(Sinatra::Tags)
50
+
51
+ <snip...>
52
+
53
+ end
54
+
55
+ ...or your Extension...
56
+
57
+ require 'sinatra/tags'
58
+
59
+ module Sinatra
60
+ module YourExtension
61
+
62
+ <snip...>
63
+
64
+ def self.registered(app)
65
+ app.register Sinatra::Tags
66
+ <snip...>
67
+ end
68
+
69
+ end
70
+ end
71
+
72
+
73
+ == Usage
74
+
75
+ Sinatra::Tags has only <b>one public method</b>, with this <b>dynamic</b> syntax:
76
+
77
+ tag(name)
78
+ tag(name, &block)
79
+
80
+ tag(name, content)
81
+ tag(name, content, attributes)
82
+ tag(name, content, attributes, &block)
83
+
84
+ tag(name, attributes)
85
+ tag(name, attributes, &block)
86
+
87
+
88
+ This dynamic syntax provides a very flexible method as you can see in the examples below:
89
+
90
+
91
+ <b>Self closing tags:</b>
92
+
93
+ tag(:br) # =>
94
+
95
+ <br> or <br/> if XHTML
96
+
97
+ tag(:hr, :class => "space") # =>
98
+
99
+ <hr class="space">
100
+
101
+ <b>Multi line tags:</b>
102
+
103
+ tag(:div) # =>
104
+
105
+ <div></div>
106
+
107
+ tag(:div, 'content') # =>
108
+
109
+ <div>
110
+ content
111
+ </div>
112
+
113
+ tag(:div, 'content', :id => 'comment') # =>
114
+
115
+ <div id="comment">
116
+ content
117
+ </div>
118
+
119
+ # NB! no content
120
+ tag(:div, :id => 'comment') # =>
121
+
122
+ <div id="comment"></div>
123
+
124
+
125
+ <b>Single line tags:</b>
126
+
127
+ tag(:h1,'Header') # =>
128
+
129
+ <h1>Header</h1>
130
+
131
+ tag(:abbr, 'WHO', :title => "World Health Organization") # =>
132
+
133
+ <abbr title="World Health Organization">WHO</abbr>
134
+
135
+
136
+ <b>Working with blocks</b>
137
+
138
+ tag(:div) do
139
+ tag(:p, 'Hello World')
140
+ end
141
+ # =>
142
+
143
+ <div>
144
+ <p>Hello World</p>
145
+ </div>
146
+
147
+ <% tag(:ul) do %>
148
+ <li>item 1</li>
149
+ <%= tag(:li, 'item 2') %>
150
+ <li>item 3</li>
151
+ <% end %>
152
+ # =>
153
+
154
+ <ul>
155
+ <li>item 1</li>
156
+ <li>item 2</li>
157
+ <li>item 3</li>
158
+ </ul>
159
+
160
+
161
+ # NB! ignored tag contents if given a block
162
+ <% tag(:div, 'ignored tag-content') do %>
163
+ <%= tag(:label, 'Comments:', :for => :comments) %>
164
+ <%= tag(:textarea,'textarea contents', :id => :comments) %>
165
+ <% end %>
166
+ # =>
167
+
168
+ <div>
169
+ <label for="comments">Comments:</label>
170
+ <textarea id="comments">
171
+ textarea contents
172
+ </textarea>
173
+ </div>
174
+
175
+
176
+
177
+ <b>Boolean attributes:</b>
178
+
179
+ tag(:input, :type => :checkbox, :checked => true)
180
+ # =>
181
+
182
+ <input type="checkbox" checked="checked" />
183
+
184
+
185
+ tag(:option, 'Sinatra', :value => "1" :selected => true)
186
+ # =>
187
+
188
+ <option value="1">Sinatra</option>
189
+
190
+
191
+ tag(:option, 'PHP', :value => "0" :selected => false)
192
+ # =>
193
+
194
+ <option value="0">PHP</option>
195
+
196
+
197
+ That's more or less it. Try it out and you'll see what it can do for you.
198
+
199
+
200
+ == Configuration Settings
201
+
202
+ The default settings should help you get moving quickly, and are fairly common sense based.
203
+
204
+
205
+ ==== <tt>:tags_output_format_is_xhtml</tt>
206
+
207
+ Sets the HTML output format, toggling between HTML vs XHTML.
208
+ Default is: <tt>false</tt>
209
+
210
+ I prefer to output in HTML 4.0.1 Strict, but you can easily switch to XHTML
211
+ by setting the value in your App or Extension:
212
+
213
+ set :tags_output_format_is_xhtml, true
214
+
215
+ ...or on the fly like this
216
+
217
+ YourApp.tags_output_format_is_xhtml = true / false
218
+
219
+ self.class.tags_output_format_is_xhtml = true / false
220
+
221
+ settings.tags_output_format_is_xhtml = true / false
222
+
223
+
224
+ ==== <tt>:tags_add_newlines_after_tags</tt>
225
+
226
+ Sets the formatting of the HTML output, whether it should be more compact in nature
227
+ or slightly better layed out.
228
+ Default is: <tt>true</tt>
229
+
230
+
231
+ == RTFM
232
+
233
+ If the above is not clear enough, please check the Specs for a better understanding.
234
+
235
+
236
+ == Errors / Bugs
237
+
238
+ If something is not behaving intuitively, it is a bug, and should be reported.
239
+ Report it here: http://github.com/kematzy/sinatra-tags/issues
240
+
241
+
242
+ == TODOs
243
+
244
+ * Keep it up to date with any changes in Sinatra.
245
+
246
+ * Decide on if it's worth it to do validity checks on all attributes passed to tags
247
+ ie: reject attributes based upon what is allowed for the tag.
248
+
249
+ tag(:base, :href => 'url', :target => '_self', :id => 'is-ignored')
250
+ # =>
251
+
252
+ <base href="url", target="_self">
253
+
254
+ * Decide on whether to add a number of convenience tags (methods), such as:
255
+
256
+ - meta(name, contents)
257
+
258
+ - img(src, attrs)
259
+
260
+
261
+ * Any other improvements I or You can think of.
262
+
263
+
264
+ == Note on Patches/Pull Requests
265
+
266
+ * Fork the project.
267
+ * Make your feature addition or bug fix.
268
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
269
+ * Commit, do not mess with rakefile, version, or history.
270
+ * (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
271
+ * Send me a pull request. Bonus points for topic branches.
272
+
273
+ == Copyright
274
+
275
+ Copyright (c) 2010 Kematzy
276
+
277
+ Released under the MIT License.
278
+
279
+ See LICENSE for further details.
280
+
281
+ === Code Inspirations:
282
+
283
+ * The ActiveSupport gem by DHH & Rails Core Team
284
+
data/Rakefile ADDED
@@ -0,0 +1,91 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "sinatra-tags"
8
+ gem.summary = %Q{A Sinatra Extension that provides easy creation of flexible HTML tags.}
9
+ gem.description = %Q{A Sinatra Extension that provides easy creation of flexible HTML tags.}
10
+ gem.email = "kematzy@gmail.com"
11
+ gem.homepage = "http://github.com/kematzy/sinatra-tags"
12
+ gem.authors = ["kematzy"]
13
+ gem.add_dependency('sinatra', '>=1.0.a')
14
+ gem.add_dependency('sinatra-outputbuffer', '>=0.1.0')
15
+ gem.add_development_dependency "sinatra-tests", ">= 0.1.6"
16
+ gem.add_development_dependency "rspec", ">= 1.3.0"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
34
+ spec.pattern = 'spec/**/*_spec.rb'
35
+ spec.rcov = true
36
+ end
37
+
38
+ namespace :spec do
39
+
40
+ desc "Run all specifications quietly"
41
+ Spec::Rake::SpecTask.new(:quiet) do |t|
42
+ t.libs << "lib"
43
+ t.spec_opts = ["--color", "--require", "spec/spec_helper.rb"]
44
+ end
45
+
46
+ desc "Run specific spec verbosely (SPEC=/path/2/file)"
47
+ Spec::Rake::SpecTask.new(:select) do |t|
48
+ t.libs << "lib"
49
+ t.spec_files = [ENV["SPEC"]]
50
+ t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
51
+ end
52
+
53
+ end
54
+
55
+ task :spec => :check_dependencies
56
+
57
+ task :default => :spec
58
+
59
+ require 'rake/rdoctask'
60
+ Rake::RDocTask.new do |rdoc|
61
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
62
+
63
+ rdoc.rdoc_dir = 'rdoc'
64
+ rdoc.title = "Sinatra::Tags #{version}"
65
+ rdoc.rdoc_files.include('README*')
66
+ rdoc.rdoc_files.include('lib/**/*.rb')
67
+ end
68
+
69
+ desc 'Build the rdoc HTML Files'
70
+ task :docs do
71
+ version = File.exist?('VERSION') ? IO.read('VERSION').chomp : "[Unknown]"
72
+
73
+ sh "sdoc -N --title 'Sinatra::Tags v#{version}' lib/ README.rdoc"
74
+ end
75
+
76
+ namespace :docs do
77
+
78
+ desc 'Remove rdoc products'
79
+ task :remove => [:clobber_rdoc]
80
+
81
+ desc 'Force a rebuild of the RDOC files'
82
+ task :rebuild => [:rerdoc]
83
+
84
+ desc 'Build docs, and open in browser for viewing (specify BROWSER)'
85
+ task :open => [:docs] do
86
+ browser = ENV["BROWSER"] || "safari"
87
+ sh "open -a #{browser} doc/index.html"
88
+ end
89
+
90
+ end
91
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,587 @@
1
+
2
+ require 'sinatra/base'
3
+ require 'sinatra/outputbuffer'
4
+
5
+ # :stopdoc:
6
+ class Hash
7
+
8
+ # remove any other version of #to_html_attributes
9
+ undef_method :to_html_attributes if method_defined?(:to_html_attributes)
10
+
11
+ def to_html_attributes(include_empties=nil)
12
+ hash = self.dup
13
+ hash.reject! {|k,v| v.blank? } unless include_empties.nil?
14
+ out = ''
15
+ hash.keys.each do |key|
16
+ val = hash[key].is_a?(Array) ? hash[key].join('_') : hash[key].to_s
17
+ out << "#{key.to_s}=\"#{val}\" "
18
+ end
19
+ out.strip
20
+ end
21
+
22
+ end
23
+ # :startdoc:
24
+
25
+ module Sinatra
26
+
27
+ # = Sinatra::Tags
28
+ #
29
+ # A Sinatra Extension that provides easy creation of flexible HTML tags.
30
+ #
31
+ # == Installation
32
+ #
33
+ # # Add RubyGems.org (former Gemcutter) to your RubyGems sources
34
+ # $ gem sources -a http://rubygems.org
35
+ #
36
+ # $ (sudo)? gem install sinatra-tags
37
+ #
38
+ # == Dependencies
39
+ #
40
+ # This Gem depends upon the following:
41
+ #
42
+ # === Runtime:
43
+ #
44
+ # * sinatra ( >= 1.0.a )
45
+ # * sinatra-outputbuffer[http://github.com/kematzy/sinatra-outputbuffer] (>= 0.1.0)
46
+ #
47
+ # Optionals:
48
+ #
49
+ # * sinatra-settings[http://github.com/kematzy/sinatra-settings] (>= 0.1.1) # to view default settings in a browser display.
50
+ #
51
+ #
52
+ # === Development & Tests:
53
+ #
54
+ # * sinatra-tests (>= 0.1.6)
55
+ # * rspec (>= 1.3.0 )
56
+ # * rack-test (>= 0.5.3)
57
+ # * rspec_hpricot_matchers (>= 0.1.0)
58
+ #
59
+ # == Getting Started
60
+ #
61
+ # To start using Sinatra::Tags, just require and register the extension
62
+ #
63
+ # ...in your App...
64
+ #
65
+ # require 'sinatra/tags'
66
+ #
67
+ # class YourApp < Sinatra::Base
68
+ # register(Sinatra::Tags)
69
+ #
70
+ # <snip...>
71
+ #
72
+ # end
73
+ #
74
+ # ...or your Extension...
75
+ #
76
+ # require 'sinatra/tags'
77
+ #
78
+ # module Sinatra
79
+ # module YourExtension
80
+ #
81
+ # <snip...>
82
+ #
83
+ # def self.registered(app)
84
+ # app.register Sinatra::Tags
85
+ # <snip...>
86
+ # end
87
+ #
88
+ # end
89
+ # end
90
+ #
91
+ #
92
+ # == Usage
93
+ #
94
+ # Sinatra::Tags has only <b>one public method</b>, with this <b>dynamic</b> syntax:
95
+ #
96
+ # tag(name)
97
+ # tag(name, &block)
98
+ #
99
+ # tag(name, content)
100
+ # tag(name, content, attributes)
101
+ # tag(name, content, attributes, &block)
102
+ #
103
+ # tag(name, attributes)
104
+ # tag(name, attributes, &block)
105
+ #
106
+ #
107
+ # This dynamic syntax provides a very flexible method as you can see in the examples below:
108
+ #
109
+ #
110
+ # <b>Self closing tags:</b>
111
+ #
112
+ # tag(:br) # =>
113
+ #
114
+ # <br> or <br/> if XHTML
115
+ #
116
+ # tag(:hr, :class => "space") # =>
117
+ #
118
+ # <hr class="space">
119
+ #
120
+ # <b>Multi line tags:</b>
121
+ #
122
+ # tag(:div) # =>
123
+ #
124
+ # <div></div>
125
+ #
126
+ # tag(:div, 'content') # =>
127
+ #
128
+ # <div>
129
+ # content
130
+ # </div>
131
+ #
132
+ # tag(:div, 'content', :id => 'comment') # =>
133
+ #
134
+ # <div id="comment">
135
+ # content
136
+ # </div>
137
+ #
138
+ # # NB! no content
139
+ # tag(:div, :id => 'comment') # =>
140
+ #
141
+ # <div id="comment"></div>
142
+ #
143
+ #
144
+ # <b>Single line tags:</b>
145
+ #
146
+ # tag(:h1,'Header') # =>
147
+ #
148
+ # <h1>Header</h1>
149
+ #
150
+ # tag(:abbr, 'WHO', :title => "World Health Organization") # =>
151
+ #
152
+ # <abbr title="World Health Organization">WHO</abbr>
153
+ #
154
+ #
155
+ # <b>Working with blocks</b>
156
+ #
157
+ # tag(:div) do
158
+ # tag(:p, 'Hello World')
159
+ # end
160
+ # # =>
161
+ #
162
+ # <div>
163
+ # <p>Hello World</p>
164
+ # </div>
165
+ #
166
+ # <% tag(:ul) do %>
167
+ # <li>item 1</li>
168
+ # <%= tag(:li, 'item 2') %>
169
+ # <li>item 3</li>
170
+ # <% end %>
171
+ # # =>
172
+ #
173
+ # <ul>
174
+ # <li>item 1</li>
175
+ # <li>item 2</li>
176
+ # <li>item 3</li>
177
+ # </ul>
178
+ #
179
+ #
180
+ # # NB! ignored tag contents if given a block
181
+ # <% tag(:div, 'ignored tag-content') do %>
182
+ # <%= tag(:label, 'Comments:', :for => :comments) %>
183
+ # <%= tag(:textarea,'textarea contents', :id => :comments) %>
184
+ # <% end %>
185
+ # # =>
186
+ #
187
+ # <div>
188
+ # <label for="comments">Comments:</label>
189
+ # <textarea id="comments">
190
+ # textarea contents
191
+ # </textarea>
192
+ # </div>
193
+ #
194
+ #
195
+ #
196
+ # <b>Boolean attributes:</b>
197
+ #
198
+ # tag(:input, :type => :checkbox, :checked => true)
199
+ # # =>
200
+ #
201
+ # <input type="checkbox" checked="checked" />
202
+ #
203
+ #
204
+ # tag(:option, 'Sinatra', :value => "1" :selected => true)
205
+ # # =>
206
+ #
207
+ # <option value="1">Sinatra</option>
208
+ #
209
+ #
210
+ # tag(:option, 'PHP', :value => "0" :selected => false)
211
+ # # =>
212
+ #
213
+ # <option value="0">PHP</option>
214
+ #
215
+ #
216
+ # That's more or less it. Try it out and you'll see what it can do for you.
217
+ #
218
+ #
219
+ # == Configuration Settings
220
+ #
221
+ # The default settings should help you get moving quickly, and are fairly common sense based.
222
+ #
223
+ #
224
+ # ==== <tt>:tags_output_format_is_xhtml</tt>
225
+ #
226
+ # Sets the HTML output format, toggling between HTML vs XHTML.
227
+ # Default is: <tt>false</tt>
228
+ #
229
+ # I prefer to output in HTML 4.0.1 Strict, but you can easily switch to XHTML
230
+ # by setting the value in your App or Extension:
231
+ #
232
+ # set :tags_output_format_is_xhtml, true
233
+ #
234
+ # ...or on the fly like this
235
+ #
236
+ # YourApp.tags_output_format_is_xhtml = true / false
237
+ #
238
+ # self.class.tags_output_format_is_xhtml = true / false
239
+ #
240
+ # settings.tags_output_format_is_xhtml = true / false
241
+ #
242
+ #
243
+ # ==== <tt>:tags_add_newlines_after_tags</tt>
244
+ #
245
+ # Sets the formatting of the HTML output, whether it should be more compact in nature
246
+ # or slightly better layed out.
247
+ # Default is: <tt>true</tt>
248
+ #
249
+ #
250
+ # == Copyright
251
+ #
252
+ # Copyright (c) 2010 Kematzy
253
+ #
254
+ # Released under the MIT License.
255
+ #
256
+ # See LICENSE for further details.
257
+ #
258
+ # === Code Inspirations:
259
+ #
260
+ # * The ActiveSupport gem by DHH & Rails Core Team
261
+ #
262
+ module Tags
263
+
264
+ VERSION = '0.1.0' unless const_defined?(:VERSION)
265
+
266
+ ##
267
+ # Returns the version string for this extension
268
+ #
269
+ # ==== Examples
270
+ #
271
+ # Sinatra::Tags.version => 'Sinatra::Tags v0.1.0'
272
+ #
273
+ def self.version; "Sinatra::Tags v#{VERSION}"; end
274
+
275
+
276
+ module Helpers
277
+
278
+ ##
279
+ # Tags that should be rendered in multiple lines, like...
280
+ #
281
+ # <body>
282
+ # <snip...>
283
+ # </body>
284
+ #
285
+ MULTI_LINE_TAGS = %w(
286
+ a address applet bdo big blockquote body button caption center
287
+ colgroup dd dir div dl dt fieldset form frameset head html iframe
288
+ map noframes noscript object ol optgroup pre script select small
289
+ style table tbody td textarea tfoot th thead title tr tt ul
290
+ )
291
+
292
+ ##
293
+ # Self closing tags, like...
294
+ #
295
+ # <hr> or <hr />
296
+ #
297
+ SELF_CLOSING_TAGS = %w( area base br col frame hr img input link meta param )
298
+
299
+ ##
300
+ # Tags that should be rendered in a single line, like...
301
+ #
302
+ # <h1>Header</h1>
303
+ #
304
+ SINGLE_LINE_TAGS = %w(
305
+ abbr acronym b cite code del dfn em h1 h2 h3 h4 h5 h6 i kbd
306
+ label legend li option p q samp span strong sub sup var
307
+ )
308
+
309
+ ##
310
+ # Boolean attributes, ie: attributes like...
311
+ #
312
+ # <input type="text" selected="selected"...>
313
+ #
314
+ BOOLEAN_ATTRIBUTES = %w( selected checked disabled readonly multiple )
315
+
316
+ ##
317
+ # Returns markup for tag _name_.
318
+ #
319
+ # Optionally _contents_ may be passed, which is literal content for
320
+ # spanning tags such as <tt>textarea</tt>, etc.
321
+ #
322
+ # A hash of _attrs_ may be passed as the *second* or *third* argument.
323
+ #
324
+ # Self closing tags such as <tt><br/></tt>, <tt><input/></tt>, etc
325
+ # are automatically closed depending on output format, HTML vs XHTML.
326
+ #
327
+ # Boolean attributes like "<tt>selected</tt>", "<tt>checked</tt>" etc,
328
+ # are mirrored or removed when <tt>true</tt> or <tt>false</tt>.
329
+ #
330
+ # ==== Examples
331
+ #
332
+ # Self closing tags:
333
+ #
334
+ # tag(:br)
335
+ # # => <br> or <br/> if XHTML
336
+ #
337
+ # tag(:hr, :class => "space")
338
+ # # => <hr class="space">
339
+ #
340
+ # Multi line tags:
341
+ #
342
+ # tag(:div)
343
+ # # => <div></div>
344
+ #
345
+ # tag(:div, 'content')
346
+ # # => <div>content</div>
347
+ #
348
+ # tag(:div, 'content', :id => 'comment')
349
+ # # => <div id="comment">content</div>
350
+ #
351
+ # tag(:div, :id => 'comment') # NB! no content
352
+ # # => <div id="comment"></div>
353
+ #
354
+ # Single line tags:
355
+ #
356
+ # tag(:h1,'Header')
357
+ # # => <h1>Header</h1>
358
+ #
359
+ # tag(:abbr, 'WHO', :title => "World Health Organization")
360
+ # # => <abbr title="World Health Organization">WHO</abbr>
361
+ #
362
+ # Working with blocks
363
+ #
364
+ # tag(:div) do
365
+ # tag(:p, 'Hello World')
366
+ # end
367
+ # # => <div><p>Hello World</p></div>
368
+ #
369
+ # <% tag(:div) do %>
370
+ # <p>Paragraph 1</p>
371
+ # <%= tag(:p, 'Paragraph 2') %>
372
+ # <p>Paragraph 3</p>
373
+ # <% end %>
374
+ # # =>
375
+ # <div>
376
+ # <p>Paragraph 1</p>
377
+ # <p>Paragraph 2</p>
378
+ # <p>Paragraph 3</p>
379
+ # </div>
380
+ #
381
+ #
382
+ # # NB! ignored tag contents if given a block
383
+ # <% tag(:div, 'ignored tag-content') do %>
384
+ # <%= tag(:label, 'Comments:', :for => :comments) %>
385
+ # <%= tag(:textarea,'textarea contents', :id => :comments) %>
386
+ # <% end %>
387
+ # # =>
388
+ # <div>
389
+ # <label for="comments">Comments:</label>
390
+ # <textarea id="comments">
391
+ # textarea contents
392
+ # </textarea>
393
+ # </div>
394
+ #
395
+ #
396
+ #
397
+ # Boolean attributes:
398
+ #
399
+ # tag(:input, :type => :checkbox, :checked => true)
400
+ # # => <input type="checkbox" checked="checked" />
401
+ #
402
+ # tag(:option, 'Sinatra', :value => "1" :selected => true)
403
+ # # => <option value="1">Sinatra</option>
404
+ #
405
+ # tag(:option, 'PHP', :value => "0" :selected => false)
406
+ # # => <option value="0">PHP</option>
407
+ #
408
+ #
409
+ # @api public
410
+ def tag(*args, &block)
411
+ name = args.first
412
+ attrs = args.last.is_a?(::Hash) ? args.pop : {}
413
+ newline = attrs[:newline] # save before it gets tainted
414
+
415
+ tag_content = block_given? ? capture_html(&block) : args[1] # content
416
+
417
+ if self_closing_tag?(name)
418
+ tag_html = self_closing_tag(name, attrs)
419
+ else
420
+ tag_html = open_tag(name, attrs) + tag_contents_for(name, tag_content, newline) + closing_tag(name)
421
+ end
422
+ block_is_template?(block) ? concat_content(tag_html) : tag_html
423
+ end
424
+
425
+
426
+ private
427
+
428
+ ##
429
+ # Return an opening tag of _name_, with _attrs_.
430
+ #
431
+ # @api private
432
+ def open_tag(name, attrs = {})
433
+ "<#{name}#{normalize_html_attributes(attrs)}>"
434
+ end
435
+
436
+ ##
437
+ # Return closing tag of _name_.
438
+ #
439
+ # @api private
440
+ def closing_tag(name)
441
+ "</#{name}>#{add_newline?}"
442
+ end
443
+
444
+ ##
445
+ # Creates a self closing tag. Like <br/> or <img src="..."/>
446
+ #
447
+ # ==== Options
448
+ # +name+ : the name of the tag to create
449
+ # +attrs+ : a hash where all members will be mapped to key="value"
450
+ #
451
+ # @api private
452
+ def self_closing_tag(name, attrs = {})
453
+ newline = (attrs[:newline].nil?) ? nil : attrs.delete(:newline)
454
+ "<#{name}#{normalize_html_attributes(attrs)}#{is_xhtml?}#{add_newline?(newline)}"
455
+ end
456
+
457
+ ##
458
+ # Based upon the context, wraps the tag content in '\n' (newlines)
459
+ #
460
+ # ==== Examples
461
+ #
462
+ # tag_contents_for(:div, 'content', nil)
463
+ # # => <div>\ncontent\n</div>
464
+ #
465
+ # tag_contents_for(:div, 'content', false)
466
+ # # => <div>content</div>
467
+ #
468
+ # Single line tag
469
+ # tag_contents_for(:option, 'content', true)
470
+ # # => <option...>\ncontent\n</option>
471
+ #
472
+ # @api private
473
+ def tag_contents_for(name, content, newline = nil )
474
+ if multi_line_tag?(name)
475
+ "#{add_newline?(newline)}#{content.to_s}#{add_newline?(newline)}"
476
+ elsif single_line_tag?(name) && newline === true
477
+ "#{add_newline?(newline)}#{content.to_s}#{add_newline?(newline)}"
478
+ else
479
+ content.to_s
480
+ end
481
+ end
482
+
483
+ ##
484
+ # Normalize _attrs_, replacing boolean keys
485
+ # with their mirrored values.
486
+ #
487
+ # @api private
488
+ def normalize_html_attributes(attrs = {})
489
+ return if attrs.blank?
490
+ attrs.delete(:newline) # remove newline from attributes
491
+ attrs.each do |name, value|
492
+ if boolean_attribute?(name)
493
+ value === true ? attrs[name] = name : attrs.delete(name)
494
+ end
495
+ end
496
+ return attrs.empty? ? '' : ' ' + attrs.to_html_attributes
497
+ end
498
+
499
+ ##
500
+ # Check if _name_ is a boolean attribute.
501
+ #
502
+ # @api private
503
+ def boolean_attribute?(name)
504
+ BOOLEAN_ATTRIBUTES.include?(name.to_s)
505
+ end
506
+
507
+ ##
508
+ # Check if tag _name_ is a self-closing tag.
509
+ #
510
+ # @api private
511
+ def self_closing_tag?(name)
512
+ SELF_CLOSING_TAGS.include?(name.to_s)
513
+ end
514
+
515
+ ##
516
+ # Check if tag _name_ is a single line tag.
517
+ #
518
+ # @api private
519
+ def single_line_tag?(name)
520
+ SINGLE_LINE_TAGS.include?(name.to_s)
521
+ end
522
+
523
+ ##
524
+ # Check if tag _name_ is a multi line tag.
525
+ #
526
+ # @api private
527
+ def multi_line_tag?(name)
528
+ MULTI_LINE_TAGS.include?(name.to_s)
529
+ end
530
+
531
+ ##
532
+ # Returns '>' or ' />' based on the output format used,
533
+ # ie: HTML vs XHTML
534
+ #
535
+ # @api private
536
+ def is_xhtml?
537
+ settings.tags_output_format_is_xhtml ? " />" : ">"
538
+ end
539
+
540
+ ##
541
+ #
542
+ #
543
+ # @api private
544
+ def add_newline?(add_override=nil)
545
+ add = (add_override.nil?) ? settings.tags_add_newlines_after_tags : add_override
546
+ add === true ? "\n" : ''
547
+ end
548
+
549
+ end #/ Helpers
550
+
551
+ ##
552
+ # Registers these Extensions:
553
+ #
554
+ # * Sinatra::OutputBuffer
555
+ #
556
+ # Default Settings:
557
+ #
558
+ # * +:tags_output_format_is_xhtml+ => sets the HTML output format. Default is: +false+
559
+ #
560
+ # * +:tags_add_newlines_after_tags+ => sets whether to add new lines to the HTML tags. Default is: +true+
561
+ #
562
+ #
563
+ # @api public
564
+ def self.registered(app)
565
+ app.register(Sinatra::OutputBuffer)
566
+ app.helpers Sinatra::Tags::Helpers
567
+
568
+ # set the HTML output formats
569
+ app.set :tags_output_format_is_xhtml, false
570
+ # set the HTML output formats
571
+ app.set :tags_add_newlines_after_tags, true
572
+
573
+ ## add the extension specific options to those inspectable by :settings_inspect method
574
+ # provided by the Sinatra::Settings extension
575
+ if app.respond_to?(:sinatra_settings_for_inspection)
576
+ %w( tags_add_newlines_after_tags tags_output_format_is_xhtml ).each do |m|
577
+ app.sinatra_settings_for_inspection << m
578
+ end
579
+ end
580
+
581
+ end #/ self.registered
582
+
583
+ end #/ Tags
584
+
585
+ register(Sinatra::Tags)
586
+
587
+ end #/ Sinatra