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.
Files changed (59) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +6 -0
  3. data/LICENCE +661 -0
  4. data/README.md +99 -0
  5. data/Rakefile +5 -0
  6. data/config.ru +9 -0
  7. data/lib/tributary/app.rb +61 -0
  8. data/lib/tributary/item.rb +66 -0
  9. data/lib/tributary/plugins/dummy.rb +7 -0
  10. data/lib/tributary/plugins/mnml.rb +14 -0
  11. data/lib/tributary/plugins/unbreak_my_art.rb +22 -0
  12. data/lib/tributary/stream.rb +51 -0
  13. data/lib/tributary.rb +8 -0
  14. data/spec/fixtures/index.en.en+pl.xml +50 -0
  15. data/spec/fixtures/index.en.en.xml +50 -0
  16. data/spec/fixtures/index.en.xml +50 -0
  17. data/spec/fixtures/index.pl.pl.xml +50 -0
  18. data/spec/fixtures/index.pl.xml +50 -0
  19. data/spec/fixtures/index.xml +50 -0
  20. data/spec/fixtures/layout.css +22 -0
  21. data/spec/fixtures/pages.css +2 -0
  22. data/spec/site/articles/600.en.md +5 -0
  23. data/spec/site/articles/600.md +5 -0
  24. data/spec/site/articles/bilingual.en.md +4 -0
  25. data/spec/site/articles/bilingual.pl.md +4 -0
  26. data/spec/site/articles/unix-millennium-bug.en.md +4 -0
  27. data/spec/site/articles/welcome.md +4 -0
  28. data/spec/site/beeps/beep.md +3 -0
  29. data/spec/site/beeps/dated.md +3 -0
  30. data/spec/site/beeps/english.en.md +3 -0
  31. data/spec/site/beeps/link.md +3 -0
  32. data/spec/site/beeps/polish.pl.md +3 -0
  33. data/spec/site/beeps/quote.md +4 -0
  34. data/spec/site/i18n/en.yml +12 -0
  35. data/spec/site/i18n/pl.yml +12 -0
  36. data/spec/site/pages/about.md +5 -0
  37. data/spec/site/views/articles.haml +4 -0
  38. data/spec/site/views/articles.index.haml +6 -0
  39. data/spec/site/views/articles.index.sass +0 -0
  40. data/spec/site/views/articles.sass +2 -0
  41. data/spec/site/views/beeps.haml +1 -0
  42. data/spec/site/views/beeps.sass +2 -0
  43. data/spec/site/views/error.haml +8 -0
  44. data/spec/site/views/error.sass +6 -0
  45. data/spec/site/views/index.haml +6 -0
  46. data/spec/site/views/index.sass +2 -0
  47. data/spec/site/views/index.xml.haml +17 -0
  48. data/spec/site/views/layout.haml +56 -0
  49. data/spec/site/views/layout.sass +22 -0
  50. data/spec/site/views/pages.haml +3 -0
  51. data/spec/site/views/pages.sass +2 -0
  52. data/spec/tributary/app_spec.rb +266 -0
  53. data/spec/tributary/item_spec.rb +129 -0
  54. data/spec/tributary/plugins/dummy_spec.rb +12 -0
  55. data/spec/tributary/plugins/mnml_spec.rb +16 -0
  56. data/spec/tributary/plugins/unbreak_my_art_spec.rb +36 -0
  57. data/spec/tributary/stream_spec.rb +155 -0
  58. data/tributary.gemspec +18 -0
  59. 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,2 @@
1
+ body {
2
+ background-color: whitesmoke; }
@@ -0,0 +1,5 @@
1
+ date: July 15th, 2010, 12 pm
2
+ title: 600th anniversary (English)
3
+
4
+ 600 years ago [something supposedly important](http://en.wikipedia.org/wiki/Battle_of_Grunwald)
5
+ happened around these parts of the world
@@ -0,0 +1,5 @@
1
+ date: July 15th, 2010, 12 pm
2
+ title: 600th anniversary (intl.)
3
+
4
+ 600 years ago [something supposedly important](http://en.wikipedia.org/wiki/Battle_of_Grunwald)
5
+ happened around these parts of the world
@@ -0,0 +1,4 @@
1
+ date: July 15th, 2010, 6 am
2
+ title: bilinguality
3
+
4
+ this article is also available [in Polish](bilingual.pl)
@@ -0,0 +1,4 @@
1
+ date: July 15th, 2010, 6 am
2
+ title: dwujęzyczność
3
+
4
+ ten wpis jest także dostępny [po angielsku](bilingual.en)
@@ -0,0 +1,4 @@
1
+ date: 2038-01-19T03:14:07Z
2
+ title: Unix Millennium Bug
3
+
4
+ in a second some things won’t be like others
@@ -0,0 +1,4 @@
1
+ date: 2010-07-15
2
+ title: welcome to tributary
3
+
4
+ tributary _welcome_ article
@@ -0,0 +1,3 @@
1
+
2
+
3
+ beep is a short, potentially YAML-less note
@@ -0,0 +1,3 @@
1
+ date: July 15th, 2010, 3 am
2
+
3
+ a dated beep.
@@ -0,0 +1,3 @@
1
+ date: July 23rd, 2010, 1 am
2
+
3
+ this beep is only in English.
@@ -0,0 +1,3 @@
1
+
2
+
3
+ [¿Qué es un link?](http://po-ru.com/) at the start of a beep.
@@ -0,0 +1,3 @@
1
+ date: July 23rd, 2010, 2 am
2
+
3
+ ten beep jest tylko po polsku.
@@ -0,0 +1,4 @@
1
+
2
+
3
+ > An interesting blockquote
4
+ in a beep.
@@ -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
@@ -0,0 +1,5 @@
1
+ title: about tributary
2
+
3
+ tributary _about_ page
4
+
5
+ about this tributary install
@@ -0,0 +1,4 @@
1
+ %p a tributary article
2
+ %h1= @item.title
3
+ %p #{t.published} #{l @item.date.to_date, :full}
4
+ = @item.body
@@ -0,0 +1,6 @@
1
+ %p a tributary index of articles
2
+ %p recent articles:
3
+ %ul
4
+ - @stream.recent(nil, type: :articles).each do |item|
5
+ %li
6
+ %a{href: item.path}= item.title
File without changes
@@ -0,0 +1,2 @@
1
+ body
2
+ background-color: silver
@@ -0,0 +1 @@
1
+ = @item.body
@@ -0,0 +1,2 @@
1
+ body
2
+ background-color: lightgrey
@@ -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,6 @@
1
+ article
2
+ text-align: left
3
+ width: 31em
4
+
5
+ pre
6
+ font-family: Georgia, serif
@@ -0,0 +1,6 @@
1
+ %h2 a tributary index
2
+ %p #{t.recent_items}:
3
+ %ul
4
+ - @stream.recent.each do |item|
5
+ %li
6
+ %a{href: item.path}= item.title
@@ -0,0 +1,2 @@
1
+ body
2
+ background-color: gainsboro
@@ -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,3 @@
1
+ %p a tributary page
2
+ %h1= @item.title
3
+ = @item.body
@@ -0,0 +1,2 @@
1
+ body
2
+ background-color: whitesmoke
@@ -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