sinatra-exstatic-assets 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/exstatic_assets'
3
+
4
+ module Example
5
+ class App2 < Sinatra::Base
6
+ register Sinatra::Exstatic
7
+
8
+ get "/" do
9
+ erb :index
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,93 @@
1
+ body {
2
+ width: 480px; margin: 0px 30px;
3
+ }
4
+
5
+
6
+ header[role=banner] h2 {
7
+ font-size: 18px; margin: 0px; color: #888;
8
+ font-style: italic;
9
+ }
10
+
11
+ ul { list-style-type: none }
12
+
13
+ nav ul {
14
+ list-style: none; padding: 0px; display: block;
15
+ clear: right; background-color: #888;
16
+ padding-left: 4px; height: 24px;
17
+ }
18
+
19
+ nav ul li {
20
+ display: inline; padding: 0px 20px 5px 10px;
21
+ height: 24px; border-right: 1px solid #ccc;
22
+ }
23
+
24
+ nav ul li a {
25
+ color: #993333; text-decoration: none;
26
+ font-size: 13px; font-weight: bold;
27
+ }
28
+
29
+ nav ul li a:hover {
30
+ color: #fff;
31
+ }
32
+
33
+ article > header time {
34
+ font-size: 14px; display: block; width: 26px;
35
+ padding: 2px; text-align: center; background-color: #993333;
36
+ color: #fff; font-weight: bold; -moz-border-radius: 6px;
37
+ -webkit-border-radius: 6px; border-radius: 6px; float: left;
38
+ margin-bottom: 10px;
39
+ }
40
+
41
+ article > header time span {
42
+ font-size: 10px; font-weight: normal;
43
+ text-transform: uppercase;
44
+ }
45
+
46
+ article > header h1 {
47
+ font-size: 30px; float: left;
48
+ margin:0;
49
+ margin-left: 14px;
50
+ text-shadow: 2px 2px 5px #333;
51
+ }
52
+
53
+ article > header h1 a {
54
+ color: #993333;
55
+ }
56
+
57
+ section > header h3 {
58
+ border-bottom: 1px dotted;
59
+ border-left: 1px dotted;
60
+ padding-left: 5px;
61
+ }
62
+
63
+ article > section {
64
+ margin-top: 30px;
65
+ }
66
+ article section section{
67
+ margin-bottom: 40px;
68
+ }
69
+
70
+ article > section header h1 {
71
+ font-size: 16px;
72
+ }
73
+
74
+ article p {
75
+ clear: both;
76
+ }
77
+
78
+ footer p {
79
+ text-align: center; font-size: 12px;
80
+ color: #888; margin-top: 24px;
81
+ }
82
+
83
+ code {
84
+ background: #E6E6E6;
85
+ border: 1px solid #D8D8D8;
86
+ display: block;
87
+ margin-bottom: 10px;
88
+ }
89
+
90
+ samp {
91
+ background: #F5F6CE;
92
+ display: block;
93
+ }
@@ -0,0 +1,8 @@
1
+ * {
2
+ font-family: 'Quicksand', sans-serif;
3
+ }
4
+
5
+ header[role=banner] h1 {
6
+ font-family: 'Cherry Swash', cursive;
7
+ font-size: 46px; margin: 0px;
8
+ }
Binary file
@@ -0,0 +1,105 @@
1
+ <header>
2
+ <h1>
3
+ <a href="#" title="Link to this post"
4
+ rel="bookmark">Usage</a>
5
+ </h1>
6
+ </header>
7
+ <p>Note that there is a Main App and an App2. This is to demonstrate that you can give links relative to the app, but if they are mounted with an extra prefix (using Rack#map, for example) the helper will respect that and produce the right href attribute.</p>
8
+ <section><header><h2>Installation and loading</h2></header>
9
+ <p>Start by installing:</p>
10
+ <code>gem 'sinatra-exstatic-assets'</code>
11
+ <p>Then require it in your Sinatra app.</p>
12
+ <code>require 'sinatra/exstatic_assets'</code>
13
+ </section>
14
+ <section>
15
+ <header><h2>The helpers</h2></header>
16
+ <p>Use these helpers in your views.</p>
17
+ <p>To add an attribute to a helper, pass it as an option, e.g. <code>width: "500"</code></p>
18
+ <p>Sometimes, you won't want the script tag (e.g. "/app2") prepended to the url, like in the case of a favicon. In that case you can pass in <code>url_options: {script_tag: false}</code> to the helper, e.g. <code>favicon_tag url_options: {script_tag: false}</code></p>
19
+ <section id='stylesheet_tag'>
20
+ <header>
21
+ <h3>stylesheet_tag</h3>
22
+ </header>
23
+ <p>The code:
24
+ </p>
25
+ <code>stylesheet_tag "/css/screen.css"</code>
26
+ <p>Output:</p>
27
+ <samp>
28
+ <%= Rack::Utils.escape_html( stylesheet_tag "/css/screen.css") %>
29
+ </samp>
30
+ <footer><p>Also known as:
31
+ <ul>
32
+ <li><code>css_tag</code></li>
33
+ <li><code>stylesheet</code></li>
34
+ </ul>
35
+ </footer>
36
+ </section>
37
+ <section id='javascript_tag'>
38
+ <header>
39
+ <h3>javascript_tag</h3>
40
+ </header>
41
+ <p>The code:
42
+ </p>
43
+ <code>javascript_tag "http://code.jquery.com/jquery-1.9.1.min.js"</code>
44
+ <p>Output:</p>
45
+ <samp>
46
+ <%= Rack::Utils.escape_html( javascript_tag "http://code.jquery.com/jquery-1.9.1.min.js") %>
47
+ </samp>
48
+ <p>The code:
49
+ </p>
50
+ <code>javascript_tag "/js/helpers.js"</code>
51
+ <p>Output:</p>
52
+ <samp>
53
+ <%= Rack::Utils.escape_html( javascript_tag "/js/helpers.js" ) %>
54
+ </samp>
55
+ <footer><p>Also known as:
56
+ <ul>
57
+ <li><code>javascript_include_tag</code></li>
58
+ <li><code>js_tag</code></li>
59
+ <li><code>script_tag</code></li>
60
+ </ul>
61
+ </footer>
62
+ </section>
63
+ <section id='image_tag'>
64
+ <header>
65
+ <h3>image_tag</h3>
66
+ </header>
67
+ <p>The code:
68
+ </p>
69
+ <code>image_tag "http://farm1.staticflickr.com/10/12470738_fc0212bf8c.jpg", width: "500", height: "375", alt: "Greased Lightning"</code>
70
+ <p>Output:</p>
71
+ <samp>
72
+ <%= Rack::Utils.escape_html( image_tag "http://farm1.staticflickr.com/10/12470738_fc0212bf8c.jpg", width: "500", height: "375", alt: "Greased Lightning" ) %>
73
+ </samp>
74
+ <p>The code:
75
+ </p>
76
+ <code>image_tag "/images/turnip.jpg", width: "500", height: "375", alt: "Turnip"</code>
77
+ <p>Output:</p>
78
+ <samp>
79
+ <%= Rack::Utils.escape_html( image_tag "/images/turnip.jpg", width: "500", height: "375", alt: "Turnip" ) %>
80
+ </samp>
81
+ <footer><p>Also known as:
82
+ <ul>
83
+ <li><code>img_tag</code></li>
84
+ <li><code>img</code></li>
85
+ </ul>
86
+ </footer>
87
+ </section>
88
+ <section id='favicon_tag'>
89
+ <header>
90
+ <h3>favicon_tag</h3>
91
+ </header>
92
+ <p>The code:
93
+ </p>
94
+ <code>favicon_tag</code>
95
+ <p>Output:</p>
96
+ <samp>
97
+ <%= Rack::Utils.escape_html( favicon_tag url_options: {script_tag: false} ) %>
98
+ </samp>
99
+ <footer><p>Also known as:
100
+ <ul>
101
+ <li><code>favicon</code></li>
102
+ </ul>
103
+ </footer>
104
+ </section>
105
+ </section>
@@ -0,0 +1,40 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Example</title>
6
+ <%= favicon_tag url_options: {script_tag: false} %>
7
+ <%= stylesheet_tag 'http://fonts.googleapis.com/css?family=Quicksand|Faster+One|Cherry+Swash:700|Titillium+Web', rel: 'stylesheet', type: 'text/css' %>
8
+ <%= stylesheet_tag "/css/base.css" %>
9
+ <%= stylesheet_tag "/css/screen.css" %>
10
+ <%= javascript_tag "http://code.jquery.com/jquery-1.9.1.min.js" %>
11
+
12
+ </head>
13
+
14
+ <body>
15
+ <header role='banner'>
16
+ <a href="http://www.flickr.com/photos/tjt195/12470738/" title="Greased Lightning by tarotastic, on Flickr"><%= image_tag "http://farm1.staticflickr.com/10/12470738_fc0212bf8c.jpg", width: "500", height: "375", alt: "Greased Lightning" %></a>
17
+ <hgroup>
18
+ <h1>Sinatra Exstatic Assets</h1>
19
+ <h2>Helpers for your JS, CSS and anything static</h2>
20
+ </hgroup>
21
+ </header>
22
+
23
+ <nav>
24
+ <ul>
25
+ <li><a href="/">Main app</a></li>
26
+ <li><a href="/app2">App 2</a></li>
27
+ <li><a href="https://rubygems.org/gems/sinatra-exstatic-assets">Rubygems</a></li>
28
+ <li><a href="https://github.com/yb66/sinatra-exstatic-assets">Source code</a></li>
29
+ </ul>
30
+ </nav>
31
+ <article>
32
+ <%= yield %>
33
+ </article>
34
+
35
+
36
+ <footer>
37
+ <p>&copy; <%= Time.now.year %> See the LICENCE file for more.</p>
38
+ </footer>
39
+ </body>
40
+ </html>
@@ -0,0 +1,17 @@
1
+ require File.expand_path "./app/main.rb", File.dirname(__FILE__)
2
+ require File.expand_path "./app2/main.rb", File.dirname(__FILE__)
3
+
4
+ module Example
5
+ def self.app
6
+ app = Rack::Builder.app do
7
+ map "/app2" do
8
+ run Example::App2
9
+ end
10
+
11
+ map "/" do
12
+ run Example::App
13
+ end
14
+ end
15
+ #run app
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.setup(:example)
6
+
7
+ root = File.expand_path File.dirname(__FILE__)
8
+ require File.expand_path("./config.rb", File.dirname(__FILE__))
9
+
10
+
11
+ run Example.app
@@ -0,0 +1,83 @@
1
+ <header>
2
+ <time datetime="<%= Time.now.httpdate %>" pubdate>
3
+ <span><%= Time.now.strftime "%B"%></span> <%= Time.now.mday %>
4
+ </time>
5
+ <h1>
6
+ <a href="#" title="Link to this post"
7
+ rel="bookmark">Usage</a>
8
+ </h1>
9
+ </header>
10
+ <p>This is an article that demonstrates how to use the library. Notice that this is a Main App and an App2. This is to demonstrate that you can give links relative to the app, but if they are mounted with an extra prefix (using Rack#map, for example) the helper will respect that and produce the right href attribute.</p>
11
+ <section><header><h2>Installation and loading</h2></header>
12
+ <p>Start by installing:</p>
13
+ <code>gem 'sinatra-static-assets'</code>
14
+ <p>Then require it in your Sinatra app.</p>
15
+ <code>require 'sinatra/static_assets'</code>
16
+ </section>
17
+ <section>
18
+ <section>
19
+ <header><h2>The helpers</h2></header>
20
+ <p>Use these helpers in your views.<p>
21
+
22
+ <section>
23
+ <header>
24
+ <h3>stylesheet_link_tag</h3>
25
+ </header>
26
+ <p>The code:
27
+ </p>
28
+ <code>stylesheet_link_tag "/css/screen.css"</code>
29
+ <p>Output:</p>
30
+ <samp>
31
+ <%= Rack::Utils.escape_html( stylesheet_link_tag "/css/screen.css") %>
32
+ </samp>
33
+ </section>
34
+ <section>
35
+ <header>
36
+ <h3>javascript_script_tag</h3>
37
+ </header>
38
+ <p>The code:
39
+ </p>
40
+ <code>javascript_script_tag "http://code.jquery.com/jquery-1.9.1.min.js"</code>
41
+ <p>Output:</p>
42
+ <samp>
43
+ <%= Rack::Utils.escape_html( javascript_script_tag "http://code.jquery.com/jquery-1.9.1.min.js") %>
44
+ </samp>
45
+ <footer><p>Also known as:
46
+ <ul>
47
+ <li><code>javascript_include_tag</code></li>
48
+ <li><code>js_tag</code></li>
49
+ <li><code>script_tag</code></li>
50
+ </ul>
51
+ </footer>
52
+ </section>
53
+ <section>
54
+ <header>
55
+ <h3>image_tag</h3>
56
+ </header>
57
+ <p>The code:
58
+ </p>
59
+ <code>image_tag "http://farm3.staticflickr.com/2474/3609420787_f7fc0e53c7.jpg", width: "500", height: "275", alt: "Magic Ball"</code>
60
+ <p>Output:</p>
61
+ <samp>
62
+ <%= Rack::Utils.escape_html( image_tag "http://farm3.staticflickr.com/2474/3609420787_f7fc0e53c7.jpg", width: "500", height: "275", alt: "Magic Ball") %>
63
+ </samp>
64
+ </section>
65
+ <section>
66
+ <header>
67
+ <h3>image_tag</h3>
68
+ </header>
69
+ <p>The code:
70
+ </p>
71
+ <code>favicon_tag</code>
72
+ <p>Output:</p>
73
+ <samp>
74
+ <%= Rack::Utils.escape_html( favicon_link_tag ) %>
75
+ </samp>
76
+ <footer><p>Also known as:
77
+ <ul>
78
+ <li><code>favicon_link_tag</code></li>
79
+ <li><code>link_favicon_tag</code></li>
80
+ </ul>
81
+ </footer>
82
+ </section>
83
+ </section>
@@ -0,0 +1,40 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Example</title>
6
+ <%= favicon_link_tag %>
7
+ <%= stylesheet_link_tag 'http://fonts.googleapis.com/css?family=Quicksand|Faster+One|Cherry+Swash:700|Titillium+Web', rel: 'stylesheet', type: 'text/css' %>
8
+ <%= stylesheet_link_tag "/css/base.css" %>
9
+ <%= stylesheet_link_tag "/css/screen.css" %>
10
+ <%= javascript_script_tag "http://code.jquery.com/jquery-1.9.1.min.js" %>
11
+
12
+ </head>
13
+
14
+ <body>
15
+ <header role='banner'>
16
+ <a href="http://www.flickr.com/photos/28931095@N03/3609420787/" title="Magic Ball by Sam Bald, on Flickr"><%= image_tag "http://farm3.staticflickr.com/2474/3609420787_f7fc0e53c7.jpg", width: "500", height: "375", alt: "Magic Ball" %></a>
17
+ <hgroup>
18
+ <h1>Sinatra Static Assets</h1>
19
+ <h2>Helpers for your JS, CSS and anything static</h2>
20
+ </hgroup>
21
+ </header>
22
+
23
+ <nav>
24
+ <ul>
25
+ <li><a href="/">Main app</a></li>
26
+ <li><a href="/app2">App 2</a></li>
27
+ <li><a href="https://rubygems.org/gems/sinatra-static-assets">Rubygems</a></li>
28
+ <li><a href="https://github.com/wbzyl/sinatra-static-assets">Source code</a></li>
29
+ </ul>
30
+ </nav>
31
+ <article>
32
+ <%= yield %>
33
+ </article>
34
+
35
+
36
+ <footer>
37
+ <p>&copy; <%= Time.now.year %> See the LICENCE file for more.</p>
38
+ </footer>
39
+ </body>
40
+ </html>
@@ -0,0 +1 @@
1
+ require_relative 'exstatic_assets.rb'
@@ -0,0 +1,304 @@
1
+ require 'sinatra/base'
2
+
3
+ # @see https://sinatrarb.com/intro The framework
4
+ module Sinatra
5
+
6
+ # A Sinatra extension for helping with static assets. You probably want to start with {Helpers}.
7
+ module Exstatic
8
+
9
+ # For creating HTML tags.
10
+ class Tag < ::String
11
+
12
+ # @param [String] name The tag name e.g. `link`.
13
+ # @param [Hash] options With the exception of any options listed here, these are passed to the tag to make the HTML attributes.
14
+ # @option options [TrueClass] :closed Whether to self-close the link XHTML style or not.
15
+ # @param [#call] block The contents of the block are wrapped by the HTML tag e.g. <p>This is from the block</p>
16
+ # @example
17
+ # Tag.new "img", {src: "/images/foo.jpg", width: "500"}
18
+ # # => "<img src="/images/foo.jpg" width="500" />"
19
+ def initialize( name, options={}, &block )
20
+ @name = name
21
+ @closed = (c = options.delete(:closed)).nil? ? true : c
22
+ @options = options
23
+ @attributes = self.class.make_attributes @options
24
+ @block = block
25
+ super tag
26
+ end
27
+
28
+ attr_reader :attributes, :options, :name
29
+
30
+ private
31
+
32
+
33
+ # @yield Its return value is used as the contents of the HTML tag.
34
+ def tag
35
+ return @tag if @tag
36
+ start_tag = "<#{@name} #{@attributes}".strip
37
+ @tag = if @block
38
+ "#{start_tag}>#{@block.call}</#{name}>"
39
+ elsif @closed
40
+ "#{start_tag} />"
41
+ else
42
+ "#{start_tag}>"
43
+ end
44
+ end
45
+
46
+
47
+ # Takes a hash and transforms it into a string of HTML attributes.
48
+ # @param [Hash] options
49
+ # @return [String]
50
+ def self.make_attributes( options )
51
+ options.sort
52
+ .map {|key, value| %(#{key}="#{value}") }
53
+ .join " "
54
+ end
55
+
56
+ end
57
+
58
+
59
+ # Encapsulates an asset, be it a stylesheet, an image…
60
+ class Asset < ::String
61
+
62
+ attr_reader :fullpath
63
+
64
+ # @param [String] filename Either the file name (and path relative to the public folder) or the external HTTP link.
65
+ # @param [String] asset_dir The asset directory. When used with Sinatra this will default to the directory defined by the `public_folder` setting.
66
+ def initialize( filename, asset_dir=nil ) # TODO failure strategy
67
+ if asset_dir.nil?
68
+ filename, asset_dir = [File.basename(filename), File.dirname(filename)]
69
+ end
70
+ # TODO fail if asset_dir.nil?
71
+ super filename
72
+ @fullpath = File.join( asset_dir, filename ) unless is_uri?
73
+ end
74
+
75
+
76
+ # If the asset is a local file this gets the timestamp.
77
+ # @return [Integer]
78
+ def timestamp
79
+ @timestamp ||= !is_uri? && exists? && mtime_int
80
+ end
81
+
82
+ # Takes the timestamp and returns it as a querystring.
83
+ # @return [String] `?ts=TIMESTAMP`
84
+ def querystring
85
+ timestamp ? "?ts=#{timestamp}" : nil
86
+ end
87
+
88
+ # We only need to check for a scheme/protocol to know
89
+ # it's not a file.
90
+ URI_PATTERN = %r{\A
91
+ (?:
92
+ [A-z]+
93
+ \:
94
+ )? # The protocol part. It's optional.
95
+ // /? # There will always be at least 2 //
96
+ }x
97
+
98
+ # Tests whether the asset is a file or an HTTP link by checking the scheme portion.
99
+ # @note
100
+ # A url will match:
101
+ # http://example.com
102
+ # //example.com
103
+ # but www.example.com or example.com will be treated as a file.
104
+ # @return [TrueClass]
105
+ def is_uri?
106
+ self =~ URI_PATTERN ? true : false
107
+ end
108
+
109
+
110
+ # Convenience, mainly for my convenience in stubbing during tests.
111
+ # @return [TrueClass]
112
+ def exists?
113
+ File.exists? fullpath
114
+ end
115
+
116
+
117
+ # Convenience, mainly for my convenience in stubbing during tests.
118
+ # @return [Int]
119
+ def mtime_int
120
+ File.mtime( fullpath ).to_i
121
+ end
122
+ end
123
+
124
+
125
+ # The private instance methods.
126
+ # @api private
127
+ module Private
128
+
129
+ private
130
+
131
+ # Wraps around Sinatra::Helpers#uri. Appends a querystring if passed an Asset object.
132
+ # @param [String,#querystring] addr
133
+ # @param [Hash] options
134
+ # @option options [TrueClass] :absolute see Sinatra::Helpers#uri
135
+ # @option options [TrueClass] :script_tag Whether to prepend the SCRIPT_TAG env variable.
136
+ # @return [String]
137
+ # @see Sinatra::Helpers#uri
138
+ def sss_url_for(addr, options=nil)
139
+ options ||= {}
140
+ absolute = options.delete :absolute
141
+ absolute = false if absolute.nil?
142
+ script_tag = options.delete(:script_tag)
143
+ script_tag = true if script_tag.nil?
144
+ href = uri addr, absolute, script_tag
145
+ addr.respond_to?(:querystring) ?
146
+ "#{href}#{addr.querystring}" :
147
+ href
148
+ end
149
+
150
+
151
+ # The default options passed with a stylesheet asset.
152
+ DEFAULT_CSS = {
153
+ # :type => "text/css", # not needed with HTML5
154
+ :charset => "utf-8",
155
+ :media => "screen",
156
+ :rel => "stylesheet"
157
+ }
158
+
159
+
160
+ # Produce a stylesheet link tag.
161
+ # @param [String] source The file or HTML resource.
162
+ # @param [Hash] options
163
+ # @option options [String] :asset_dir The directory the asset is held. Defaults to Sinatra's `public_folder` setting.
164
+ # @option options [Hash] :url_options Options for devising the URL.
165
+ # @option options [TrueClass] :script_tag Whether to prepend the SCRIPT_TAG env variable.
166
+ # @return [Tag]
167
+ def sss_stylesheet_tag(source, options = {})
168
+ asset_dir = options.delete(:asset_dir) || settings.public_folder
169
+ asset = Asset.new source, asset_dir
170
+ href = sss_url_for( asset, options.delete(:url_options) )
171
+ Tag.new "link", DEFAULT_CSS.merge(:href => href)
172
+ .merge(options)
173
+ end
174
+
175
+
176
+ # Default options for the javascript script tags.
177
+ DEFAULT_JS = {
178
+ # :type => "text/javascript",
179
+ :charset => "utf-8"
180
+ }
181
+
182
+
183
+ # Produce a javascript script tag.
184
+ # @see #sss_stylesheet_tag but there is no `closed` option here.
185
+ def sss_javascript_tag(source, options = {})
186
+ asset = Asset.new source, settings.public_folder
187
+ href = sss_url_for asset, options.delete(:url_options)
188
+ Tag.new("script", DEFAULT_JS.merge(:src => href)
189
+ .merge(options)
190
+ ) {}
191
+ end
192
+
193
+
194
+ # Make's sure the options don't get mixed up with the other args.
195
+ def sss_extract_options(a)
196
+ opts = a.last.respond_to?(:keys) ? a.pop : {}
197
+ [a, opts]
198
+ end
199
+
200
+
201
+ # @see #sss_stylesheet_tag
202
+ def sss_image_tag(source, options = {})
203
+ options[:src] = sss_url_for Asset.new( source, settings.public_folder ), options.delete(:url_options)
204
+ Tag.new "img", options
205
+ end
206
+
207
+ end
208
+
209
+ # These are the helpers available to a Sinatra app using the extension.
210
+ # @example
211
+ # # For a classic app
212
+ # require 'sinatra/exstatic'
213
+ # # That's all for a classic app, the helpers
214
+ # # are now available.
215
+ #
216
+ # # For a modular app
217
+ # require 'sinatra/base'
218
+ # require 'sinatra/exstatic'
219
+ # class MyApp < Sinatra::Base
220
+ # helpers Sinatra::Exstatic
221
+ module Helpers
222
+ include Private
223
+
224
+ # @!method image_tag(*sources)
225
+ # Produce an HTML img tag.
226
+ # @param [String] sources The file or HTML resource.
227
+ # @param [Hash] options
228
+ # @option options [String] :asset_dir The directory the asset is held. Defaults to Sinatra's `public_folder` setting.
229
+ # @option options [Hash] :url_options Options for devising the URL. (see sss_url_for)
230
+ # @return [#to_s]
231
+ # @example
232
+ # image_tag "/images/big-fish.jpg", width: "500", height: "250", alt: "The biggest fish in the world!"
233
+ # # => <img alt="The biggest fish in the world!" height="250" src="/images/big-fish.jpg?ts=1367933468" width="500" />
234
+
235
+ # @!method stylesheet_tag(*sources)
236
+ # Produce an HTML link tag to a stylesheet.
237
+ # @param [String] sources The file or HTML resource.
238
+ # @param [Hash] options
239
+ # @option options [String] :asset_dir The directory the asset is held. Defaults to Sinatra's `public_folder` setting.
240
+ # @option options [Hash] :url_options Options for devising the URL. (see sss_url_for)
241
+ # @return [#to_s]
242
+ # @example
243
+ # stylesheet_tag "/css/screen.css"
244
+ # # => <link charset="utf-8" href="/css/screen.css?ts=1367678587" media="screen" rel="stylesheet">
245
+
246
+ # @!method javascript_tag(*sources)
247
+ # Produce an HTML script tag.
248
+ # @param [String] sources The file or HTML resource.
249
+ # @param [Hash] options
250
+ # @option options [String] :asset_dir The directory the asset is held. Defaults to Sinatra's `public_folder` setting.
251
+ # @option options [Hash] :url_options Options for devising the URL. (see sss_url_for)
252
+ # @return [#to_s]
253
+ # @example
254
+ # javascript_tag "http://code.jquery.com/jquery-1.9.1.min.js"
255
+ # # => <script charset="utf-8" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
256
+ %w{image_tag stylesheet_tag javascript_tag}.each do |method_name|
257
+ define_method method_name do |*sources|
258
+ list, options = sss_extract_options sources
259
+ list.map {|source|
260
+ send "sss_#{method_name}", source, options
261
+ }.join "\n"
262
+ end
263
+ end
264
+
265
+
266
+ alias_method :img_tag, :image_tag
267
+ alias_method :css_tag, :stylesheet_tag
268
+ alias_method :stylesheet, :stylesheet_tag
269
+ alias_method :javascript_include_tag, :javascript_tag
270
+ alias_method :js_tag, :javascript_tag
271
+ alias_method :script_tag, :javascript_tag
272
+
273
+ # @param [String] source
274
+ # @param [Hash] options
275
+ # @option options [Hash] :url_options script_tag
276
+ # @example
277
+ # favicon_tag
278
+ # # => <link href="/favicon.ico" rel="icon">
279
+ def favicon_tag(*args)
280
+ source, options = sss_extract_options args
281
+ source = "favicon.ico" if source.nil? or source.empty?
282
+
283
+ # xhtml style like <link rel="shortcut icon" href="http://example.com/myicon.ico" />
284
+ options[:rel] ||= settings.xhtml ? "shortcut icon" : "icon"
285
+
286
+ options[:href] = sss_url_for(source, options.delete(:url_options))
287
+
288
+ Tag.new "link", options
289
+ end
290
+
291
+ alias_method :link_favicon_tag, :favicon_tag
292
+ alias_method :favicon, :favicon_tag
293
+
294
+ end
295
+
296
+ # Extending
297
+ def self.registered(app)
298
+ app.helpers Exstatic::Helpers
299
+ app.disable :xhtml
300
+ end
301
+ end
302
+
303
+ register Exstatic
304
+ end