tributary 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.rspec +6 -0
- data/LICENCE +661 -0
- data/README.md +99 -0
- data/Rakefile +5 -0
- data/config.ru +9 -0
- data/lib/tributary/app.rb +61 -0
- data/lib/tributary/item.rb +66 -0
- data/lib/tributary/plugins/dummy.rb +7 -0
- data/lib/tributary/plugins/mnml.rb +14 -0
- data/lib/tributary/plugins/unbreak_my_art.rb +22 -0
- data/lib/tributary/stream.rb +51 -0
- data/lib/tributary.rb +8 -0
- data/spec/fixtures/index.en.en+pl.xml +50 -0
- data/spec/fixtures/index.en.en.xml +50 -0
- data/spec/fixtures/index.en.xml +50 -0
- data/spec/fixtures/index.pl.pl.xml +50 -0
- data/spec/fixtures/index.pl.xml +50 -0
- data/spec/fixtures/index.xml +50 -0
- data/spec/fixtures/layout.css +22 -0
- data/spec/fixtures/pages.css +2 -0
- data/spec/site/articles/600.en.md +5 -0
- data/spec/site/articles/600.md +5 -0
- data/spec/site/articles/bilingual.en.md +4 -0
- data/spec/site/articles/bilingual.pl.md +4 -0
- data/spec/site/articles/unix-millennium-bug.en.md +4 -0
- data/spec/site/articles/welcome.md +4 -0
- data/spec/site/beeps/beep.md +3 -0
- data/spec/site/beeps/dated.md +3 -0
- data/spec/site/beeps/english.en.md +3 -0
- data/spec/site/beeps/link.md +3 -0
- data/spec/site/beeps/polish.pl.md +3 -0
- data/spec/site/beeps/quote.md +4 -0
- data/spec/site/i18n/en.yml +12 -0
- data/spec/site/i18n/pl.yml +12 -0
- data/spec/site/pages/about.md +5 -0
- data/spec/site/views/articles.haml +4 -0
- data/spec/site/views/articles.index.haml +6 -0
- data/spec/site/views/articles.index.sass +0 -0
- data/spec/site/views/articles.sass +2 -0
- data/spec/site/views/beeps.haml +1 -0
- data/spec/site/views/beeps.sass +2 -0
- data/spec/site/views/error.haml +8 -0
- data/spec/site/views/error.sass +6 -0
- data/spec/site/views/index.haml +6 -0
- data/spec/site/views/index.sass +2 -0
- data/spec/site/views/index.xml.haml +17 -0
- data/spec/site/views/layout.haml +56 -0
- data/spec/site/views/layout.sass +22 -0
- data/spec/site/views/pages.haml +3 -0
- data/spec/site/views/pages.sass +2 -0
- data/spec/tributary/app_spec.rb +266 -0
- data/spec/tributary/item_spec.rb +129 -0
- data/spec/tributary/plugins/dummy_spec.rb +12 -0
- data/spec/tributary/plugins/mnml_spec.rb +16 -0
- data/spec/tributary/plugins/unbreak_my_art_spec.rb +36 -0
- data/spec/tributary/stream_spec.rb +155 -0
- data/tributary.gemspec +18 -0
- metadata +204 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
article {
|
2
|
+
background: white;
|
3
|
+
border: 1px dashed black;
|
4
|
+
margin: auto;
|
5
|
+
padding: 1em;
|
6
|
+
width: 30em; }
|
7
|
+
|
8
|
+
a {
|
9
|
+
color: inherit; }
|
10
|
+
|
11
|
+
body {
|
12
|
+
font-family: Georgia;
|
13
|
+
text-align: center; }
|
14
|
+
|
15
|
+
h1 {
|
16
|
+
font-variant: small-caps; }
|
17
|
+
|
18
|
+
li {
|
19
|
+
list-style: none; }
|
20
|
+
|
21
|
+
ul {
|
22
|
+
padding: 0; }
|
@@ -0,0 +1,12 @@
|
|
1
|
+
content: content
|
2
|
+
default: default
|
3
|
+
english: English
|
4
|
+
english_only: English only
|
5
|
+
language: language
|
6
|
+
no_limit: no limit
|
7
|
+
polish: Polish
|
8
|
+
polish_only: Polish only
|
9
|
+
previously: previously
|
10
|
+
published: published
|
11
|
+
recent_items: recent items
|
12
|
+
subsequently: subsequently
|
@@ -0,0 +1,12 @@
|
|
1
|
+
content: treść
|
2
|
+
default: domyślny
|
3
|
+
english: angielski
|
4
|
+
english_only: tylko angielska
|
5
|
+
language: język
|
6
|
+
no_limit: bez ograniczeń
|
7
|
+
polish: polski
|
8
|
+
polish_only: tylko polska
|
9
|
+
previously: poprzednio
|
10
|
+
published: opublikowany
|
11
|
+
recent_items: najnowsze
|
12
|
+
subsequently: następnie
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
= @item.body
|
@@ -0,0 +1,8 @@
|
|
1
|
+
%pre
|
2
|
+
:preserve
|
3
|
+
Once upon a midnight dreary, while I websurf’d, weak and weary,
|
4
|
+
Over many a strange and spurious website of ‘hot chicks galore,’
|
5
|
+
While I clicked my fav’rite darling, suddenly there came a warning,
|
6
|
+
And my heart was filled with mourning, mourning for my dear amour.
|
7
|
+
‘’Tis not possible,’ I muttered, ‘give me back my cheap hardcore!’ —
|
8
|
+
Quoth the Server, ‘<a href='http://plinko.net/board'>404</a>.’
|
@@ -0,0 +1,17 @@
|
|
1
|
+
!!! XML
|
2
|
+
%feed{xmlns: 'http://www.w3.org/2005/Atom'}
|
3
|
+
%author
|
4
|
+
%name&= settings.author
|
5
|
+
%generator{uri: 'http://github.com/chastell/tributary'} tributary
|
6
|
+
%id= "http://#{request.host}/"
|
7
|
+
%link{href: "http://#{request.host}/", rel: 'alternate'}
|
8
|
+
%link{href: "http://#{request.host}/#{escape params['feed']}.xml", rel: 'self'}
|
9
|
+
%title&= settings.sitename
|
10
|
+
%updated= @stream.recent.first.date.iso8601
|
11
|
+
- @stream.recent(5).each do |item|
|
12
|
+
%entry
|
13
|
+
%id= "http://#{request.host}/#{item.path}"
|
14
|
+
%link{href: "http://#{request.host}/#{item.path}", rel: 'alternate'}
|
15
|
+
%title&= item.title
|
16
|
+
%updated= item.date.iso8601
|
17
|
+
%content{type: 'html'}&= item.body
|
@@ -0,0 +1,56 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html{lang: @item.lang || Tributary::App.locale || 'en'}
|
3
|
+
%head
|
4
|
+
%link{href: 'index.xml', rel: 'alternate', title: 'no language preference', type: 'application/atom+xml'}
|
5
|
+
%link{href: 'index.en.xml', rel: 'alternate', title: 'English preference', type: 'application/atom+xml'}
|
6
|
+
%link{href: 'index.pl.xml', rel: 'alternate', title: 'Polish preference', type: 'application/atom+xml'}
|
7
|
+
%link{href: 'index.en.en.xml', rel: 'alternate', title: 'English-only content', type: 'application/atom+xml'}
|
8
|
+
%link{href: 'index.pl.pl.xml', rel: 'alternate', title: 'Polish-only content', type: 'application/atom+xml'}
|
9
|
+
%link{href: 'layout.css', rel: 'stylesheet'}
|
10
|
+
%link{href: "#{@item.type}.css", rel: 'stylesheet'}
|
11
|
+
%meta{charset: 'UTF-8'}
|
12
|
+
%title= @item.title or settings.sitename + "#{": #{@item.path}" if @item.path}"
|
13
|
+
%body
|
14
|
+
%h1
|
15
|
+
%a{href: '/'}= settings.sitename
|
16
|
+
%article
|
17
|
+
= yield
|
18
|
+
%nav
|
19
|
+
%p
|
20
|
+
- previous = @stream.previous(@item)
|
21
|
+
- subsequent = @stream.subsequent(@item)
|
22
|
+
- if previous
|
23
|
+
#{t.previously}:
|
24
|
+
%a{href: previous.path}= previous.title
|
25
|
+
- if previous and subsequent
|
26
|
+
\/
|
27
|
+
- if subsequent
|
28
|
+
#{t.subsequently}:
|
29
|
+
%a{href: subsequent.path}= subsequent.title
|
30
|
+
%footer
|
31
|
+
%p
|
32
|
+
#{t.language}:
|
33
|
+
- {'en' => t.english, 'pl' => t.polish}.each do |lang, name|
|
34
|
+
- if settings.locale == lang
|
35
|
+
= name
|
36
|
+
- else
|
37
|
+
%a{href: "/set?locale=#{lang}"}= name
|
38
|
+
|
|
39
|
+
- if settings.locale.nil?
|
40
|
+
= t.default
|
41
|
+
- else
|
42
|
+
%a{href: '/set?locale'}= t.default
|
43
|
+
%p
|
44
|
+
#{t.content}:
|
45
|
+
- {'en' => t.english_only, 'pl' => t.polish_only}.each do |lang, name|
|
46
|
+
- if settings.lang_limit == [lang]
|
47
|
+
= name
|
48
|
+
- else
|
49
|
+
%a{href: "/set?lang_limit=#{lang}"}= name
|
50
|
+
|
|
51
|
+
- if settings.lang_limit.nil?
|
52
|
+
= t.no_limit
|
53
|
+
- else
|
54
|
+
%a{href: '/set?lang_limit'}= t.no_limit
|
55
|
+
%p
|
56
|
+
%a{href: 'about'} designed by chastell in Mazovia
|
@@ -0,0 +1,22 @@
|
|
1
|
+
article
|
2
|
+
background: white
|
3
|
+
border: 1px dashed black
|
4
|
+
margin: auto
|
5
|
+
padding: 1em
|
6
|
+
width: 30em
|
7
|
+
|
8
|
+
a
|
9
|
+
color: inherit
|
10
|
+
|
11
|
+
body
|
12
|
+
font-family: Georgia
|
13
|
+
text-align: center
|
14
|
+
|
15
|
+
h1
|
16
|
+
font-variant: small-caps
|
17
|
+
|
18
|
+
li
|
19
|
+
list-style: none
|
20
|
+
|
21
|
+
ul
|
22
|
+
padding: 0
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Tributary describe App do
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
App
|
9
|
+
end
|
10
|
+
|
11
|
+
def session
|
12
|
+
Marshal.load rack_test_session.instance_variable_get(:@rack_mock_session).cookie_jar['rack.session'].unpack('m*').first
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
App.configure do |config|
|
17
|
+
config.set :author, 'Ary Tribut'
|
18
|
+
config.set :root, 'spec/site'
|
19
|
+
config.set :sitename, 'a tributary site'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'rendering content' do
|
24
|
+
|
25
|
+
it 'renders the index view when no path given' do
|
26
|
+
get '/'
|
27
|
+
last_response.should be_ok
|
28
|
+
last_response.body.should include 'a tributary index'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'renders the given view’s index' do
|
32
|
+
get '/articles'
|
33
|
+
last_response.should be_ok
|
34
|
+
last_response.body.should include 'welcome to tributary'
|
35
|
+
last_response.body.should_not include 'a…'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'renders the relevant, path-based view' do
|
39
|
+
get '/about'
|
40
|
+
last_response.should be_ok
|
41
|
+
last_response.body.should include 'a tributary page'
|
42
|
+
last_response.body.should include 'tributary <em>about</em> page'
|
43
|
+
|
44
|
+
get '/welcome'
|
45
|
+
last_response.should be_ok
|
46
|
+
last_response.body.should include 'a tributary article'
|
47
|
+
last_response.body.should include 'tributary <em>welcome</em> article'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns HTTP 404 Not Found on missing items and renders the error template' do
|
51
|
+
get '/foo'
|
52
|
+
last_response.should_not be_ok
|
53
|
+
last_response.status.should == 404
|
54
|
+
last_response.body.should include 'Quoth the Server'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns HTTP 404 Not Found on missing feeds and stylesheets and does not return the error template' do
|
58
|
+
get '/foo.xml'
|
59
|
+
last_response.should_not be_ok
|
60
|
+
last_response.status.should == 404
|
61
|
+
last_response.body.should be_empty
|
62
|
+
|
63
|
+
get '/foo.css'
|
64
|
+
last_response.should_not be_ok
|
65
|
+
last_response.status.should == 404
|
66
|
+
last_response.body.should be_empty
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'view settings' do
|
72
|
+
|
73
|
+
it 'sets @item.path in the views’ indices' do
|
74
|
+
get '/articles'
|
75
|
+
last_response.should be_ok
|
76
|
+
last_response.body.should include '<title>a tributary site: articles</title>'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'sets /’s view to :index' do
|
80
|
+
get '/'
|
81
|
+
last_response.should be_ok
|
82
|
+
last_response.body.should include 'index.css'
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'exposes settings to views' do
|
86
|
+
get '/'
|
87
|
+
last_response.should be_ok
|
88
|
+
last_response.body.should include '<title>a tributary site</title>'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'exposes Stream to views' do
|
92
|
+
get '/'
|
93
|
+
last_response.should be_ok
|
94
|
+
last_response.body.should include 'welcome to tributary'
|
95
|
+
|
96
|
+
get '/600'
|
97
|
+
last_response.should be_ok
|
98
|
+
last_response.body.should include 'bilinguality'
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'feeds' do
|
104
|
+
|
105
|
+
it 'renders the Atom feed' do
|
106
|
+
get '/index.xml'
|
107
|
+
last_response.should be_ok
|
108
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
109
|
+
last_response.body.should == File.read('spec/fixtures/index.xml')
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'renders per-locale Atom feeds' do
|
113
|
+
get '/index.en.xml'
|
114
|
+
last_response.should be_ok
|
115
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
116
|
+
last_response.body.should == File.read('spec/fixtures/index.en.xml')
|
117
|
+
|
118
|
+
get '/index.pl.xml'
|
119
|
+
last_response.should be_ok
|
120
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
121
|
+
last_response.body.should == File.read('spec/fixtures/index.pl.xml')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'renders lang_limit-ed Atom feeds' do
|
125
|
+
get '/index.en.en.xml'
|
126
|
+
last_response.should be_ok
|
127
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
128
|
+
last_response.body.should == File.read('spec/fixtures/index.en.en.xml')
|
129
|
+
|
130
|
+
get '/index.pl.pl.xml'
|
131
|
+
last_response.should be_ok
|
132
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
133
|
+
last_response.body.should == File.read('spec/fixtures/index.pl.pl.xml')
|
134
|
+
|
135
|
+
get '/index.en.en+pl.xml'
|
136
|
+
last_response.should be_ok
|
137
|
+
last_response.headers['Content-Type'].should == 'application/atom+xml;charset=utf-8'
|
138
|
+
last_response.body.should == File.read('spec/fixtures/index.en.en+pl.xml')
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'stylesheets' do
|
144
|
+
|
145
|
+
it 'renders the CSS stylesheet' do
|
146
|
+
get '/layout.css'
|
147
|
+
last_response.should be_ok
|
148
|
+
last_response.headers['Content-Type'].should == 'text/css;charset=utf-8'
|
149
|
+
last_response.body.should == File.read('spec/fixtures/layout.css')
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'renders per-view CSS stylesheets' do
|
153
|
+
get '/pages.css'
|
154
|
+
last_response.should be_ok
|
155
|
+
last_response.headers['Content-Type'].should == 'text/css;charset=utf-8'
|
156
|
+
last_response.body.should == File.read('spec/fixtures/pages.css')
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'localisation and multilinguality' do
|
162
|
+
|
163
|
+
it 'defaults to nil locale and lang_limit' do
|
164
|
+
App.locale.should == nil
|
165
|
+
App.lang_limit.should == nil
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'sets the right App settings and redirects properly' do
|
169
|
+
get '/set?locale=pl', {}, 'HTTP_REFERER' => '/bilingual'
|
170
|
+
last_response.location.should == 'http://example.org/bilingual'
|
171
|
+
follow_redirect!
|
172
|
+
App.locale.should == 'pl'
|
173
|
+
last_response.should be_ok
|
174
|
+
last_response.body.should include '<title>dwujęzyczność</title>'
|
175
|
+
|
176
|
+
get '/set?lang_limit=pl'
|
177
|
+
follow_redirect!
|
178
|
+
App.lang_limit.should == ['pl']
|
179
|
+
last_response.should be_ok
|
180
|
+
last_response.body.should_not include '600th anniversary (English)'
|
181
|
+
|
182
|
+
get '/set?locale'
|
183
|
+
follow_redirect!
|
184
|
+
App.locale.should == nil
|
185
|
+
|
186
|
+
get '/set?lang_limit'
|
187
|
+
follow_redirect!
|
188
|
+
App.lang_limit.should == nil
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'localises the output based on locale (defaulting to English)' do
|
192
|
+
get '/set?locale=pl'
|
193
|
+
get '/bilingual'
|
194
|
+
last_response.should be_ok
|
195
|
+
last_response.body.should include 'opublikowany 15 lipca 2010'
|
196
|
+
|
197
|
+
get '/set?locale=en'
|
198
|
+
get '/bilingual'
|
199
|
+
last_response.should be_ok
|
200
|
+
last_response.body.should include 'published 15th of July, 2010'
|
201
|
+
|
202
|
+
get '/set?locale'
|
203
|
+
get '/bilingual'
|
204
|
+
last_response.should be_ok
|
205
|
+
last_response.body.should include 'published 15th of July, 2010'
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'sets the right value for the <html> element’s lang attribute' do
|
209
|
+
get '/set?locale=en'
|
210
|
+
get '/'
|
211
|
+
last_response.should be_ok
|
212
|
+
last_response.body.should include "<html lang='en'>"
|
213
|
+
|
214
|
+
get '/set?locale=pl'
|
215
|
+
get '/'
|
216
|
+
last_response.should be_ok
|
217
|
+
last_response.body.should include "<html lang='pl'>"
|
218
|
+
|
219
|
+
get '/set?locale'
|
220
|
+
get '/'
|
221
|
+
last_response.should be_ok
|
222
|
+
last_response.body.should include "<html lang='en'>"
|
223
|
+
|
224
|
+
get '/set?locale=en'
|
225
|
+
get '/bilingual.pl'
|
226
|
+
last_response.should be_ok
|
227
|
+
last_response.body.should include "<html lang='pl'>"
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'configuration' do
|
233
|
+
|
234
|
+
it 'has proper defaults' do
|
235
|
+
App.cache?.should be_false
|
236
|
+
App.lang_limit.should be_nil
|
237
|
+
App.locale.should be_nil
|
238
|
+
App.plugins.should be_empty
|
239
|
+
App.user_prefs.should == [:lang_limit, :locale]
|
240
|
+
App.stream.should be_nil
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'sets only whitelisted settings' do
|
244
|
+
get '/set?foo=bar&locale=en'
|
245
|
+
get '/'
|
246
|
+
session.should have_key :locale
|
247
|
+
session.should_not have_key :foo
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'stream caching' do
|
253
|
+
|
254
|
+
it 'caches the Stream in production by default' do
|
255
|
+
App.stub production?: true
|
256
|
+
App.configure {}
|
257
|
+
App.stream.should be_a Stream
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'does not cache the Stream in development/testing by default' do
|
261
|
+
App.stream.should be_nil
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end end
|