nesta 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +58 -0
  4. data/LICENSE +19 -0
  5. data/README.md +45 -0
  6. data/Rakefile +12 -0
  7. data/bin/nesta +67 -0
  8. data/config.ru +9 -0
  9. data/config/config.yml.sample +73 -0
  10. data/config/deploy.rb.sample +62 -0
  11. data/lib/nesta/app.rb +199 -0
  12. data/lib/nesta/cache.rb +139 -0
  13. data/lib/nesta/commands.rb +135 -0
  14. data/lib/nesta/config.rb +87 -0
  15. data/lib/nesta/models.rb +313 -0
  16. data/lib/nesta/nesta.rb +0 -0
  17. data/lib/nesta/overrides.rb +59 -0
  18. data/lib/nesta/path.rb +11 -0
  19. data/lib/nesta/plugins.rb +15 -0
  20. data/lib/nesta/version.rb +3 -0
  21. data/nesta.gemspec +49 -0
  22. data/scripts/import-from-mephisto +207 -0
  23. data/spec/atom_spec.rb +138 -0
  24. data/spec/commands_spec.rb +220 -0
  25. data/spec/config_spec.rb +69 -0
  26. data/spec/model_factory.rb +94 -0
  27. data/spec/models_spec.rb +445 -0
  28. data/spec/overrides_spec.rb +113 -0
  29. data/spec/page_spec.rb +428 -0
  30. data/spec/path_spec.rb +28 -0
  31. data/spec/sitemap_spec.rb +102 -0
  32. data/spec/spec.opts +1 -0
  33. data/spec/spec_helper.rb +72 -0
  34. data/templates/Gemfile +8 -0
  35. data/templates/Rakefile +35 -0
  36. data/templates/config.ru +9 -0
  37. data/templates/config/config.yml +73 -0
  38. data/templates/config/deploy.rb +47 -0
  39. data/views/analytics.haml +12 -0
  40. data/views/atom.builder +28 -0
  41. data/views/categories.haml +3 -0
  42. data/views/comments.haml +8 -0
  43. data/views/error.haml +13 -0
  44. data/views/feed.haml +3 -0
  45. data/views/index.haml +5 -0
  46. data/views/layout.haml +27 -0
  47. data/views/master.sass +246 -0
  48. data/views/not_found.haml +13 -0
  49. data/views/page.haml +29 -0
  50. data/views/sidebar.haml +3 -0
  51. data/views/sitemap.builder +15 -0
  52. data/views/summaries.haml +14 -0
  53. metadata +302 -0
@@ -0,0 +1,220 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+ require File.expand_path("../lib/nesta/commands", File.dirname(__FILE__))
3
+
4
+ describe "nesta" do
5
+ include FixtureHelper
6
+
7
+ before(:each) do
8
+ create_fixtures_directory
9
+ @project_path = File.join(FixtureHelper::FIXTURE_DIR, 'mysite.com')
10
+ end
11
+
12
+ after(:each) do
13
+ remove_fixtures
14
+ end
15
+
16
+ def project_path(path)
17
+ File.join(@project_path, path)
18
+ end
19
+
20
+ def should_exist(file)
21
+ File.exist?(project_path(file)).should be_true
22
+ end
23
+
24
+ describe "new" do
25
+ def gemfile_source
26
+ File.read(project_path('Gemfile'))
27
+ end
28
+
29
+ def rakefile_source
30
+ File.read(project_path('Rakefile'))
31
+ end
32
+
33
+ describe "without options" do
34
+ before(:each) do
35
+ Nesta::Commands::New.new(@project_path).execute
36
+ end
37
+
38
+ it "should create the content directories" do
39
+ should_exist('content/attachments')
40
+ should_exist('content/pages')
41
+ end
42
+
43
+ it "should create the rackup file" do
44
+ should_exist('config.ru')
45
+ end
46
+
47
+ it "should create the config.yml file" do
48
+ should_exist('config/config.yml')
49
+ end
50
+
51
+ it "should add a Gemfile" do
52
+ should_exist('Gemfile')
53
+ gemfile_source.should match(/gem 'nesta', '#{Nesta::VERSION}'/)
54
+ end
55
+ end
56
+
57
+ describe "--heroku" do
58
+ before(:each) do
59
+ Nesta::Commands::New.new(@project_path, 'heroku' => '').execute
60
+ end
61
+
62
+ it "should add heroku to Gemfile" do
63
+ gemfile_source.should match(/gem 'heroku'/)
64
+ end
65
+
66
+ it "should add the heroku:config Rake task" do
67
+ should_exist('Rakefile')
68
+ rakefile_source.should match(/namespace :heroku/)
69
+ rakefile_source.should match(/task :config/)
70
+ end
71
+ end
72
+
73
+ describe "--vlad" do
74
+ before(:each) do
75
+ Nesta::Commands::New.new(@project_path, 'vlad' => '').execute
76
+ end
77
+
78
+ it "should add vlad to Gemfile" do
79
+ gemfile_source.should match(/gem 'vlad', '2.1.0'/)
80
+ gemfile_source.should match(/gem 'vlad-git', '2.2.0'/)
81
+ end
82
+
83
+ it "should configure the vlad rake tasks" do
84
+ should_exist('Rakefile')
85
+ rakefile_source.should match(/require 'vlad'/)
86
+ end
87
+
88
+ it "should create deploy.rb" do
89
+ should_exist('config/deploy.rb')
90
+ deploy_source = File.read(project_path('config/deploy.rb'))
91
+ deploy_source.should match(/set :application, 'mysite.com'/)
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "theme:install" do
97
+ before(:each) do
98
+ @repo_url = 'git://github.com/gma/nesta-theme-mine.git'
99
+ @theme_dir = 'themes/mine'
100
+ FileUtils.mkdir_p(File.join(@theme_dir, '.git'))
101
+ @command = Nesta::Commands::Theme::Install.new(@repo_url)
102
+ @command.stub!(:system)
103
+ end
104
+
105
+ after(:each) do
106
+ FileUtils.rm_r(@theme_dir)
107
+ end
108
+
109
+ it "should clone the repository" do
110
+ @command.should_receive(:system).with(
111
+ 'git', 'clone', @repo_url, @theme_dir)
112
+ @command.execute
113
+ end
114
+
115
+ it "should remove the theme's .git directory" do
116
+ @command.execute
117
+ File.exist?(@theme_dir).should be_true
118
+ File.exist?(File.join(@theme_dir, '.git')).should be_false
119
+ end
120
+
121
+ it "should enable the freshly installed theme" do
122
+ @command.should_receive(:enable).with('mine')
123
+ @command.execute
124
+ end
125
+
126
+ describe "when theme URL doesn't match recommendation" do
127
+ before(:each) do
128
+ @repo_url = 'git://foobar.com/path/to/mytheme.git'
129
+ @other_theme_dir = 'themes/mytheme'
130
+ FileUtils.mkdir_p(File.join(@other_theme_dir, '.git'))
131
+ @command = Nesta::Commands::Theme::Install.new(@repo_url)
132
+ end
133
+
134
+ after(:each) do
135
+ FileUtils.rm_r(@other_theme_dir)
136
+ end
137
+
138
+ it "should use the basename as theme dir" do
139
+ @command.should_receive(:system).with(
140
+ 'git', 'clone', @repo_url, @other_theme_dir)
141
+ @command.execute
142
+ end
143
+ end
144
+ end
145
+
146
+ describe "theme:enable" do
147
+ before(:each) do
148
+ config = File.join(FixtureHelper::FIXTURE_DIR, 'config.yml')
149
+ Nesta::Config.stub!(:yaml_path).and_return(config)
150
+ @name = 'mytheme'
151
+ @command = Nesta::Commands::Theme::Enable.new(@name)
152
+ end
153
+
154
+ def create_config_yaml(text)
155
+ File.open(Nesta::Config.yaml_path, 'w') { |f| f.puts(text) }
156
+ end
157
+
158
+ shared_examples_for "command that configures the theme" do
159
+ it "should enable the theme" do
160
+ @command.execute
161
+ File.read(Nesta::Config.yaml_path).should match(/^theme: #{@name}/)
162
+ end
163
+ end
164
+
165
+ describe "when theme config is commented out" do
166
+ before(:each) do
167
+ create_config_yaml(' # theme: blah')
168
+ end
169
+
170
+ it_should_behave_like "command that configures the theme"
171
+ end
172
+
173
+ describe "when another theme is configured" do
174
+ before(:each) do
175
+ create_config_yaml('theme: another')
176
+ end
177
+
178
+ it_should_behave_like "command that configures the theme"
179
+ end
180
+
181
+ describe "when no theme config exists" do
182
+ before(:each) do
183
+ create_config_yaml('# I have no theme config')
184
+ end
185
+
186
+ it_should_behave_like "command that configures the theme"
187
+ end
188
+ end
189
+
190
+ describe "theme:create" do
191
+ def should_exist(file)
192
+ File.exist?(Nesta::Path.themes(@name, file)).should be_true
193
+ end
194
+
195
+ before(:each) do
196
+ Nesta::App.stub!(:root).and_return(FixtureHelper::FIXTURE_DIR)
197
+ @name = 'my-new-theme'
198
+ Nesta::Commands::Theme::Create.new(@name).execute
199
+ end
200
+
201
+ it "should create the theme directory" do
202
+ File.directory?(Nesta::Path.themes(@name)).should be_true
203
+ end
204
+
205
+ it "should create a dummy README file" do
206
+ should_exist('README.md')
207
+ text = File.read(Nesta::Path.themes(@name, 'README.md'))
208
+ text.should match(/#{@name} is a theme/)
209
+ end
210
+
211
+ it "should create a default app.rb file" do
212
+ should_exist('app.rb')
213
+ end
214
+
215
+ it "should create public and view directories" do
216
+ should_exist("public/#{@name}")
217
+ should_exist('views')
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,69 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe "Config" do
4
+ include ConfigSpecHelper
5
+
6
+ after(:each) do
7
+ ENV.keys.each { |variable| ENV.delete(variable) if variable =~ /NESTA_/ }
8
+ end
9
+
10
+ describe "when settings defined in ENV" do
11
+ before(:each) do
12
+ @title = "Title from ENV"
13
+ ENV["NESTA_TITLE"] = @title
14
+ end
15
+
16
+ it "should never try and access config.yml" do
17
+ stub_config_key("subtitle", "Subtitle in YAML file")
18
+ Nesta::Config.subtitle.should be_nil
19
+ end
20
+
21
+ it "should override config.yml" do
22
+ stub_config_key("title", "Title in YAML file")
23
+ Nesta::Config.title.should == @title
24
+ end
25
+
26
+ it "should know how to cope with boolean values" do
27
+ ENV["NESTA_CACHE"] = "true"
28
+ Nesta::Config.cache.should be_true
29
+ ENV["NESTA_CACHE"] = "false"
30
+ Nesta::Config.cache.should be_false
31
+ end
32
+
33
+ it "should set author hash from ENV" do
34
+ name = "Name from ENV"
35
+ uri = "URI from ENV"
36
+ ENV["NESTA_AUTHOR__NAME"] = name
37
+ ENV["NESTA_AUTHOR__URI"] = uri
38
+ Nesta::Config.author["name"].should == name
39
+ Nesta::Config.author["uri"].should == uri
40
+ Nesta::Config.author["email"].should be_nil
41
+ end
42
+ end
43
+
44
+ describe "when settings only defined in config.yml" do
45
+ before(:each) do
46
+ @title = "Title in YAML file"
47
+ stub_config_key("subtitle", @title)
48
+ end
49
+
50
+ it "should read configuration from YAML" do
51
+ Nesta::Config.subtitle.should == @title
52
+ end
53
+
54
+ it "should set author hash from YAML" do
55
+ name = "Name from YAML"
56
+ uri = "URI from YAML"
57
+ stub_config_key("author", { "name" => name, "uri" => uri })
58
+ Nesta::Config.author["name"].should == name
59
+ Nesta::Config.author["uri"].should == uri
60
+ Nesta::Config.author["email"].should be_nil
61
+ end
62
+
63
+ it "should override top level settings with RACK_ENV specific settings" do
64
+ stub_config_key('content', 'general/path')
65
+ stub_config_key('content', 'rack_env/path', :rack_env => true)
66
+ Nesta::Config.content.should == 'rack_env/path'
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,94 @@
1
+ module ModelFactory
2
+ include FixtureHelper
3
+
4
+ def create_page(options)
5
+ extension = options[:ext] || :mdown
6
+ path = filename(Nesta::Config.page_path, options[:path], extension)
7
+ create_file(path, options)
8
+ yield(path) if block_given?
9
+ Nesta::Page.new(path)
10
+ end
11
+
12
+ def create_article(options = {}, &block)
13
+ o = {
14
+ :path => 'article-prefix/my-article',
15
+ :heading => 'My article',
16
+ :content => 'Content goes here',
17
+ :metadata => {
18
+ 'date' => '29 December 2008'
19
+ }.merge(options.delete(:metadata) || {})
20
+ }.merge(options)
21
+ create_page(o, &block)
22
+ end
23
+
24
+ def create_category(options = {}, &block)
25
+ o = {
26
+ :path => 'category-prefix/my-category',
27
+ :heading => 'My category',
28
+ :content => 'Content goes here'
29
+ }.merge(options)
30
+ create_page(o, &block)
31
+ end
32
+
33
+ def write_menu_item(indent, file, menu_item)
34
+ if menu_item.is_a?(Array)
35
+ indent.sub!(/^/, ' ')
36
+ menu_item.each { |path| write_menu_item(indent, file, path) }
37
+ indent.sub!(/^ /, '')
38
+ else
39
+ file.write("#{indent}#{menu_item}\n")
40
+ end
41
+ end
42
+
43
+ def create_menu(menu_text)
44
+ file = filename(Nesta::Config.content_path, 'menu', :txt)
45
+ File.open(file, 'w') { |file| file.write(menu_text) }
46
+ end
47
+
48
+ def delete_page(type, permalink, extension)
49
+ file = filename(Nesta::Config.page_path, permalink, extension)
50
+ FileUtils.rm(file)
51
+ end
52
+
53
+ def create_content_directories
54
+ FileUtils.mkdir_p(Nesta::Config.page_path)
55
+ FileUtils.mkdir_p(Nesta::Config.attachment_path)
56
+ end
57
+
58
+ def mock_file_stat(method, filename, time)
59
+ stat = mock(:stat)
60
+ stat.stub!(:mtime).and_return(Time.parse(time))
61
+ File.send(method, :stat).with(filename).and_return(stat)
62
+ end
63
+
64
+ private
65
+ def filename(directory, basename, extension = :mdown)
66
+ File.join(directory, "#{basename}.#{extension}")
67
+ end
68
+
69
+ def heading(options)
70
+ prefix = case options[:ext]
71
+ when :haml
72
+ "%div\n %h1"
73
+ when :textile
74
+ "<div>\nh1."
75
+ else
76
+ '# '
77
+ end
78
+ "#{prefix} #{options[:heading]}\n\n"
79
+ end
80
+
81
+ def create_file(path, options = {})
82
+ create_content_directories
83
+ metadata = options[:metadata] || {}
84
+ metatext = metadata.map { |key, value| "#{key}: #{value}" }.join("\n")
85
+ heading = options[:heading] ? heading(options) : ''
86
+ contents =<<-EOF
87
+ #{metatext}
88
+
89
+ #{heading}#{options[:content]}
90
+ EOF
91
+ FileUtils.mkdir_p(File.dirname(path))
92
+ File.open(path, 'w') { |file| file.write(contents) }
93
+ end
94
+ end
@@ -0,0 +1,445 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+ require File.expand_path('model_factory', File.dirname(__FILE__))
3
+
4
+ module ModelMatchers
5
+ class HavePage
6
+ def initialize(path)
7
+ @category = path
8
+ end
9
+
10
+ def matches?(article)
11
+ @article = article
12
+ article.categories.map { |c| c.path }.include?(@category)
13
+ end
14
+
15
+ def failure_message
16
+ "expected '#{@article.path}' to be assigned to #{@category}"
17
+ end
18
+
19
+ def negative_failure_message
20
+ "'#{@article.path}' should not be assigned to #{@category}"
21
+ end
22
+ end
23
+
24
+ def be_in_category(path)
25
+ HavePage.new(path)
26
+ end
27
+ end
28
+
29
+ describe "Page", :shared => true do
30
+ include ConfigSpecHelper
31
+ include ModelFactory
32
+ include ModelMatchers
33
+
34
+ def create_page(options)
35
+ super(options.merge(:ext => @extension))
36
+ end
37
+
38
+ before(:each) do
39
+ stub_configuration
40
+ end
41
+
42
+ after(:each) do
43
+ remove_fixtures
44
+ Nesta::FileModel.purge_cache
45
+ end
46
+
47
+ it "should be findable" do
48
+ create_page(:heading => "Apple", :path => "the-apple")
49
+ Nesta::Page.find_all.should have(1).item
50
+ end
51
+
52
+ it "should find by path" do
53
+ create_page(:heading => "Banana", :path => "banana")
54
+ Nesta::Page.find_by_path("banana").heading.should == "Banana"
55
+ end
56
+
57
+ it "should not find nonexistent page" do
58
+ Nesta::Page.find_by_path("no-such-page").should be_nil
59
+ end
60
+
61
+ it "should ensure file exists on instantiation" do
62
+ lambda {
63
+ Nesta::Page.new("no-such-file")
64
+ }.should raise_error(Sinatra::NotFound)
65
+ end
66
+
67
+ it "should reload cached files when modified" do
68
+ create_page(:path => "a-page", :heading => "Version 1")
69
+ File.stub!(:mtime).and_return(Time.new - 1)
70
+ Nesta::Page.find_by_path("a-page")
71
+ create_page(:path => "a-page", :heading => "Version 2")
72
+ File.stub!(:mtime).and_return(Time.new)
73
+ Nesta::Page.find_by_path("a-page").heading.should == "Version 2"
74
+ end
75
+
76
+ describe "with assigned pages" do
77
+ before(:each) do
78
+ @category = create_category
79
+ create_article(:heading => "Article 1", :path => "article-1")
80
+ create_article(
81
+ :heading => "Article 2",
82
+ :path => "article-2",
83
+ :metadata => {
84
+ "date" => "30 December 2008",
85
+ "categories" => @category.path
86
+ }
87
+ )
88
+ @article = create_article(
89
+ :heading => "Article 3",
90
+ :path => "article-3",
91
+ :metadata => {
92
+ "date" => "31 December 2008",
93
+ "categories" => @category.path
94
+ }
95
+ )
96
+ create_category(:path => "category-2",
97
+ :metadata => { "categories" => @category.path })
98
+ end
99
+
100
+ it "should find articles" do
101
+ @category.articles.should have(2).items
102
+ end
103
+
104
+ it "should list most recent articles first" do
105
+ @category.articles.first.path.should == @article.path
106
+ end
107
+
108
+ it "should find pages" do
109
+ @category.pages.should have(1).item
110
+ end
111
+
112
+ it "should not find pages scheduled in the future" do
113
+ future_date = (Time.now + 86400).strftime("%d %B %Y")
114
+ article = create_article(:heading => "Article 4",
115
+ :path => "foo/article-4",
116
+ :metadata => { "date" => future_date })
117
+ Nesta::Page.find_articles.detect{|a| a == article}.should be_nil
118
+ end
119
+ end
120
+
121
+ describe "when finding articles" do
122
+ before(:each) do
123
+ create_article(:heading => "Article 1", :path => "article-1")
124
+ create_article(:heading => "Article 2",
125
+ :path => "article-2",
126
+ :metadata => { "date" => "31 December 2008" })
127
+ create_article(:heading => "Article 3",
128
+ :path => "foo/article-3",
129
+ :metadata => { "date" => "30 December 2008" })
130
+ end
131
+
132
+ it "should only find pages with dates" do
133
+ articles = Nesta::Page.find_articles
134
+ articles.size.should > 0
135
+ Nesta::Page.find_articles.each { |page| page.date.should_not be_nil }
136
+ end
137
+
138
+ it "should return articles in reverse chronological order" do
139
+ article1, article2 = Nesta::Page.find_articles[0..1]
140
+ article1.date.should > article2.date
141
+ end
142
+ end
143
+
144
+ describe "when assigned to categories" do
145
+ before(:each) do
146
+ create_category(:heading => "Apple", :path => "the-apple")
147
+ create_category(:heading => "Banana", :path => "banana")
148
+ @article = create_article(
149
+ :metadata => { "categories" => "banana, the-apple" })
150
+ end
151
+
152
+ it "should be possible to list the categories" do
153
+ @article.categories.should have(2).items
154
+ @article.should be_in_category("the-apple")
155
+ @article.should be_in_category("banana")
156
+ end
157
+
158
+ it "should sort categories by heading" do
159
+ @article.categories.first.heading.should == "Apple"
160
+ end
161
+
162
+ it "should not be assigned to non-existant category" do
163
+ delete_page(:category, "banana", @extension)
164
+ @article.should_not be_in_category("banana")
165
+ end
166
+ end
167
+
168
+ it "should be able to find parent page" do
169
+ category = create_category(:path => "parent")
170
+ article = create_article(:path => "parent/child")
171
+ article.parent.should == category
172
+ end
173
+
174
+ it "should set parent to nil when at root" do
175
+ create_category(:path => "top-level").parent.should be_nil
176
+ end
177
+
178
+ describe "when not assigned to category" do
179
+ it "should have empty category list" do
180
+ article = create_article
181
+ Nesta::Page.find_by_path(article.path).categories.should be_empty
182
+ end
183
+ end
184
+
185
+ describe "without metadata" do
186
+ before(:each) do
187
+ create_article
188
+ @article = Nesta::Page.find_all.first
189
+ end
190
+
191
+ it "should use default layout" do
192
+ @article.layout.should == :layout
193
+ end
194
+
195
+ it "should use default template" do
196
+ @article.template.should == :page
197
+ end
198
+
199
+ it "should parse heading correctly" do
200
+ @article.to_html.should have_tag("h1", "My article")
201
+ end
202
+
203
+ it "should have default read more link text" do
204
+ @article.read_more.should == "Continue reading"
205
+ end
206
+
207
+ it "should not have description" do
208
+ @article.description.should be_nil
209
+ end
210
+
211
+ it "should not have keywords" do
212
+ @article.keywords.should be_nil
213
+ end
214
+ end
215
+
216
+ describe "with metadata" do
217
+ before(:each) do
218
+ @layout = "my_layout"
219
+ @template = "my_template"
220
+ @date = "07 September 2009"
221
+ @keywords = "things, stuff"
222
+ @description = "Page about stuff"
223
+ @summary = 'Multiline\n\nsummary'
224
+ @read_more = "Continue at your leisure"
225
+ @article = create_article(:metadata => {
226
+ "layout" => @layout,
227
+ "template" => @template,
228
+ "date" => @date.gsub("September", "Sep"),
229
+ "description" => @description,
230
+ "keywords" => @keywords,
231
+ "summary" => @summary,
232
+ "read more" => @read_more
233
+ })
234
+ end
235
+
236
+ it "should override default layout" do
237
+ @article.layout.should == @layout.to_sym
238
+ end
239
+
240
+ it "should override default template" do
241
+ @article.template.should == @template.to_sym
242
+ end
243
+
244
+ it "should set permalink from filename" do
245
+ @article.permalink.should == "my-article"
246
+ end
247
+
248
+ it "should set path from filename" do
249
+ @article.path.should == "article-prefix/my-article"
250
+ end
251
+
252
+ it "should retrieve heading" do
253
+ @article.heading.should == "My article"
254
+ end
255
+
256
+ it "should be possible to convert an article to HTML" do
257
+ @article.to_html.should have_tag("h1", "My article")
258
+ end
259
+
260
+ it "should not include metadata in the HTML" do
261
+ @article.to_html.should_not have_tag("p", /^Date/)
262
+ end
263
+
264
+ it "should not include heading in body" do
265
+ @article.body.should_not have_tag("h1", "My article")
266
+ end
267
+
268
+ it "should retrieve description from metadata" do
269
+ @article.description.should == @description
270
+ end
271
+
272
+ it "should retrieve keywords from metadata" do
273
+ @article.keywords.should == @keywords
274
+ end
275
+
276
+ it "should retrieve date published from metadata" do
277
+ @article.date.strftime("%d %B %Y").should == @date
278
+ end
279
+
280
+ it "should retrieve read more link from metadata" do
281
+ @article.read_more.should == @read_more
282
+ end
283
+
284
+ it "should retrieve summary text from metadata" do
285
+ @article.summary.should match(/#{@summary.split('\n\n').first}/)
286
+ end
287
+
288
+ it "should treat double newline chars as paragraph break in summary" do
289
+ @article.summary.should match(/#{@summary.split('\n\n').last}/)
290
+ end
291
+ end
292
+
293
+ describe "when checking last modification time" do
294
+ before(:each) do
295
+ create_article
296
+ @article = Nesta::Page.find_all.first
297
+ end
298
+
299
+ it "should check filesystem" do
300
+ mock_file_stat(:should_receive, @article.filename, "3 January 2009")
301
+ @article.last_modified.should == Time.parse("3 January 2009")
302
+ end
303
+ end
304
+ end
305
+
306
+ describe "All types of page" do
307
+ include ConfigSpecHelper
308
+ include ModelFactory
309
+
310
+ before(:each) do
311
+ stub_configuration
312
+ end
313
+
314
+ after(:each) do
315
+ remove_fixtures
316
+ Nesta::FileModel.purge_cache
317
+ end
318
+
319
+ it "should still return top level menu items" do
320
+ # Page.menu_items is deprecated; we're keeping it for the moment so
321
+ # that we don't break themes or code in a local app.rb (just yet).
322
+ page1 = create_category(:path => "page-1")
323
+ page2 = create_category(:path => "page-2")
324
+ create_menu([page1.path, page2.path].join("\n"))
325
+ Nesta::Page.menu_items.should == [page1, page2]
326
+ end
327
+ end
328
+
329
+ describe "Markdown page" do
330
+ include ConfigSpecHelper
331
+
332
+ before(:each) do
333
+ @extension = :mdown
334
+ end
335
+
336
+ it_should_behave_like "Page"
337
+
338
+ it "should set heading from first h1 tag" do
339
+ create_page(
340
+ :path => "a-page",
341
+ :heading => "First heading",
342
+ :content => "# Second heading"
343
+ )
344
+ Nesta::Page.find_by_path("a-page").heading.should == "First heading"
345
+ end
346
+ end
347
+
348
+ describe "Haml page" do
349
+ include ConfigSpecHelper
350
+
351
+ before(:each) do
352
+ @extension = :haml
353
+ end
354
+
355
+ it_should_behave_like "Page"
356
+
357
+ it "should set heading from first h1 tag" do
358
+ create_page(
359
+ :path => "a-page",
360
+ :heading => "First heading",
361
+ :content => "%h1 Second heading"
362
+ )
363
+ Nesta::Page.find_by_path("a-page").heading.should == "First heading"
364
+ end
365
+ end
366
+
367
+ describe "Textile page" do
368
+ include ConfigSpecHelper
369
+
370
+ before(:each) do
371
+ @extension = :textile
372
+ end
373
+
374
+ it_should_behave_like "Page"
375
+
376
+ it "should set heading from first h1 tag" do
377
+ create_page(
378
+ :path => "a-page",
379
+ :heading => "First heading",
380
+ :content => "h1. Second heading"
381
+ )
382
+ Nesta::Page.find_by_path("a-page").heading.should == "First heading"
383
+ end
384
+ end
385
+
386
+ describe "Menu" do
387
+ include ConfigSpecHelper
388
+ include ModelFactory
389
+
390
+ before(:each) do
391
+ stub_configuration
392
+ @page = create_page(:path => "page-1")
393
+ end
394
+
395
+ after(:each) do
396
+ remove_fixtures
397
+ Nesta::FileModel.purge_cache
398
+ end
399
+
400
+ it "should find top level menu items" do
401
+ text = [@page.path, "no-such-page"].join("\n")
402
+ create_menu(text)
403
+ Nesta::Menu.top_level.should == [@page]
404
+ end
405
+
406
+ it "should find all items in the menu" do
407
+ create_menu(@page.path)
408
+ Nesta::Menu.full_menu.should == [@page]
409
+ Nesta::Menu.for_path('/').should == [@page]
410
+ end
411
+
412
+ describe "with nested sub menus" do
413
+ before(:each) do
414
+ (2..6).each do |i|
415
+ instance_variable_set("@page#{i}", create_page(:path => "page-#{i}"))
416
+ end
417
+ text = <<-EOF
418
+ #{@page.path}
419
+ #{@page2.path}
420
+ #{@page3.path}
421
+ #{@page4.path}
422
+ #{@page5.path}
423
+ #{@page6.path}
424
+ EOF
425
+ create_menu(text)
426
+ end
427
+
428
+ it "should return top level menu items" do
429
+ Nesta::Menu.top_level.should == [@page, @page5]
430
+ end
431
+
432
+ it "should return full tree of menu items" do
433
+ Nesta::Menu.full_menu.should ==
434
+ [@page, [@page2, [@page3, @page4]], @page5, [@page6]]
435
+ end
436
+
437
+ it "should return part of the tree of menu items" do
438
+ Nesta::Menu.for_path(@page2.path).should == [@page2, [@page3, @page4]]
439
+ end
440
+
441
+ it "should deem menu for path that isn't in menu to be nil" do
442
+ Nesta::Menu.for_path('wibble').should be_nil
443
+ end
444
+ end
445
+ end