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.
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