nesta 0.9.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.
- data/.gitignore +13 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +58 -0
- data/LICENSE +19 -0
- data/README.md +45 -0
- data/Rakefile +12 -0
- data/bin/nesta +67 -0
- data/config.ru +9 -0
- data/config/config.yml.sample +73 -0
- data/config/deploy.rb.sample +62 -0
- data/lib/nesta/app.rb +199 -0
- data/lib/nesta/cache.rb +139 -0
- data/lib/nesta/commands.rb +135 -0
- data/lib/nesta/config.rb +87 -0
- data/lib/nesta/models.rb +313 -0
- data/lib/nesta/nesta.rb +0 -0
- data/lib/nesta/overrides.rb +59 -0
- data/lib/nesta/path.rb +11 -0
- data/lib/nesta/plugins.rb +15 -0
- data/lib/nesta/version.rb +3 -0
- data/nesta.gemspec +49 -0
- data/scripts/import-from-mephisto +207 -0
- data/spec/atom_spec.rb +138 -0
- data/spec/commands_spec.rb +220 -0
- data/spec/config_spec.rb +69 -0
- data/spec/model_factory.rb +94 -0
- data/spec/models_spec.rb +445 -0
- data/spec/overrides_spec.rb +113 -0
- data/spec/page_spec.rb +428 -0
- data/spec/path_spec.rb +28 -0
- data/spec/sitemap_spec.rb +102 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +72 -0
- data/templates/Gemfile +8 -0
- data/templates/Rakefile +35 -0
- data/templates/config.ru +9 -0
- data/templates/config/config.yml +73 -0
- data/templates/config/deploy.rb +47 -0
- data/views/analytics.haml +12 -0
- data/views/atom.builder +28 -0
- data/views/categories.haml +3 -0
- data/views/comments.haml +8 -0
- data/views/error.haml +13 -0
- data/views/feed.haml +3 -0
- data/views/index.haml +5 -0
- data/views/layout.haml +27 -0
- data/views/master.sass +246 -0
- data/views/not_found.haml +13 -0
- data/views/page.haml +29 -0
- data/views/sidebar.haml +3 -0
- data/views/sitemap.builder +15 -0
- data/views/summaries.haml +14 -0
- metadata +302 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('model_factory', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe "Rendering" do
|
5
|
+
include ConfigSpecHelper
|
6
|
+
include ModelFactory
|
7
|
+
include RequestSpecHelper
|
8
|
+
|
9
|
+
def create_fixture(type, name, content)
|
10
|
+
base_path = {
|
11
|
+
:local => Nesta::Path.local,
|
12
|
+
:theme => Nesta::Path.themes(@theme)
|
13
|
+
}[type]
|
14
|
+
path = File.join(base_path, name)
|
15
|
+
@fixtures << path
|
16
|
+
FileUtils.mkdir_p(File.dirname(path))
|
17
|
+
open(path, 'w') { |file| file.write(content) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_template(type, name, content)
|
21
|
+
create_fixture(type, File.join('views', name), content)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_app_file(type)
|
25
|
+
create_fixture(type, 'app.rb', "DEFINED_IN_#{type.to_s.upcase}_FILE = true")
|
26
|
+
end
|
27
|
+
|
28
|
+
before(:each) do
|
29
|
+
@app_root = Nesta::App.root
|
30
|
+
Nesta::App.root = File.expand_path('fixtures/tmp', File.dirname(__FILE__))
|
31
|
+
@theme = 'my-theme'
|
32
|
+
@fixtures = []
|
33
|
+
stub_configuration
|
34
|
+
end
|
35
|
+
|
36
|
+
after(:each) do
|
37
|
+
@fixtures.each { |path| FileUtils.rm(path) if File.exist?(path) }
|
38
|
+
Nesta::App.root = @app_root
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "when local files exist" do
|
42
|
+
before(:each) do
|
43
|
+
create_template(:local, 'page.haml', '%p Local template')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should use local application files" do
|
47
|
+
create_app_file(:local)
|
48
|
+
Nesta::Overrides.load_local_app
|
49
|
+
Object.const_get(:DEFINED_IN_LOCAL_FILE).should be_true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use local template in place of default" do
|
53
|
+
get create_category.abspath
|
54
|
+
body.should have_tag("p", "Local template")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "when theme installed" do
|
59
|
+
before(:each) do
|
60
|
+
create_template(:theme, 'page.haml', '%p Theme template')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not require theme application file automatically" do
|
64
|
+
create_app_file(:theme)
|
65
|
+
lambda {
|
66
|
+
Object.const_get(:DEFINED_IN_THEME_FILE)
|
67
|
+
}.should raise_error(NameError)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should not use theme templates automatically" do
|
71
|
+
get create_category.abspath
|
72
|
+
body.should_not have_tag("p", "Theme template")
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "and configured" do
|
76
|
+
before(:each) do
|
77
|
+
stub_config_key("theme", @theme)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should require theme application file" do
|
81
|
+
create_app_file(:theme)
|
82
|
+
Nesta::Overrides.load_theme_app
|
83
|
+
Object.const_get(:DEFINED_IN_THEME_FILE).should be_true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should use theme's template in place of default" do
|
87
|
+
get create_category.abspath
|
88
|
+
body.should have_tag("p", "Theme template")
|
89
|
+
end
|
90
|
+
|
91
|
+
context "and local files exist" do
|
92
|
+
before(:each) do
|
93
|
+
create_template(:local, "page.haml", "%p Local template")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should require local and theme application files" do
|
97
|
+
create_app_file(:local)
|
98
|
+
create_app_file(:theme)
|
99
|
+
Nesta::Overrides.load_theme_app
|
100
|
+
Nesta::Overrides.load_local_app
|
101
|
+
Object.const_get(:DEFINED_IN_LOCAL_FILE).should be_true
|
102
|
+
Object.const_get(:DEFINED_IN_THEME_FILE).should be_true
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should use local template" do
|
106
|
+
get create_category.abspath
|
107
|
+
body.should_not have_tag("p", "Theme template")
|
108
|
+
body.should have_tag("p", "Local template")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/spec/page_spec.rb
ADDED
@@ -0,0 +1,428 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('model_factory', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe "page with keyword and description", :shared => true do
|
5
|
+
it "should set the keywords meta tag" do
|
6
|
+
do_get
|
7
|
+
body.should have_tag("meta[@name=keywords][@content='#{@keywords}']")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should set description meta tag" do
|
11
|
+
do_get
|
12
|
+
body.should have_tag("meta[@name=description][@content='#{@description}']")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "page that can display menus", :shared => true do
|
17
|
+
it "should not display menu by default" do
|
18
|
+
do_get
|
19
|
+
body.should_not have_tag("#sidebar ul.menu")
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "and simple menu configured" do
|
23
|
+
before(:each) do
|
24
|
+
create_menu(@category.path)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should link to top level menu items" do
|
28
|
+
do_get
|
29
|
+
body.should have_tag(
|
30
|
+
"ul.menu a[@href=#{@category.abspath}]", Regexp.new(@category.heading))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "and nested menu configured" do
|
35
|
+
before(:each) do
|
36
|
+
@level2 = create_category(:path => "level-2", :heading => "Level 2")
|
37
|
+
@level3 = create_category(:path => "level-3", :heading => "Level 3")
|
38
|
+
text = <<-EOF
|
39
|
+
#{@category.abspath}
|
40
|
+
#{@level2.abspath}
|
41
|
+
#{@level3.abspath}
|
42
|
+
EOF
|
43
|
+
create_menu(text)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should display first level of nested sub menus" do
|
47
|
+
do_get
|
48
|
+
body.should have_tag("ul.menu li ul li a", Regexp.new(@level2.heading))
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not display nested menus to arbitrary depth" do
|
52
|
+
do_get
|
53
|
+
body.should_not have_tag("ul.menu li ul li ul")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "The layout" do
|
59
|
+
include ConfigSpecHelper
|
60
|
+
include ModelFactory
|
61
|
+
include RequestSpecHelper
|
62
|
+
|
63
|
+
it "should not include GA JavaScript by default" do
|
64
|
+
stub_configuration
|
65
|
+
get "/"
|
66
|
+
body.should_not have_tag("script", /'_setAccount', 'UA-1234'/)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should include GA JavaScript if configured" do
|
70
|
+
stub_config_key('google_analytics_code', 'UA-1234', :rack_env => true)
|
71
|
+
stub_configuration
|
72
|
+
get '/'
|
73
|
+
body.should have_tag('script', /'_setAccount', 'UA-1234'/)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "The home page" do
|
78
|
+
include ConfigSpecHelper
|
79
|
+
include ModelFactory
|
80
|
+
include RequestSpecHelper
|
81
|
+
|
82
|
+
before(:each) do
|
83
|
+
stub_configuration
|
84
|
+
create_category
|
85
|
+
end
|
86
|
+
|
87
|
+
after(:each) do
|
88
|
+
remove_fixtures
|
89
|
+
Nesta::FileModel.purge_cache
|
90
|
+
end
|
91
|
+
|
92
|
+
def do_get
|
93
|
+
get "/"
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "when categories exist" do
|
97
|
+
before(:each) do
|
98
|
+
@category = create_category
|
99
|
+
end
|
100
|
+
|
101
|
+
it_should_behave_like "page that can display menus"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should render successfully" do
|
105
|
+
do_get
|
106
|
+
last_response.should be_ok
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should display title and subtitle in title tag" do
|
110
|
+
do_get
|
111
|
+
body.should have_tag("title", "My blog - about stuff")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should display site title in h1 tag" do
|
115
|
+
do_get
|
116
|
+
body.should have_tag('#header p.title', /My blog/)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should display site subtitle in h1 tag" do
|
120
|
+
do_get
|
121
|
+
body.should have_tag('#header p.subtitle', /about stuff/)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should set description meta tag" do
|
125
|
+
do_get
|
126
|
+
body.should have_tag("meta[@name=description][@content='great web site']")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should set keywords meta tag" do
|
130
|
+
do_get
|
131
|
+
body.should have_tag("meta[@name=keywords][@content='home, page']")
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "when articles have no summary" do
|
135
|
+
before(:each) do
|
136
|
+
create_article
|
137
|
+
do_get
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should display full content of article" do
|
141
|
+
body.should have_tag("p", "Content goes here")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not display read more link" do
|
145
|
+
body.should_not have_tag("a", /continue/i)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "when articles have metadata" do
|
150
|
+
before(:each) do
|
151
|
+
@summary = 'Multiline\n\nsummary'
|
152
|
+
@read_more = "Continue at your leisure"
|
153
|
+
@article = create_article(:metadata => {
|
154
|
+
"summary" => @summary,
|
155
|
+
"read more" => @read_more
|
156
|
+
})
|
157
|
+
do_get
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should display link to article in h2 tag" do
|
161
|
+
body.should have_tag(
|
162
|
+
"h2 a[@href=#{@article.abspath}]", /^\s*#{@article.heading}$/)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should display article summary if available" do
|
166
|
+
body.should have_tag("p", @summary.split('\n\n').first)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should display read more link" do
|
170
|
+
body.should have_tag("a[@href=#{@article.abspath}]", @read_more)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "An article" do
|
176
|
+
include ConfigSpecHelper
|
177
|
+
include ModelFactory
|
178
|
+
include RequestSpecHelper
|
179
|
+
|
180
|
+
before(:each) do
|
181
|
+
stub_configuration
|
182
|
+
@date = "07 September 2009"
|
183
|
+
@keywords = "things, stuff"
|
184
|
+
@description = "Page about stuff"
|
185
|
+
@summary = 'Multiline\n\nsummary'
|
186
|
+
@article = create_article(:metadata => {
|
187
|
+
"date" => @date.gsub("September", "Sep"),
|
188
|
+
"description" => @description,
|
189
|
+
"keywords" => @keywords,
|
190
|
+
"summary" => @summary,
|
191
|
+
})
|
192
|
+
end
|
193
|
+
|
194
|
+
after(:each) do
|
195
|
+
remove_fixtures
|
196
|
+
Nesta::FileModel.purge_cache
|
197
|
+
end
|
198
|
+
|
199
|
+
def do_get
|
200
|
+
get @article.abspath
|
201
|
+
end
|
202
|
+
|
203
|
+
it_should_behave_like "page with keyword and description"
|
204
|
+
|
205
|
+
describe "when categories exist" do
|
206
|
+
before(:each) do
|
207
|
+
@category = create_category
|
208
|
+
end
|
209
|
+
|
210
|
+
it_should_behave_like "page that can display menus"
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should render successfully" do
|
214
|
+
do_get
|
215
|
+
last_response.should be_ok
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should display the heading" do
|
219
|
+
do_get
|
220
|
+
body.should have_tag("h1", "My article")
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should not display category links" do
|
224
|
+
do_get
|
225
|
+
body.should_not have_tag("div.breadcrumb div.categories", /filed in/)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should display the date" do
|
229
|
+
do_get
|
230
|
+
body.should have_tag("div.date", @date)
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should display the content" do
|
234
|
+
do_get
|
235
|
+
body.should have_tag("p", "Content goes here")
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "that is assigned to categories" do
|
239
|
+
before(:each) do
|
240
|
+
create_category(:heading => "Apple", :path => "the-apple")
|
241
|
+
@category = create_category(:heading => "Banana", :path => "banana")
|
242
|
+
@article = create_article(
|
243
|
+
:path => "#{@category.path}/article",
|
244
|
+
:metadata => { "categories" => "banana, the-apple" }
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should render successfully" do
|
249
|
+
do_get
|
250
|
+
last_response.should be_ok
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should link to each category" do
|
254
|
+
do_get
|
255
|
+
body.should have_tag("div.categories", /Categories/)
|
256
|
+
body.should have_tag("div.categories") do |categories|
|
257
|
+
categories.should have_tag("a[@href=/banana]", "Banana")
|
258
|
+
categories.should have_tag("a[@href=/the-apple]", "Apple")
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should link to a category in breadcrumb" do
|
263
|
+
do_get
|
264
|
+
body.should have_tag(
|
265
|
+
"div.breadcrumb/a[@href=#{@category.abspath}]", @category.heading)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should contain category name in page title" do
|
269
|
+
do_get
|
270
|
+
body.should_not have_tag("title", /My blog/)
|
271
|
+
body.should have_tag("title", /- #{@category.heading}$/)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "A page" do
|
277
|
+
include ConfigSpecHelper
|
278
|
+
include ModelFactory
|
279
|
+
include RequestSpecHelper
|
280
|
+
|
281
|
+
before(:each) do
|
282
|
+
stub_configuration
|
283
|
+
end
|
284
|
+
|
285
|
+
after(:each) do
|
286
|
+
remove_fixtures
|
287
|
+
Nesta::FileModel.purge_cache
|
288
|
+
end
|
289
|
+
|
290
|
+
def do_get
|
291
|
+
get @category.abspath
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "that doesn't exist" do
|
295
|
+
it "should render the 404 page" do
|
296
|
+
get "/no-such-page"
|
297
|
+
last_response.should_not be_ok
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
describe "that has meta data" do
|
302
|
+
before(:each) do
|
303
|
+
@content = "Page content"
|
304
|
+
@description = "Page about stuff"
|
305
|
+
@keywords = "things, stuff"
|
306
|
+
@category = create_category(
|
307
|
+
:content => "# My category\n\n#{@content}",
|
308
|
+
:metadata => { "description" => @description, "keywords" => @keywords }
|
309
|
+
)
|
310
|
+
end
|
311
|
+
|
312
|
+
it_should_behave_like "page with keyword and description"
|
313
|
+
it_should_behave_like "page that can display menus"
|
314
|
+
|
315
|
+
it "should render successfully" do
|
316
|
+
do_get
|
317
|
+
last_response.should be_ok
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should display the heading" do
|
321
|
+
do_get
|
322
|
+
body.should have_tag("h1", @category.heading)
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should display the content" do
|
326
|
+
do_get
|
327
|
+
body.should have_tag("p", @content)
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "with associated articles" do
|
331
|
+
before(:each) do
|
332
|
+
@article = create_article(
|
333
|
+
:path => "another-page",
|
334
|
+
:heading => "Categorised",
|
335
|
+
:metadata => { :categories => @category.path },
|
336
|
+
:content => "Article content"
|
337
|
+
)
|
338
|
+
@article2 = create_article(
|
339
|
+
:path => "second-article", :heading => "Second article")
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should display links to articles" do
|
343
|
+
do_get
|
344
|
+
body.should have_tag(
|
345
|
+
"h3 a[@href='#{@article.abspath}']", /^\s*#{@article.heading}$/)
|
346
|
+
body.should_not have_tag("h3", @article2.heading)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should not include Disqus comments by default" do
|
351
|
+
do_get
|
352
|
+
body.should_not have_tag('#disqus_thread')
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe "that is configured to show Disqus comments" do
|
357
|
+
before(:each) do
|
358
|
+
stub_config_key("disqus_short_name", "mysite")
|
359
|
+
@category = create_category
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should display Disqus comments" do
|
363
|
+
do_get
|
364
|
+
body.should have_tag('#disqus_thread')
|
365
|
+
body.should have_tag('script[@src*="mysite/embed.js"]')
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
describe "A Haml page" do
|
371
|
+
include ConfigSpecHelper
|
372
|
+
include ModelFactory
|
373
|
+
include RequestSpecHelper
|
374
|
+
|
375
|
+
before(:each) do
|
376
|
+
stub_configuration
|
377
|
+
end
|
378
|
+
|
379
|
+
after(:each) do
|
380
|
+
remove_fixtures
|
381
|
+
Nesta::FileModel.purge_cache
|
382
|
+
end
|
383
|
+
|
384
|
+
it "should be able to access helper methods" do
|
385
|
+
create_page(
|
386
|
+
:path => "a-page",
|
387
|
+
:ext => :haml,
|
388
|
+
:content => "%div= format_date(Date.new(2010, 11, 23))"
|
389
|
+
)
|
390
|
+
get "/a-page"
|
391
|
+
body.should have_tag("div", "23 November 2010")
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
describe "attachments" do
|
396
|
+
include ConfigSpecHelper
|
397
|
+
include ModelFactory
|
398
|
+
include RequestSpecHelper
|
399
|
+
|
400
|
+
def create_attachment
|
401
|
+
stub_configuration
|
402
|
+
create_content_directories
|
403
|
+
path = File.join(Nesta::Config.attachment_path, "test.txt")
|
404
|
+
File.open(path, "w") { |file| file.write("I'm a test attachment") }
|
405
|
+
end
|
406
|
+
|
407
|
+
before(:each) do
|
408
|
+
create_attachment
|
409
|
+
get "/attachments/test.txt"
|
410
|
+
end
|
411
|
+
|
412
|
+
after(:each) do
|
413
|
+
remove_fixtures
|
414
|
+
Nesta::FileModel.purge_cache
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should be served successfully" do
|
418
|
+
last_response.should be_ok
|
419
|
+
end
|
420
|
+
|
421
|
+
it "should be sent to the client" do
|
422
|
+
body.should include("I'm a test attachment")
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should set the appropriate MIME type" do
|
426
|
+
last_response.headers["Content-Type"].should =~ Regexp.new("^text/plain")
|
427
|
+
end
|
428
|
+
end
|