sinatra-head 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE.markdown +113 -0
- data/README.markdown +169 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/lib/sinatra/head.rb +39 -0
- data/lib/sinatra/head/data_helpers.rb +94 -0
- data/lib/sinatra/head/tag_helpers.rb +72 -0
- data/spec/sinatra/head_spec.rb +43 -0
- data/spec/sinatra/javascripts_spec.rb +67 -0
- data/spec/sinatra/stylesheet_spec.rb +62 -0
- data/spec/sinatra/title_spec.rb +68 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/dummy_app.rb +38 -0
- data/spec/title_spec.rb +5 -0
- metadata +149 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE.markdown
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
The Don't Be a Dick License
|
2
|
+
===========================
|
3
|
+
_version 0.2_
|
4
|
+
|
5
|
+
**Project:** [Sinatra::Head](http://github.com/SFEley/sinatra-head)
|
6
|
+
**Author:** Stephen Eley (<sfeley@gmail.com>)
|
7
|
+
|
8
|
+
This is a proposed draft of the **Don't Be a Dick** license for open source projects. The purpose of this license is to permit the broadest feasible scope for reuse and modification of creative work, restricted only by the requirement that one is not a dick about it.
|
9
|
+
|
10
|
+
1. Legal Parameters
|
11
|
+
-------------------
|
12
|
+
For legal purposes, the DBAD license is a superset of the [Apache License, Version 2.0][1] and incorporates all terms, conditions, privileges and limitations therein. The following text is a binding part of this license for this project:
|
13
|
+
|
14
|
+
> Copyright 2010 Stephen Eley
|
15
|
+
|
16
|
+
> Licensed under the Apache License, Version 2.0 (the "License");
|
17
|
+
you may not use this file except in compliance with the License.
|
18
|
+
You may obtain a copy of the License at
|
19
|
+
|
20
|
+
> <http://www.apache.org/licenses/LICENSE-2.0>
|
21
|
+
|
22
|
+
> Unless required by applicable law or agreed to in writing, software
|
23
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
24
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
25
|
+
See the License for the specific language governing permissions and
|
26
|
+
limitations under the License.
|
27
|
+
|
28
|
+
Nothing in the following text should be construed to inhibit, contradict, or override any part of the Apache License, Version 2.0.
|
29
|
+
|
30
|
+
2. Definitions
|
31
|
+
--------------
|
32
|
+
The following terms and definitions shall be in effect for the rest of this document.
|
33
|
+
|
34
|
+
> **NOTE:** Singular nouns and pronouns are used throughout this License for
|
35
|
+
grammatical convenience. However, any of the terms below _may_ refer to a
|
36
|
+
collective work or group of people. If this pegs your punctiliousness, you
|
37
|
+
are directed to mentally substitute "Person _or persons_," "Dick _or
|
38
|
+
dicks,_" etc., throughout this license. Just don't tell us about it.
|
39
|
+
|
40
|
+
### A. Project
|
41
|
+
|
42
|
+
A creative work of (software | writing | visual art | music) into which significant time and energy have been invested by people who _are not you,_ and which has been released into the world for the benefit of the general public (_including you._)
|
43
|
+
|
44
|
+
The **Project** may include, incorporate, derive from, or be inspired by other works. The Author, being a Reasonable Person, has made use of such source materials only as permitted by their own licenses or applicable law. The License you are reading applies only to those portions of the Project which are original and distinct to it. Source materials may be covered by their own licenses or conditions, and should not be assumed to have coverage under this License. (However, you are strongly encouraged not to be a dick about them either.)
|
45
|
+
|
46
|
+
### B. Author
|
47
|
+
|
48
|
+
A person who has invested significant time and energy into the Project licensed herein. Given the Author's release of the Project to the world under a liberal license, the Author is declared a Reasonable Person (at least within this context) and inherits all attributes, freedoms, and responsibilities thereof. No other assumptions are made about the Author, nor should you make any.
|
49
|
+
|
50
|
+
### C. Reasonable Person
|
51
|
+
|
52
|
+
A person who respects the time and energy that have been invested in the Project licensed herein, and acts accordingly. A Reasonable Person is broadly characterized as one who exercises his or her privilege to use, _not_ use, redistribute, modify, improve, worsen, review, report issues upon, participate in the community of, or ignore the work _without_ placing undue demands upon the Author. I.e., a Reasonable Person is a constituent of the majority of open source users and the population at large who are not Dicks.
|
53
|
+
|
54
|
+
### D. Dick
|
55
|
+
|
56
|
+
A person who _does not_ respect the time and energy that have been invested in the Project, and acts to punish such effort by giving others associated with the Project -- including, but not limited to, the Author -- a hard time. A Dick is nearly always selfish, but not necessarily with deliberate intent; some Dicks are merely thoughtless. The distinguishing characteristic of a Dick is that he or she places burdens upon Reasonable People, reducing their motivation to engage in open source activities. This damping effect is a significant detriment to the Project, to open source in general, to the production of new intellectual value in the world -- and, ultimately, to the Dick himself or herself.
|
57
|
+
|
58
|
+
> **NOTE:** Despite its original gender association, the word "Dick" is used herein in a _cultural_ context and not a _genital_ context. This License has chosen to adopt the term for its linguistic force and psychological impact, and sincerely regrets any inference of sexism. For purposes of the terms and conditions contained herein, it is understood that both men and women are equally capable of being Dicks.
|
59
|
+
|
60
|
+
> (But they shouldn't be.)
|
61
|
+
|
62
|
+
3. Permissions
|
63
|
+
--------------
|
64
|
+
|
65
|
+
The following privileges are granted explicitly and exclusively to Reasonable People. Although the Author acknowledges the practical unfeasibility of barring Dicks from enjoying the same privileges, they are nevertheless asked to refrain from any activity related to the Project _and/or_ to reconsider their behavior and stop being Dicks.
|
66
|
+
|
67
|
+
1. You are permitted to use the Project or any component of the Project.
|
68
|
+
|
69
|
+
2. You are permitted to redistribute the Project or any component of the Project, by itself or as part of a different work, provided that you give fair and reasonable credit back to the Author.
|
70
|
+
|
71
|
+
3. You are permitted to change the Project for your own needs or anyone else's. You may keep your changes to yourself or submit them back to the Author or the community, as you see fit, provided you are not a Dick about it.
|
72
|
+
|
73
|
+
4. You are permitted and encouraged to participate in any community related to the Project, or to create new communities.
|
74
|
+
|
75
|
+
5. You are permitted to report issues or problems with the Project, and to request that they be addressed, so long as the request is made in a reasonable fashion. (This privilege does _not_ oblige the Author to respond.)
|
76
|
+
|
77
|
+
6. You are permitted to make money from the Project. No recompense is owed to the Author unless by separate agreement, although sharing opportunities for mutual benefit is by no means discouraged.
|
78
|
+
|
79
|
+
7. You are permitted to discuss the Project in any medium, in any positive or negative spirit, so long as criticism is not libelous nor _ad hominem._ (I.e., don't lie, and keep it about the _work_ and not the _people._)
|
80
|
+
|
81
|
+
8. You are permitted to ignore the Project completely and make no use of it whatsoever. This right is irrevocable and absolute, and extended to Dicks and Reasonable People alike.
|
82
|
+
|
83
|
+
4. Limitations
|
84
|
+
--------------
|
85
|
+
|
86
|
+
The following restrictions are imposed explicitly and exclusively upon Dicks. These limitations are the inverse of the above privileges and are also tautological, as the prohibited actions are those _definitive_ of Dickhood.
|
87
|
+
|
88
|
+
1. You may not impede Reasonable People from exercising their privilege to use, redistribute, change, participate in, profit from, discuss, or ignore the Project.
|
89
|
+
|
90
|
+
2. You may not withhold the Author's credit for the Project, nor otherwise present the work of anyone else as your own.
|
91
|
+
|
92
|
+
3. You may not hold the Author responsible for any use or abuse of the Project by you or anyone else.
|
93
|
+
|
94
|
+
4. You may not troll, flame, nor dumb down any community associated with the Project.
|
95
|
+
|
96
|
+
5. Barring separate agreements, you may not _demand_ any time or attention on the part of the Author nor anyone else in the community. You may not hold the Author personally accountable for any issues you discover nor otherwise spread your own problems to other people.
|
97
|
+
|
98
|
+
6. You may not attempt to _compel_ time nor money from the Author nor any other community member by any means, including but not limited to legal action, intimidation, or annoyance.
|
99
|
+
|
100
|
+
7. You may not engage in _ad hominem_ (i.e. personal) attacks or criticism of the Author in the course of criticizing the Project.
|
101
|
+
|
102
|
+
8. You may not impede the absolute and irrevocable privilege of the Author and other members of the community to ignore you.
|
103
|
+
|
104
|
+
5. Use of This License
|
105
|
+
----------------------
|
106
|
+
The Don't Be a Dick License is released under the terms of the Don't Be a Dick License. Projects released under this License should remain under the License, and the terms of the License may not be modified by anyone other than the Project's original Author.
|
107
|
+
|
108
|
+
If you wish to make use of the License for your own open work, you may do so without asking permission, provided said work is truly your own, truly open, and you are truly not a Dick. You may modify the terms of the License to suit your own needs, but are strongly advised to annotate said changes. Modifications may not reduce the freedoms granted to Reasonable People as described in Section 3.
|
109
|
+
|
110
|
+
Reasonable People are _invited,_ but not compelled, to visit the Web site at <http://dbad-license.org> and browse or add their project to the repository of works released under the License.
|
111
|
+
|
112
|
+
|
113
|
+
[1]: http://apache.org/licenses/LICENSE-2.0
|
data/README.markdown
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
Sinatra::Head
|
2
|
+
=============
|
3
|
+
|
4
|
+
This is a simple asset and `<head>` tag manager for Sinatra projects. It allows dynamically adding or
|
5
|
+
changing stylesheets, javascript includes, or the page title at any level of Sinatra class inheritance
|
6
|
+
or within an action.
|
7
|
+
|
8
|
+
Setting Up
|
9
|
+
----------
|
10
|
+
You should know this part:
|
11
|
+
|
12
|
+
$ gem install sinatra-head
|
13
|
+
|
14
|
+
(Or `sudo gem install` if you're the last person on Earth who isn't using [RVM][1] yet.)
|
15
|
+
|
16
|
+
If you're developing a Sinatra ['classic'][2] application, then all you need to do is require the library:
|
17
|
+
|
18
|
+
# blah_app.rb
|
19
|
+
require 'sinatra'
|
20
|
+
require 'sinatra/head'
|
21
|
+
|
22
|
+
title << 'My Wonderful App'
|
23
|
+
stylesheets << 'main.css'
|
24
|
+
|
25
|
+
get '/blah' do
|
26
|
+
title << 'Feeling blah'
|
27
|
+
stylesheets << 'blah.css'
|
28
|
+
end
|
29
|
+
|
30
|
+
Then, in your layout, just call the `head_tag` helper:
|
31
|
+
|
32
|
+
# views/layout.haml
|
33
|
+
%html
|
34
|
+
=head_tag
|
35
|
+
%body
|
36
|
+
=yield
|
37
|
+
|
38
|
+
When called, you'll see a head that sets the charset to UTF-8, "**Feeling blah | My Wonderful App**" as the page title, and
|
39
|
+
includes both */stylesheets/main.css* and *stylesheets/blah.css*. You can override the default choices here with Sinatra settings.
|
40
|
+
|
41
|
+
If you're using the [Sinatra::Base][2] style, you also need to register the extension:
|
42
|
+
|
43
|
+
# bleh_app.rb
|
44
|
+
require 'sinatra/base'
|
45
|
+
require 'sinatra/head'
|
46
|
+
|
47
|
+
class BlehApp < Sinatra::Base
|
48
|
+
register Sinatra::Head
|
49
|
+
|
50
|
+
# Everything else is the same as the 'classic' example above.
|
51
|
+
end
|
52
|
+
|
53
|
+
See the Sinatra documentation on [using extensions][3] for more detail and rationale.
|
54
|
+
|
55
|
+
Head element
|
56
|
+
------------
|
57
|
+
**Tag helpers:** `head_tag`
|
58
|
+
|
59
|
+
This extension is all about the head and the layout. Accordingly, there's a convenient `head_tag` helper that puts together the four other elements described below:
|
60
|
+
|
61
|
+
<head>
|
62
|
+
<meta charset='UTF-8' />
|
63
|
+
<title>All title elements | as appended using the 'title' call | in reverse order</title>
|
64
|
+
<link rel='stylesheet' href='/stylesheets/first.css' />
|
65
|
+
<!-- ...other stylesheets as declared in order... -->
|
66
|
+
<script src="/javascript/first.js"></script>
|
67
|
+
<!-- ...other javascripts as declared in order... -->
|
68
|
+
</head>
|
69
|
+
|
70
|
+
If you want something more or something different, you can of course skip this and call the other _*\_tag_ methods any way you want.
|
71
|
+
|
72
|
+
*A note on style:* My markup flavor of choice is [HTML5][4]. HTML5 is backwards compatible with everything and does not require self-closing tags. However, some of you may be using XHTML, and I don't want to break your stuff over a minor religious difference. So the `meta` and `link` tags are self-closed, to keep your validators from complaining and because it doesn't really hurt anyone else.
|
73
|
+
|
74
|
+
Charset
|
75
|
+
-------
|
76
|
+
**Sinatra settings:** `:charset`
|
77
|
+
**Tag helpers:** `charset_tag`
|
78
|
+
|
79
|
+
It's best practice for all Web pages to declare their encoding -- even if the server _should_ be doing it, even if you only use ASCII, etc. etc. **Sinatra::Head** makes an opinionated choice and sets this to **utf-8** for you, but you can override it if you want:
|
80
|
+
|
81
|
+
set :charset, 'shift-jis'
|
82
|
+
|
83
|
+
You are of course responsible for making sure that the page output keeps any encoding promise you make. If you're using Ruby 1.9, it's a good idea to set the `Encoding.default_internal` value to utf-8 as well. Also note that using Sinatra's **content_type** helper will override this for any page by setting the HTTP headers directly, which take precedence over `<meta>` tags.
|
84
|
+
|
85
|
+
*A note on meta tags:* Someone is doubtless going to ask what happened to the _http-equiv_ or _content_ attributes. [This][5] is my short answer. If this fails to validate for any common use case, let me know.
|
86
|
+
|
87
|
+
Title
|
88
|
+
-----
|
89
|
+
**Sinatra settings:** `:title`, `:title_separator`
|
90
|
+
**Data helpers:** `title`, `title=`, `title_string`
|
91
|
+
**Tag helpers:** `title_tag`
|
92
|
+
|
93
|
+
Multi-part titles that describe the page, the category, and the site are standard practice for SEO and other reasons. **Sinatra::Head** manages this by setting up **title** as a Sinatra setting with an empty array and letting you add to it:
|
94
|
+
|
95
|
+
title << 'Site'
|
96
|
+
title << 'Page' # => 'Page | Site'
|
97
|
+
|
98
|
+
Note that the title chain unspools in LIFO order, not FIFO. (I.e., it's a stack, not a queue.)
|
99
|
+
|
100
|
+
If you want to blow away this chain for a single action, we do have a `title=` helper for the purpose. You can also change the separator from ` | ` to anything you want with the `:title_separator` setting.
|
101
|
+
|
102
|
+
Stylesheets
|
103
|
+
-----------
|
104
|
+
**Sinatra settings:** `:stylesheets`, `:stylesheet_path`
|
105
|
+
**Data helpers:** `stylesheets`, `expand_stylesheet_path`
|
106
|
+
**Tag helpers:** `stylesheet_tag`, `stylesheet_tags`
|
107
|
+
|
108
|
+
Like the _title_ setting, the _stylesheets_ setting begins life as an empty array. Thus, you can add sheets to it at any time. Simple filenames will have the *stylesheet_path* setting prepended for a consistent relative path (it defaults simply to _"stylesheets"_); hyperlinks beginning with `http:` or `https:` will not be touched.
|
109
|
+
|
110
|
+
stylesheets << 'main.css'
|
111
|
+
stylesheets << 'http://someothersite.org/popular_css_extension.css'
|
112
|
+
|
113
|
+
get '/blah' do
|
114
|
+
stylesheets << 'specific.css'
|
115
|
+
end
|
116
|
+
|
117
|
+
In your layout, you can call the `stylesheet_tag` helper for a single filename or URL you provide, or the `stylesheet_tags` helper which walks the array and creates a tag for each. (In FIFO or queue order, unlike _title._)
|
118
|
+
|
119
|
+
Currently nothing is done for nicer asset packaging, fingerprinting, compressing, etc. There's [Rack][10] [middleware][9] for some of it, and future iterations may include these features. If you'd really really like to see them, [create an issue][7] and ask for them.
|
120
|
+
|
121
|
+
Javascripts
|
122
|
+
-----------
|
123
|
+
**Sinatra settings:** `:javascripts`, `:javascript_path`
|
124
|
+
**Data helpers:** `javascripts`, `expand_javascript_path`
|
125
|
+
**Tag helpers:** `javascript_tag`, `javascript_tags`
|
126
|
+
|
127
|
+
These helpers are functionally very similar to the _stylesheets_ ones, allowing the addition of relative filenames (which will be expanded with the *javascript_path* setting) or full URLs. One wrinkle here is that you can _also_ include inline code:
|
128
|
+
|
129
|
+
javascripts << 'main.js'
|
130
|
+
javascripts << 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'
|
131
|
+
|
132
|
+
get '/blah' do
|
133
|
+
javascripts << %q[
|
134
|
+
window.onload = function(){
|
135
|
+
some_silly_thing;
|
136
|
+
};]
|
137
|
+
end
|
138
|
+
|
139
|
+
Inline code is detected by the presence of a semicolon, and will be included as the body of the `<script>` tag rather than as the **src=** attribute. (So if you have semicolons in your scripts' filenames or URLs... _What were you thinking?_)
|
140
|
+
|
141
|
+
As noted above for stylesheets, right now there are no facilities to minify, compress, or recombobulate your Javascript. Also as noted, [feel free to ask][7] or contribute.
|
142
|
+
|
143
|
+
Credit, Support, and Contributions
|
144
|
+
----------------------------------
|
145
|
+
This extension is the fault of **Stephen Eley**. You can reach me at <sfeley@gmail.com>. If you like science fiction stories, I know a [good podcast][6] for them as well.
|
146
|
+
|
147
|
+
If you find bugs, please report them on the [Github issue tracker][7].
|
148
|
+
|
149
|
+
The documentation can of course be found on [RDoc.info][8].
|
150
|
+
|
151
|
+
Contributions are welcome. This was a quick start to get me some features I needed in a complex stack of Sinatra apps. There's a lot more that _can_ be done on this, but I'll keep sniffing the wind to find out what _should_ be done.
|
152
|
+
|
153
|
+
License
|
154
|
+
-------
|
155
|
+
This project is licensed under the **Don't Be a Dick License**, version 0.2, and is copyright 2010 by Stephen Eley. See the [LICENSE.markdown][11] file or the [DBAD License site][12] for elaboration on not being a dick.
|
156
|
+
|
157
|
+
|
158
|
+
[1]: http://rvm.beginrescueend.com
|
159
|
+
[2]: https://sinatra.lighthouseapp.com/projects/9779/tickets/240-sinatrabase-vs-sinatradefault-vs-sinatraapplication
|
160
|
+
[3]: http://www.sinatrarb.com/extensions-wild.html
|
161
|
+
[4]: http://diveintohtml5.org/semantics.html
|
162
|
+
[5]: http://diveintohtml5.org/semantics.html#encoding
|
163
|
+
[6]: http://escapepod.org
|
164
|
+
[7]: http://github.com/SFEley/sinatra-head/issues
|
165
|
+
[8]: http://rdoc.info/projects/SFEley/sinatra-head
|
166
|
+
[9]: http://coderack.org/users/chriskottom/middlewares/66-rackdomainsprinkler
|
167
|
+
[10]: http://rack.rubyforge.org/doc/Rack/Static.html
|
168
|
+
[11]: http://github.com/SFEley/sinatra-head/blob/master/LICENSE.markdown
|
169
|
+
[12]: http://dbad-license.org
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sinatra-head"
|
8
|
+
gem.summary = %Q{A Sinatra extension that gets inside your <HEAD>.}
|
9
|
+
gem.description = %Q{Sinatra::Head provides class methods and helpers for dynamically controlling the fields in your <HEAD> element that are usually preset in your layout: the page title, stylesheet and javascript assets, etc. Asset lists are inherited throughout superclasses, subclasses, and within action methods, and basic asset path management is supported.}
|
10
|
+
gem.email = "sfeley@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/SFEley/sinatra-head"
|
12
|
+
gem.authors = ["Stephen Eley"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_development_dependency "yard", ">= 0"
|
15
|
+
gem.add_development_dependency "haml", ">= 3"
|
16
|
+
gem.add_development_dependency "capybara", ">= 0.3.8"
|
17
|
+
|
18
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'spec/rake/spectask'
|
26
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
27
|
+
spec.libs << 'lib' << 'spec'
|
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.pattern = 'spec/**/*_spec.rb'
|
34
|
+
spec.rcov = true
|
35
|
+
end
|
36
|
+
|
37
|
+
task :spec => :check_dependencies
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
begin
|
42
|
+
require 'yard'
|
43
|
+
YARD::Rake::YardocTask.new
|
44
|
+
rescue LoadError
|
45
|
+
task :yardoc do
|
46
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
47
|
+
end
|
48
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/sinatra/head.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
require 'sinatra/head/data_helpers'
|
4
|
+
require 'sinatra/head/tag_helpers'
|
5
|
+
|
6
|
+
module Sinatra
|
7
|
+
module Head
|
8
|
+
|
9
|
+
# # Exposes the 'title' setting so that it can be overwritten or appended to.
|
10
|
+
# # @see DataHelpers#title
|
11
|
+
# def title
|
12
|
+
# settings.title
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # Exposes the 'stylesheets' setting so that it can be overwritten or appended to.
|
16
|
+
# # @see DataHelpers#stylesheets
|
17
|
+
# def stylesheets
|
18
|
+
# settings.stylesheets
|
19
|
+
# end
|
20
|
+
|
21
|
+
def self.registered(app)
|
22
|
+
app.helpers DataHelpers
|
23
|
+
app.helpers TagHelpers
|
24
|
+
|
25
|
+
app.configure do
|
26
|
+
app.set :charset, 'utf-8'
|
27
|
+
|
28
|
+
app.set :title, []
|
29
|
+
app.set :title_separator, ' | '
|
30
|
+
|
31
|
+
app.set :stylesheets, []
|
32
|
+
app.set :stylesheet_path, '/stylesheets'
|
33
|
+
|
34
|
+
app.set :javascripts, []
|
35
|
+
app.set :javascript_path, '/javascript'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Head
|
3
|
+
|
4
|
+
# Helpers intended to be used in your Sinatra actions rather than your views. (Yes, you can use them both places,
|
5
|
+
# but setting any of these in a view _after_ your layout's rendered the <head> element is sort of pointless.)
|
6
|
+
module DataHelpers
|
7
|
+
# Exposes an array of title elements that you can read or add to. Can be set at both the class and
|
8
|
+
# instance (action) level.
|
9
|
+
#
|
10
|
+
# @example Recommended usage
|
11
|
+
# class MyApp < Sinatra::Base
|
12
|
+
# register Sinatra::Head
|
13
|
+
# title << 'My Application'
|
14
|
+
#
|
15
|
+
# get '/people' do
|
16
|
+
# title << 'Directory'
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# This will create a title by default that looks like:
|
21
|
+
# Directory | My Application
|
22
|
+
def title
|
23
|
+
@title ||= Array(settings.title.clone)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Overrides any title elements you've already set. It's more conventional to use the << operator instead.
|
27
|
+
def title=(val)
|
28
|
+
@title = Array(val)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the title elements you've set, in reverse order, separated by ' | '. (You can override this with
|
32
|
+
# a Sinatra option: `set :title_separator, ' <*> '`)
|
33
|
+
def title_string
|
34
|
+
title.reverse.join(settings.title_separator)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Exposes an array of stylesheets. Can be set at both the class and the instance (action) level.
|
38
|
+
# Full hyperlinks or relative filenames can be set; if relative, the final result will include the
|
39
|
+
# Sinatra stylesheet_path setting.
|
40
|
+
# @example Recommended usage
|
41
|
+
# class MyApp < Sinatra::Base
|
42
|
+
# register Sinatra::Head
|
43
|
+
# stylesheets << 'main.css'
|
44
|
+
# stylesheets << 'http://example.org/some_famous_grid_stylesheet.css'
|
45
|
+
#
|
46
|
+
# get '/form' do
|
47
|
+
# stylesheets << 'form.css'
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
def stylesheets
|
51
|
+
@stylesheets ||= Array(settings.stylesheets.clone)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the full path for a stylesheet's filename, with the Sinatra `stylesheet_path` setting
|
55
|
+
# prepending it. Full hyperlinks are not altered.
|
56
|
+
def expand_stylesheet_path(sheet)
|
57
|
+
if sheet =~ %r{^https?://}
|
58
|
+
sheet
|
59
|
+
else
|
60
|
+
File.join(settings.stylesheet_path, sheet)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Exposes an array of javascript sources. Can be set at both the class and the instance (action) level.
|
65
|
+
# Full hyperlinks or relative filenames can be set; if relative, the final result will include the
|
66
|
+
# Sinatra stylesheet_path setting.
|
67
|
+
# @example Recommended usage
|
68
|
+
# class MyApp < Sinatra::Base
|
69
|
+
# register Sinatra::Head
|
70
|
+
# javascripts << 'main.js'
|
71
|
+
# javascripts << 'http://example.org/some_popular_script.js'
|
72
|
+
#
|
73
|
+
# get '/form' do
|
74
|
+
# javascripts << 'form.js'
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
def javascripts
|
78
|
+
@javascripts ||= Array(settings.javascripts.clone)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the full path for a javascript source's filename, with the Sinatra `javascript_path` setting
|
82
|
+
# prepending it. Full hyperlinks are not altered.
|
83
|
+
def expand_javascript_path(script)
|
84
|
+
if script =~ %r{^https?://}
|
85
|
+
script
|
86
|
+
else
|
87
|
+
File.join(settings.javascript_path, script)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'sinatra/head/data_helpers'
|
2
|
+
|
3
|
+
# Helper methods
|
4
|
+
module Sinatra
|
5
|
+
module Head
|
6
|
+
# Methods intended for view or layout templates, to generate the usual set of metadata and include tags.
|
7
|
+
module TagHelpers
|
8
|
+
|
9
|
+
# Spits out a default <head> element which incorporates the <meta> and <title> elements as well as any given
|
10
|
+
# stylesheet or Javascript includes. This is a convenience; if there are other things you want in your head,
|
11
|
+
# there's no need to use this instead of making your own inside your layout.
|
12
|
+
def head_tag
|
13
|
+
<<-HEAD_TAG
|
14
|
+
<head>
|
15
|
+
#{charset_tag}
|
16
|
+
#{title_tag}
|
17
|
+
#{stylesheet_tags}
|
18
|
+
#{javascript_tags}
|
19
|
+
</head>
|
20
|
+
HEAD_TAG
|
21
|
+
end
|
22
|
+
|
23
|
+
# Spits out a <meta> tag with the named charset. Defaults to UTF-8, but you can override it
|
24
|
+
# with the Sinatra 'charset' setting.
|
25
|
+
def charset_tag
|
26
|
+
"<meta charset='#{settings.charset}' />"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Spits out a <title> element with anything that's been added to the title by various actions.
|
30
|
+
# The title array is treated like a stack; items are popped off of it in reverse order of
|
31
|
+
# inclusion.
|
32
|
+
def title_tag
|
33
|
+
"<title>#{title_string}</title>"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Spits out a <link rel='stylesheet'> element for the given stylesheet reference.
|
37
|
+
# Relative filenames will be expanded with the Sinatra assets path, if set.
|
38
|
+
#
|
39
|
+
# @param [String] sheet
|
40
|
+
def stylesheet_tag(sheet)
|
41
|
+
"<link rel='stylesheet' href='#{expand_stylesheet_path(sheet)}' />"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Spits out stylesheet tags for all declared stylesheets, one per line.
|
45
|
+
def stylesheet_tags
|
46
|
+
stylesheets.collect{|s| stylesheet_tag(s)}.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Spits out a <script src='filename'> element for the given javascript file.
|
50
|
+
# Relative filenames will be expanded with the Sinatra assets path, if set.
|
51
|
+
#
|
52
|
+
# EXCEPTION: If an item in 'javascripts' contains a semicolon, it will be interpreted
|
53
|
+
# as Javascript source code instead of a filename, and will be included inline in the
|
54
|
+
# script tag instead of on the 'src' element.
|
55
|
+
#
|
56
|
+
# @param [String] script
|
57
|
+
def javascript_tag(script)
|
58
|
+
if script.include?(';')
|
59
|
+
"<script>\n#{script}\n</script>"
|
60
|
+
else
|
61
|
+
"<script src='#{expand_javascript_path(script)}'></script>"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Spits out javascript tags for all declared scripts, one per line.
|
66
|
+
def javascript_tags
|
67
|
+
javascripts.collect{|s| javascript_tag(s)}.join("\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Sinatra::Head do
|
4
|
+
include DummyFixture
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
visit '/'
|
8
|
+
end
|
9
|
+
|
10
|
+
it "displays the head" do
|
11
|
+
page.should have_css('head')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has a title element" do
|
15
|
+
within 'head' do
|
16
|
+
page.should have_css('title')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "has a meta tag for the charset" do
|
21
|
+
within 'head' do
|
22
|
+
page.should have_css("meta[charset='utf-8']")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "lets you override the charset" do
|
27
|
+
class DummyGrandkid < DummyFixture::DummyChild
|
28
|
+
set :charset, 'iso-8859-1'
|
29
|
+
get '/new' do
|
30
|
+
title << 'Really Low Level'
|
31
|
+
haml "This is something new."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
app DummyGrandkid
|
35
|
+
|
36
|
+
visit '/'
|
37
|
+
within 'head' do
|
38
|
+
page.should have_css("meta[charset='iso-8859-1']")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Sinatra::Head, "javascripts" do
|
4
|
+
include DummyFixture
|
5
|
+
|
6
|
+
|
7
|
+
class DummyFixture::DummyApp
|
8
|
+
javascripts << 'main.js'
|
9
|
+
end
|
10
|
+
|
11
|
+
class DummyFixture::DummyChild
|
12
|
+
javascripts << 'secondary.js'
|
13
|
+
set :javascript_path, '/things/javascript'
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
app DummyFixture::DummyChild
|
18
|
+
@instance = app.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can be appended to in a top-level class" do
|
22
|
+
@instance.javascripts.should include('main.js')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can be appended to in a subclass" do
|
26
|
+
@instance.javascripts.should include('secondary.js')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can be appended to in an instance" do
|
30
|
+
@instance.javascripts << 'specific.js'
|
31
|
+
@instance.javascripts.should == ['main.js', 'secondary.js', 'specific.js']
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it "expands the assets path for relative filenames" do
|
36
|
+
@instance.expand_javascript_path(@instance.javascripts.first).should == '/things/javascript/main.js'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "leaves fully qualified hyperlinks intact" do
|
40
|
+
@instance.javascripts << 'http://google.com/google_script.js'
|
41
|
+
@instance.expand_javascript_path(@instance.javascripts[2]).should == 'http://google.com/google_script.js'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "knows how to make a tag" do
|
45
|
+
@instance.javascript_tag(@instance.javascripts.first).should == "<script src='/things/javascript/main.js'></script>"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "can make a tag for inline code" do
|
49
|
+
@instance.javascripts << "window.onload=alert('This is a page!');"
|
50
|
+
@instance.javascript_tag(@instance.javascripts[2]).should == "<script>\nwindow.onload=alert('This is a page!');\n</script>"
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
it "knows how to make all the tags" do
|
55
|
+
@instance.javascripts << 'http://yahoo.com/yahoo_script.js'
|
56
|
+
@instance.javascript_tags.should == "<script src='/things/javascript/main.js'></script>\n<script src='/things/javascript/secondary.js'></script>\n<script src='http://yahoo.com/yahoo_script.js'></script>"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "shows up in the header" do
|
60
|
+
visit '/'
|
61
|
+
within 'head' do
|
62
|
+
page.should have_css("script[src='/things/javascript/main.js']")
|
63
|
+
page.should have_css("script[src='/things/javascript/secondary.js']")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Sinatra::Head, "stylesheets" do
|
4
|
+
include DummyFixture
|
5
|
+
|
6
|
+
|
7
|
+
class DummyFixture::DummyApp
|
8
|
+
stylesheets << 'main.css'
|
9
|
+
end
|
10
|
+
|
11
|
+
class DummyFixture::DummyChild
|
12
|
+
stylesheets << 'secondary.css'
|
13
|
+
set :stylesheet_path, '/stuff/stylesheets'
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
app DummyFixture::DummyChild
|
18
|
+
@instance = app.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can be appended to in a top-level class" do
|
22
|
+
@instance.stylesheets.should include('main.css')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can be appended to in a subclass" do
|
26
|
+
@instance.stylesheets.should include('secondary.css')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can be appended to in an instance" do
|
30
|
+
@instance.stylesheets << 'specific.css'
|
31
|
+
@instance.stylesheets.should == ['main.css', 'secondary.css', 'specific.css']
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it "expands the assets path for relative filenames" do
|
36
|
+
@instance.expand_stylesheet_path(@instance.stylesheets.first).should == '/stuff/stylesheets/main.css'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "leaves fully qualified hyperlinks intact" do
|
40
|
+
@instance.stylesheets << 'http://google.com/google_style.css'
|
41
|
+
@instance.expand_stylesheet_path(@instance.stylesheets[2]).should == 'http://google.com/google_style.css'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "knows how to make a tag" do
|
45
|
+
@instance.stylesheet_tag(@instance.stylesheets.first).should == "<link rel='stylesheet' href='/stuff/stylesheets/main.css' />"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "knows how to make all the tags" do
|
49
|
+
@instance.stylesheets << 'http://yahoo.com/yahoo_style.css'
|
50
|
+
@instance.stylesheet_tags.should == "<link rel='stylesheet' href='/stuff/stylesheets/main.css' />\n<link rel='stylesheet' href='/stuff/stylesheets/secondary.css' />\n<link rel='stylesheet' href='http://yahoo.com/yahoo_style.css' />"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "shows up in the header" do
|
54
|
+
visit '/'
|
55
|
+
within 'head' do
|
56
|
+
page.should have_css("link[rel='stylesheet'][href='/stuff/stylesheets/main.css']")
|
57
|
+
page.should have_css("link[rel='stylesheet'][href='/stuff/stylesheets/secondary.css']")
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Sinatra::Head, "titles" do
|
4
|
+
include DummyFixture
|
5
|
+
|
6
|
+
|
7
|
+
class DummyFixture::DummyApp
|
8
|
+
title << 'High Level'
|
9
|
+
end
|
10
|
+
|
11
|
+
class DummyFixture::DummyChild
|
12
|
+
title << 'Mid-Level'
|
13
|
+
end
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@instance = app.new
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can be appended to in a top-level class" do
|
20
|
+
@instance.title.should include('High Level')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can be appended to in a subclass" do
|
24
|
+
@instance.title.should include('Mid-Level')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can be appended to in an instance" do
|
28
|
+
@instance.title << 'Low Level'
|
29
|
+
@instance.title.should == ['High Level', 'Mid-Level', 'Low Level']
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can be overridden" do
|
33
|
+
@instance.title = 'Kaboom!'
|
34
|
+
@instance.title.should == ['Kaboom!']
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns itself as a string" do
|
38
|
+
@instance.title << 'Low Level'
|
39
|
+
@instance.title_string.should == 'Low Level | Mid-Level | High Level'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can set a different title separator" do
|
43
|
+
class DummyGrandkid < DummyFixture::DummyChild
|
44
|
+
set :title_separator, ' <*> '
|
45
|
+
end
|
46
|
+
|
47
|
+
instance = DummyGrandkid.new
|
48
|
+
instance.title_string.should == 'Mid-Level <*> High Level'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "knows how to make a tag" do
|
52
|
+
@instance.title_tag.should == '<title>Mid-Level | High Level</title>'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "shows up in the title tag" do
|
56
|
+
class DummyGrandkid < DummyFixture::DummyChild
|
57
|
+
get '/new' do
|
58
|
+
title << 'Really Low Level'
|
59
|
+
haml "This is something new."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
app DummyGrandkid
|
63
|
+
|
64
|
+
visit '/new'
|
65
|
+
page.locate('title').text.should == 'Really Low Level | Mid-Level | High Level'
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'rack/test'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
require 'capybara'
|
7
|
+
require 'capybara/dsl'
|
8
|
+
|
9
|
+
require 'sinatra/head'
|
10
|
+
require 'support/dummy_app'
|
11
|
+
|
12
|
+
Spec::Runner.configure do |config|
|
13
|
+
include Rack::Test::Methods
|
14
|
+
include Capybara
|
15
|
+
Capybara.default_selector = :css
|
16
|
+
end
|
17
|
+
|
18
|
+
# Confirm our dummy app
|
19
|
+
describe "Dummy app" do
|
20
|
+
include DummyFixture
|
21
|
+
|
22
|
+
it "returns a page" do
|
23
|
+
app DummyApp
|
24
|
+
visit('/')
|
25
|
+
page.should have_content('Hello dummy')
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module DummyFixture
|
4
|
+
# A simple dummy app to perform our tests against. We make our templates out of strings so that we
|
5
|
+
# can change them easily in our tests.
|
6
|
+
class DummyApp < Sinatra::Base
|
7
|
+
set :environment, :test
|
8
|
+
enable :inline_templates
|
9
|
+
|
10
|
+
register Sinatra::Head
|
11
|
+
|
12
|
+
get "/" do
|
13
|
+
haml :index
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class DummyChild < DummyApp
|
18
|
+
end
|
19
|
+
|
20
|
+
def app(klass=nil)
|
21
|
+
if klass
|
22
|
+
Capybara.app = klass
|
23
|
+
else
|
24
|
+
Capybara.app ||= DummyChild
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
__END__
|
30
|
+
|
31
|
+
@@ layout
|
32
|
+
%html
|
33
|
+
=head_tag
|
34
|
+
%body
|
35
|
+
= yield
|
36
|
+
|
37
|
+
@@ index
|
38
|
+
Hello dummy!
|
data/spec/title_spec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-head
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Stephen Eley
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-05-20 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
34
|
+
version: 1.2.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: yard
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: haml
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 5
|
60
|
+
segments:
|
61
|
+
- 3
|
62
|
+
version: "3"
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: capybara
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
- 3
|
77
|
+
- 8
|
78
|
+
version: 0.3.8
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
description: "Sinatra::Head provides class methods and helpers for dynamically controlling the fields in your <HEAD> element that are usually preset in your layout: the page title, stylesheet and javascript assets, etc. Asset lists are inherited throughout superclasses, subclasses, and within action methods, and basic asset path management is supported."
|
82
|
+
email: sfeley@gmail.com
|
83
|
+
executables: []
|
84
|
+
|
85
|
+
extensions: []
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE.markdown
|
89
|
+
- README.markdown
|
90
|
+
files:
|
91
|
+
- .document
|
92
|
+
- .gitignore
|
93
|
+
- LICENSE.markdown
|
94
|
+
- README.markdown
|
95
|
+
- Rakefile
|
96
|
+
- VERSION
|
97
|
+
- lib/sinatra/head.rb
|
98
|
+
- lib/sinatra/head/data_helpers.rb
|
99
|
+
- lib/sinatra/head/tag_helpers.rb
|
100
|
+
- spec/sinatra/head_spec.rb
|
101
|
+
- spec/sinatra/javascripts_spec.rb
|
102
|
+
- spec/sinatra/stylesheet_spec.rb
|
103
|
+
- spec/sinatra/title_spec.rb
|
104
|
+
- spec/spec.opts
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/support/dummy_app.rb
|
107
|
+
- spec/title_spec.rb
|
108
|
+
has_rdoc: true
|
109
|
+
homepage: http://github.com/SFEley/sinatra-head
|
110
|
+
licenses: []
|
111
|
+
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options:
|
114
|
+
- --charset=UTF-8
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
hash: 3
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
version: "0"
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
hash: 3
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
version: "0"
|
135
|
+
requirements: []
|
136
|
+
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 1.3.7
|
139
|
+
signing_key:
|
140
|
+
specification_version: 3
|
141
|
+
summary: A Sinatra extension that gets inside your <HEAD>.
|
142
|
+
test_files:
|
143
|
+
- spec/sinatra/head_spec.rb
|
144
|
+
- spec/sinatra/javascripts_spec.rb
|
145
|
+
- spec/sinatra/stylesheet_spec.rb
|
146
|
+
- spec/sinatra/title_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
148
|
+
- spec/support/dummy_app.rb
|
149
|
+
- spec/title_spec.rb
|