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.
- data/.gitignore +13 -0
- data/CHANGES +97 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +44 -0
- data/LICENSE +19 -0
- data/README.md +42 -0
- data/Rakefile +12 -0
- data/bin/nesta +79 -0
- data/config.ru +9 -0
- data/config/deploy.rb.sample +62 -0
- data/lib/nesta/app.rb +167 -0
- data/lib/nesta/cache.rb +139 -0
- data/lib/nesta/commands.rb +188 -0
- data/lib/nesta/config.rb +86 -0
- data/lib/nesta/models.rb +364 -0
- data/lib/nesta/navigation.rb +60 -0
- data/lib/nesta/nesta.rb +7 -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 +48 -0
- data/scripts/import-from-mephisto +207 -0
- data/spec/atom_spec.rb +138 -0
- data/spec/commands_spec.rb +292 -0
- data/spec/config_spec.rb +69 -0
- data/spec/model_factory.rb +94 -0
- data/spec/models_spec.rb +554 -0
- data/spec/overrides_spec.rb +114 -0
- data/spec/page_spec.rb +458 -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 +70 -0
- data/templates/Gemfile +8 -0
- data/templates/Rakefile +11 -0
- data/templates/config.ru +9 -0
- data/templates/config/config.yml +67 -0
- data/templates/config/deploy.rb +47 -0
- data/templates/index.haml +1 -0
- data/templates/themes/README.md +7 -0
- data/templates/themes/app.rb +19 -0
- data/views/analytics.haml +12 -0
- data/views/atom.haml +28 -0
- data/views/categories.haml +4 -0
- data/views/colors.sass +10 -0
- data/views/comments.haml +8 -0
- data/views/error.haml +12 -0
- data/views/feed.haml +3 -0
- data/views/footer.haml +5 -0
- data/views/header.haml +4 -0
- data/views/layout.haml +24 -0
- data/views/master.sass +246 -0
- data/views/mixins.sass +39 -0
- data/views/not_found.haml +12 -0
- data/views/page.haml +21 -0
- data/views/page_meta.haml +16 -0
- data/views/sidebar.haml +3 -0
- data/views/sitemap.haml +11 -0
- data/views/summaries.haml +15 -0
- metadata +235 -0
@@ -0,0 +1,292 @@
|
|
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
|
+
def create_config_yaml(text)
|
25
|
+
File.open(Nesta::Config.yaml_path, 'w') { |f| f.puts(text) }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "new" do
|
29
|
+
def gemfile_source
|
30
|
+
File.read(project_path('Gemfile'))
|
31
|
+
end
|
32
|
+
|
33
|
+
def rakefile_source
|
34
|
+
File.read(project_path('Rakefile'))
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "without options" do
|
38
|
+
before(:each) do
|
39
|
+
Nesta::Commands::New.new(@project_path).execute
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should create the content directories" do
|
43
|
+
should_exist('content/attachments')
|
44
|
+
should_exist('content/pages')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should create the home page" do
|
48
|
+
should_exist('content/pages/index.haml')
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should create the rackup file" do
|
52
|
+
should_exist('config.ru')
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should create the config.yml file" do
|
56
|
+
should_exist('config/config.yml')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should add a Gemfile" do
|
60
|
+
should_exist('Gemfile')
|
61
|
+
gemfile_source.should match(/gem 'nesta', '#{Nesta::VERSION}'/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "--git" do
|
66
|
+
before(:each) do
|
67
|
+
@command = Nesta::Commands::New.new(@project_path, 'git' => '')
|
68
|
+
@command.stub!(:system)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should create a .gitignore file" do
|
72
|
+
@command.execute
|
73
|
+
File.read(project_path('.gitignore')).should match(/\.bundle/)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should create a git repo" do
|
77
|
+
@command.should_receive(:system).with('git', 'init')
|
78
|
+
@command.execute
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should commit the blank project" do
|
82
|
+
@command.should_receive(:system).with('git', 'add', '.')
|
83
|
+
@command.should_receive(:system).with(
|
84
|
+
'git', 'commit', '-m', 'Initial commit')
|
85
|
+
@command.execute
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "--vlad" do
|
90
|
+
before(:each) do
|
91
|
+
Nesta::Commands::New.new(@project_path, 'vlad' => '').execute
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should add vlad to Gemfile" do
|
95
|
+
gemfile_source.should match(/gem 'vlad', '2.1.0'/)
|
96
|
+
gemfile_source.should match(/gem 'vlad-git', '2.2.0'/)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should configure the vlad rake tasks" do
|
100
|
+
should_exist('Rakefile')
|
101
|
+
rakefile_source.should match(/require 'vlad'/)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should create deploy.rb" do
|
105
|
+
should_exist('config/deploy.rb')
|
106
|
+
deploy_source = File.read(project_path('config/deploy.rb'))
|
107
|
+
deploy_source.should match(/set :application, 'mysite.com'/)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "demo:content" do
|
113
|
+
before(:each) do
|
114
|
+
@config_path = project_path('config/config.yml')
|
115
|
+
FileUtils.mkdir_p(File.dirname(@config_path))
|
116
|
+
Nesta::Config.stub!(:yaml_path).and_return(@config_path)
|
117
|
+
create_config_yaml('content: path/to/content')
|
118
|
+
Nesta::App.stub!(:root).and_return(@project_path)
|
119
|
+
@repo_url = 'git://github.com/gma/nesta-demo-content.git'
|
120
|
+
@demo_path = project_path('content-demo')
|
121
|
+
@command = Nesta::Commands::Demo::Content.new
|
122
|
+
@command.stub!(:system)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should clone the repository" do
|
126
|
+
@command.should_receive(:system).with(
|
127
|
+
'git', 'clone', @repo_url, @demo_path)
|
128
|
+
@command.execute
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should configure the content directory" do
|
132
|
+
@command.execute
|
133
|
+
File.read(@config_path).should match(/^content: content-demo/)
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "when repository already exists" do
|
137
|
+
before(:each) do
|
138
|
+
FileUtils.mkdir_p(@demo_path)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should update the repository" do
|
142
|
+
@command.should_receive(:system).with('git', 'pull', 'origin', 'master')
|
143
|
+
@command.execute
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "when site versioned with git" do
|
148
|
+
before(:each) do
|
149
|
+
@exclude_path = project_path('.git/info/exclude')
|
150
|
+
FileUtils.mkdir_p(File.dirname(@exclude_path))
|
151
|
+
File.open(@exclude_path, 'w') { |file| file.puts '# Excludes' }
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should tell git to ignore content-demo" do
|
155
|
+
@command.execute
|
156
|
+
File.read(@exclude_path).should match(/content-demo/)
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "and content-demo already ignored" do
|
160
|
+
before(:each) do
|
161
|
+
File.open(@exclude_path, 'w') { |file| file.puts 'content-demo' }
|
162
|
+
end
|
163
|
+
|
164
|
+
it "shouldn't tell git to ignore it twice" do
|
165
|
+
@command.execute
|
166
|
+
File.read(@exclude_path).scan('content-demo').size.should == 1
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "theme:install" do
|
173
|
+
before(:each) do
|
174
|
+
@repo_url = 'git://github.com/gma/nesta-theme-mine.git'
|
175
|
+
@theme_dir = 'themes/mine'
|
176
|
+
FileUtils.mkdir_p(File.join(@theme_dir, '.git'))
|
177
|
+
@command = Nesta::Commands::Theme::Install.new(@repo_url)
|
178
|
+
@command.stub!(:system)
|
179
|
+
end
|
180
|
+
|
181
|
+
after(:each) do
|
182
|
+
FileUtils.rm_r(@theme_dir)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should clone the repository" do
|
186
|
+
@command.should_receive(:system).with(
|
187
|
+
'git', 'clone', @repo_url, @theme_dir)
|
188
|
+
@command.execute
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should remove the theme's .git directory" do
|
192
|
+
@command.execute
|
193
|
+
File.exist?(@theme_dir).should be_true
|
194
|
+
File.exist?(File.join(@theme_dir, '.git')).should be_false
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should enable the freshly installed theme" do
|
198
|
+
@command.should_receive(:enable).with('mine')
|
199
|
+
@command.execute
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "when theme URL doesn't match recommendation" do
|
203
|
+
before(:each) do
|
204
|
+
@repo_url = 'git://foobar.com/path/to/mytheme.git'
|
205
|
+
@other_theme_dir = 'themes/mytheme'
|
206
|
+
FileUtils.mkdir_p(File.join(@other_theme_dir, '.git'))
|
207
|
+
@command = Nesta::Commands::Theme::Install.new(@repo_url)
|
208
|
+
end
|
209
|
+
|
210
|
+
after(:each) do
|
211
|
+
FileUtils.rm_r(@other_theme_dir)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should use the basename as theme dir" do
|
215
|
+
@command.should_receive(:system).with(
|
216
|
+
'git', 'clone', @repo_url, @other_theme_dir)
|
217
|
+
@command.execute
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "theme:enable" do
|
223
|
+
before(:each) do
|
224
|
+
config = File.join(FixtureHelper::FIXTURE_DIR, 'config.yml')
|
225
|
+
Nesta::Config.stub!(:yaml_path).and_return(config)
|
226
|
+
@name = 'mytheme'
|
227
|
+
@command = Nesta::Commands::Theme::Enable.new(@name)
|
228
|
+
end
|
229
|
+
|
230
|
+
shared_examples_for "command that configures the theme" do
|
231
|
+
it "should enable the theme" do
|
232
|
+
@command.execute
|
233
|
+
File.read(Nesta::Config.yaml_path).should match(/^theme: #{@name}/)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "when theme config is commented out" do
|
238
|
+
before(:each) do
|
239
|
+
create_config_yaml(' # theme: blah')
|
240
|
+
end
|
241
|
+
|
242
|
+
it_should_behave_like "command that configures the theme"
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "when another theme is configured" do
|
246
|
+
before(:each) do
|
247
|
+
create_config_yaml('theme: another')
|
248
|
+
end
|
249
|
+
|
250
|
+
it_should_behave_like "command that configures the theme"
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "when no theme config exists" do
|
254
|
+
before(:each) do
|
255
|
+
create_config_yaml('# I have no theme config')
|
256
|
+
end
|
257
|
+
|
258
|
+
it_should_behave_like "command that configures the theme"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe "theme:create" do
|
263
|
+
def should_exist(file)
|
264
|
+
File.exist?(Nesta::Path.themes(@name, file)).should be_true
|
265
|
+
end
|
266
|
+
|
267
|
+
before(:each) do
|
268
|
+
Nesta::App.stub!(:root).and_return(FixtureHelper::FIXTURE_DIR)
|
269
|
+
@name = 'my-new-theme'
|
270
|
+
Nesta::Commands::Theme::Create.new(@name).execute
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should create the theme directory" do
|
274
|
+
File.directory?(Nesta::Path.themes(@name)).should be_true
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should create a dummy README file" do
|
278
|
+
should_exist('README.md')
|
279
|
+
text = File.read(Nesta::Path.themes(@name, 'README.md'))
|
280
|
+
text.should match(/#{@name} is a theme/)
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should create a default app.rb file" do
|
284
|
+
should_exist('app.rb')
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should create public and view directories" do
|
288
|
+
should_exist("public/#{@name}")
|
289
|
+
should_exist('views')
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -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
|