mars-nesta 0.9.4

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