sinatra-exstatic-assets 2.0.0

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,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