massimo 0.7.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.document +5 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +88 -0
  5. data/README.md +3 -1
  6. data/Rakefile +8 -0
  7. data/bin/massimo +1 -17
  8. data/lib/massimo/cli.rb +63 -0
  9. data/lib/massimo/config.rb +8 -5
  10. data/lib/massimo/javascript.rb +10 -2
  11. data/lib/massimo/reloader.rb +37 -0
  12. data/lib/massimo/site.rb +24 -21
  13. data/lib/massimo/templates/site/config.rb +18 -0
  14. data/lib/massimo/templates/site/javascripts/main.js +0 -0
  15. data/lib/massimo/templates/site/pages/index.erb +5 -0
  16. data/lib/massimo/templates/site/public/.empty_directory +0 -0
  17. data/lib/massimo/templates/site/stylesheets/main.scss +0 -0
  18. data/lib/massimo/templates/site/views/layouts/main.erb +12 -0
  19. data/lib/massimo/ui.rb +2 -2
  20. data/lib/massimo/version.rb +1 -1
  21. data/lib/massimo/watcher.rb +22 -7
  22. data/lib/massimo.rb +3 -11
  23. data/massimo.gemspec +40 -0
  24. data/spec/massimo/cli_spec.rb +254 -0
  25. data/spec/massimo/config_spec.rb +97 -0
  26. data/spec/massimo/helpers_spec.rb +26 -0
  27. data/spec/massimo/javascript_spec.rb +120 -0
  28. data/spec/massimo/massimo_spec.rb +23 -0
  29. data/spec/massimo/page_spec.rb +224 -0
  30. data/spec/massimo/reloader_spec.rb +135 -0
  31. data/spec/massimo/resource_spec.rb +208 -0
  32. data/spec/massimo/server_spec.rb +35 -0
  33. data/spec/massimo/site_spec.rb +299 -0
  34. data/spec/massimo/stylesheet_spec.rb +77 -0
  35. data/spec/massimo/ui_spec.rb +109 -0
  36. data/spec/massimo/view_spec.rb +46 -0
  37. data/spec/massimo/watcher_spec.rb +122 -0
  38. data/spec/spec_helper.rb +65 -0
  39. data/spec/support/matchers/be_a_directory_matcher.rb +5 -0
  40. data/spec/support/matchers/be_a_file_matcher.rb +26 -0
  41. metadata +74 -20
  42. data/lib/massimo/commands/base.rb +0 -85
  43. data/lib/massimo/commands/build.rb +0 -19
  44. data/lib/massimo/commands/generate.rb +0 -62
  45. data/lib/massimo/commands/help.rb +0 -34
  46. data/lib/massimo/commands/server.rb +0 -24
  47. data/lib/massimo/commands/version.rb +0 -9
  48. data/lib/massimo/commands/watch.rb +0 -16
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe Massimo::Page do
4
+ context 'with meta data' do
5
+ let(:page) { Massimo::Page.new 'page.erb' }
6
+
7
+ let(:page_content) do
8
+ <<-CONTENT.unindent
9
+ ---
10
+ title: A Page
11
+ created_at: 2010-04-01
12
+ ---
13
+ <%= title %>
14
+ <%= created_at.strftime('%m-%Y') %>
15
+ CONTENT
16
+ end
17
+
18
+ it 'should read the meta data into a #meta_data hash' do
19
+ with_file 'page.erb', page_content do
20
+ page.title.should == 'A Page'
21
+ end
22
+ end
23
+
24
+ it 'should create attributes for each key in the #meta_data' do
25
+ with_file 'page.erb', page_content do
26
+ page.created_at.should_not be_nil
27
+ end
28
+ end
29
+
30
+ it 'should report the #created_at attribute has been set' do
31
+ with_file 'page.erb', page_content do
32
+ page.created_at?.should === true
33
+ end
34
+ end
35
+
36
+ it 'should report the correct line number to Tilt' do
37
+ content = <<-CONTENT.unindent
38
+ ---
39
+ title: A Page
40
+ ---
41
+ <%= raise 'Error' %>
42
+ CONTENT
43
+ with_file 'page.erb', content do
44
+ begin
45
+ page.render
46
+ rescue Exception => error
47
+ error.backtrace.first.should =~ /:4:/
48
+ end
49
+ end
50
+ end
51
+
52
+ it 'should include the meta_data as locals when rendering' do
53
+ with_file 'page.erb', page_content do
54
+ page.render.should include('A Page')
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'without meta data' do
60
+ let(:page) { Massimo::Page.new 'without_meta_data.erb' }
61
+
62
+ it 'should create the #title from the filename' do
63
+ with_file 'without_meta_data.erb' do
64
+ page.title.should == 'Without Meta Data'
65
+ end
66
+ end
67
+
68
+ it "should default the #extension to '.html'" do
69
+ with_file 'without_meta_data.erb' do
70
+ page.extension.should == '.html'
71
+ end
72
+ end
73
+
74
+ it "should default the #layout to 'application'" do
75
+ with_file 'without_meta_data.erb' do
76
+ page.layout.should == 'main'
77
+ end
78
+ end
79
+
80
+ it 'should report the #created_at attribute has not been set' do
81
+ with_file 'without_meta_data.erb' do
82
+ page.created_at?.should === false
83
+ end
84
+ end
85
+ end
86
+
87
+ describe '#render' do
88
+ let(:page) { Massimo::Page.new 'page.erb' }
89
+
90
+ context 'with layouts' do
91
+ it 'should wrap the content in a layout' do
92
+ within_construct do |c|
93
+ c.file 'page.erb'
94
+ c.file 'views/layouts/main.erb', 'Layout'
95
+ page.render.should == 'Layout'
96
+ end
97
+ end
98
+
99
+ it 'should include the content with #yield' do
100
+ within_construct do |c|
101
+ c.file 'page.erb', 'Content'
102
+ c.file 'views/layouts/main.erb', '<%= yield %>'
103
+ page.render.should == 'Content'
104
+ end
105
+ end
106
+
107
+ it 'should include the page as a local' do
108
+ within_construct do |c|
109
+ c.file 'page.erb', "---\ntitle: A Page\n---"
110
+ c.file 'views/layouts/main.erb', "<%= page.title %>"
111
+ page.render.should == 'A Page'
112
+ end
113
+ end
114
+
115
+ it 'should not render the layout if #layout is false' do
116
+ within_construct do |c|
117
+ c.file 'page.erb', "---\nlayout: false\n---\nContent"
118
+ c.file 'views/layouts/main.erb', 'Layout'
119
+
120
+ page.render.should_not include('Layout')
121
+ end
122
+ end
123
+ end
124
+
125
+ it 'should use Site#template_scope as the scope' do
126
+ within_construct do |c|
127
+ c.file 'index.erb', "<%= render 'partial' %>"
128
+ c.file 'views/partial.erb', 'Partial'
129
+ Massimo::Page.new('index.erb').render.should == 'Partial'
130
+ end
131
+ end
132
+
133
+ it 'should include a local that references itself' do
134
+ NewPage = Class.new(Massimo::Page)
135
+ with_file 'new_page.erb', '<%= new_page.title %>' do
136
+ NewPage.new('new_page.erb').render.should == 'New Page'
137
+ end
138
+ end
139
+
140
+ it 'should pass config options for the template' do
141
+ Massimo.config.haml = { :attr_wrapper => %(") }
142
+ with_file 'new_page.haml', '#header Title' do
143
+ Massimo::Page.new('new_page.haml').render.should == %(<div id="header">Title</div>\n)
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '#url' do
149
+ it 'should be a pretty url based on the filename' do
150
+ with_file 'pages/about-us.erb' do
151
+ Massimo::Page.new('pages/about-us.erb').url.should == '/about-us/'
152
+ end
153
+ end
154
+
155
+ context 'with a root directory index' do
156
+ it "should be '/'" do
157
+ with_file 'pages/index.erb' do
158
+ Massimo::Page.new('pages/index.erb').url.should == '/'
159
+ end
160
+ end
161
+ end
162
+
163
+ context 'with a nested directory index' do
164
+ it 'should drop the filename' do
165
+ with_file 'pages/some/url/index.haml' do
166
+ Massimo::Page.new('pages/some/url/index.haml').url.should == '/some/url/'
167
+ end
168
+ end
169
+ end
170
+
171
+ context "when the extension is not '.html'" do
172
+ it 'should not create a pretty url' do
173
+ with_file 'pages/about-us.rss', "---\nextension: .rss\n---" do
174
+ Massimo::Page.new('pages/about-us.rss').url.should == '/about-us.rss'
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ describe '#output_path' do
181
+ it 'should re-add directory index file names' do
182
+ with_file 'pages/some/url/index.html' do
183
+ resource = Massimo::Page.new('pages/some/url/index.html')
184
+ resource.output_path.to_s.should == File.expand_path('public/some/url/index.html')
185
+ end
186
+ end
187
+
188
+ context 'with a root url' do
189
+ it 'should add the directory index' do
190
+ with_file 'pages/index.erb' do
191
+ Massimo::Page.new('pages/index.erb').output_path.to_s.should == File.expand_path('public/index.html')
192
+ end
193
+ end
194
+ end
195
+
196
+ context 'with a pretty url' do
197
+ it 'should create a directory index file' do
198
+ with_file 'pages/about-us.erb' do
199
+ Massimo::Page.new('pages/about-us.erb').output_path.to_s.should == File.expand_path('public/about-us/index.html')
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ context 'as a .yml file' do
206
+ it 'should treat the whole file as front matter' do
207
+ with_file 'pages/data.yml', 'name: Joe' do
208
+ Massimo::Page.new('pages/data.yml').name.should == 'Joe'
209
+ end
210
+ end
211
+
212
+ it 'should default content to an empty string' do
213
+ with_file 'pages/data.yml', 'name: Joe' do
214
+ Massimo::Page.new('pages/data.yml').content.should == ''
215
+ end
216
+ end
217
+
218
+ it 'should set the content with a content attribute' do
219
+ with_file 'pages/data.yml', 'content: Some Content' do
220
+ Massimo::Page.new('pages/data.yml').content.should == 'Some Content'
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+
3
+ describe Massimo::Reloader do
4
+ def within_load_path
5
+ begin
6
+ dir = create_construct
7
+ path = dir.expand_path.to_s
8
+ $LOAD_PATH << path
9
+ dir.maybe_change_dir(true) do
10
+ yield dir
11
+ end
12
+ ensure
13
+ $LOAD_PATH.delete(path)
14
+ dir.destroy!
15
+ end
16
+ end
17
+
18
+ def feature_path(path)
19
+ if RUBY_VERSION.starts_with?('1.8')
20
+ path.to_s
21
+ else
22
+ File.expand_path(path.to_s)
23
+ end
24
+ end
25
+
26
+ after :each do
27
+ Object.send(:remove_const, :Constant) if Object.const_defined?(:Constant)
28
+ end
29
+
30
+ describe '.load' do
31
+ it 'stores the loaded constants in a cache' do
32
+ cache = Massimo::Reloader.load do
33
+ module Constant; end
34
+ end
35
+ cache[:constants].map(&:to_s).should include('Constant')
36
+ end
37
+
38
+ it 'stores the loaded feature paths in a cache' do
39
+ within_load_path do |d|
40
+ d.file('lib/constant.rb', 'module Constant; end')
41
+ cache = Massimo::Reloader.load do
42
+ require 'lib/constant'
43
+ end
44
+ cache[:constants].map(&:to_s).should include('Constant')
45
+ cache[:features].should include(feature_path('lib/constant.rb'))
46
+ $LOADED_FEATURES.delete(feature_path('lib/constant.rb'))
47
+ end
48
+ end
49
+
50
+ context 'with a cache name' do
51
+ it 'stores a different cache for each given name' do
52
+ default_cache = Massimo::Reloader.load
53
+ cache = Massimo::Reloader.load(:libs) do
54
+ module Constant; end
55
+ end
56
+ default_cache.should_not === cache
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '.unload' do
62
+ context 'with a constant defined in .load' do
63
+ before do
64
+ Massimo::Reloader.load do
65
+ module Constant; end
66
+ end
67
+ end
68
+
69
+ it 'undefines the constant' do
70
+ Massimo::Reloader.unload
71
+ defined?(Constant).should be_false
72
+ end
73
+
74
+ it 'removes the constant from the cache' do
75
+ cache = Massimo::Reloader.unload
76
+ cache[:constants].map(&:to_s).should_not include('Constant')
77
+ end
78
+ end
79
+
80
+ context 'with a required feature' do
81
+ it 'removes the loaded feature' do
82
+ within_load_path do |d|
83
+ d.file('lib/constant.rb', 'module Constant; end')
84
+ Massimo::Reloader.load { require 'lib/constant' }
85
+ $LOADED_FEATURES.should include(feature_path('lib/constant.rb'))
86
+ Massimo::Reloader.unload
87
+ $LOADED_FEATURES.should_not include(feature_path('lib/constant.rb'))
88
+ end
89
+ end
90
+
91
+ it 'removes the feature from the cache' do
92
+ within_load_path do |d|
93
+ d.file('lib/constant.rb', 'module Constant; end')
94
+ Massimo::Reloader.load { require 'lib/constant' }
95
+ cache = Massimo::Reloader.unload
96
+ cache[:features].should_not include(feature_path('lib/constant.rb'))
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'with a cache name' do
102
+ it 'removes the constants for that cache' do
103
+ Massimo::Reloader.load do
104
+ module Constant; end
105
+ end
106
+ Massimo::Reloader.load(:libs) do
107
+ module AnotherConstant; end
108
+ end
109
+ Massimo::Reloader.unload(:libs)
110
+ defined?(Constant).should be_true
111
+ defined?(AnotherConstant).should be_false
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '.reload' do
117
+ context 'with a previously defined constant' do
118
+ it 'removes the constant' do
119
+ Massimo::Reloader.reload do
120
+ module Constant; end
121
+ end
122
+ Massimo::Reloader.reload
123
+ defined?(Constant).should be_false
124
+ end
125
+
126
+ it 'defines new constants' do
127
+ Massimo::Reloader.reload
128
+ Massimo::Reloader.reload do
129
+ module Constant; end
130
+ end
131
+ defined?(Constant).should be_true
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,208 @@
1
+ require 'spec_helper'
2
+
3
+ describe Massimo::Resource do
4
+ let(:resource) { Massimo::Resource.new 'file.txt' }
5
+
6
+ describe '#initialize' do
7
+ it 'should require the #source_path to the file' do
8
+ expect { Massimo::Resource.new }.to raise_error
9
+ end
10
+ end
11
+
12
+ describe '#source_path' do
13
+ context 'when set with a string' do
14
+ it 'should be a Pathname object' do
15
+ with_file 'file.txt' do
16
+ resource.source_path.should be_an_instance_of(Pathname)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#url' do
23
+ it 'should be created from the filename' do
24
+ with_file 'a_resource_url.erb' do
25
+ Massimo::Resource.new('a_resource_url.erb').url.should == '/a-resource-url.erb'
26
+ end
27
+ end
28
+
29
+ it "should prepend the Resource's url" do
30
+ with_file 'url.erb' do
31
+ Massimo.config.resources_url = '/resources'
32
+ Massimo::Resource.new('url.erb').url.should == '/resources/url.erb'
33
+ end
34
+ end
35
+
36
+ it 'should replace custom extensions' do
37
+ with_file 'url.erb' do
38
+ resource = Massimo::Resource.new('url.erb')
39
+ stub(resource).extension { '.rss' }
40
+ resource.url.should == '/url.rss'
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#extension' do
46
+ it 'should be the extension of the file' do
47
+ with_file 'url.erb' do
48
+ Massimo::Resource.new('url.erb').extension.should == '.erb'
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#filename' do
54
+ it 'should be the filename of the file' do
55
+ with_file 'url.erb' do
56
+ Massimo::Resource.new('url.erb').filename.should == 'url.erb'
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#output_path' do
62
+ it 'should be a Pathname object' do
63
+ with_file 'file.txt' do
64
+ resource.output_path.should be_an_instance_of(Pathname)
65
+ end
66
+ end
67
+
68
+ it 'should move the #source_path to the sites output dir' do
69
+ with_file 'file.txt' do
70
+ resource.output_path.to_s.should == File.expand_path('public/file.txt')
71
+ end
72
+ end
73
+
74
+ context 'with a custom #base_url' do
75
+ it 'should not include the #base_url' do
76
+ Massimo.config.base_url = '/blog'
77
+ with_file 'file.txt' do
78
+ resource.output_path.to_s.should == File.expand_path('public/file.txt')
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe '#content' do
85
+ it "should read the associated file's content" do
86
+ with_file 'file.txt', 'content' do
87
+ resource.content.should == 'content'
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#render' do
93
+ it "should return the file's content" do
94
+ with_file 'file.txt', 'content' do
95
+ resource.render.should == 'content'
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#process' do
101
+ it 'should create a file with the rendered content' do
102
+ with_file 'file.txt', 'content' do
103
+ resource.process
104
+ File.read('public/file.txt').should == 'content'
105
+ end
106
+ end
107
+ end
108
+
109
+ describe '.resource_name' do
110
+ context 'for Resource' do
111
+ it "should be 'resource'" do
112
+ Massimo::Resource.resource_name.should == 'resources'
113
+ end
114
+ end
115
+
116
+ context 'for Page' do
117
+ it "should be 'page'" do
118
+ Massimo::Page.resource_name.should == 'pages'
119
+ end
120
+ end
121
+
122
+ context 'for a custom Resource' do
123
+ it 'should be determined based on the class name' do
124
+ NewResource = Class.new(Massimo::Resource)
125
+ NewResource.resource_name.should == 'new_resources'
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '.path' do
131
+ it 'should get the path from the configuration' do
132
+ Massimo::Site.new :pages_path => 'some/path'
133
+ Massimo::Page.path.should == File.expand_path('some/path')
134
+ end
135
+ end
136
+
137
+ describe '.url' do
138
+ it 'should get the url from the configuration' do
139
+ Massimo::Site.new :pages_url => '/pages'
140
+ Massimo::Page.url.should == '/pages'
141
+ end
142
+ end
143
+
144
+ describe '.find' do
145
+ it 'should find resources by their file name' do
146
+ with_file 'views/partials/post.haml', '%h1 Post' do
147
+ Massimo::View.find('partials/post').content.should == '%h1 Post'
148
+ end
149
+ end
150
+ end
151
+
152
+ describe '.all' do
153
+ context 'with no options' do
154
+ it 'should return an array of the resource type' do
155
+ within_construct do |c|
156
+ c.file 'file.txt'
157
+ c.file 'file-2.txt'
158
+ Massimo::Resource.all.map(&:class).should == [ Massimo::Resource, Massimo::Resource ]
159
+ end
160
+ end
161
+
162
+ it 'should find all the files in the resource path' do
163
+ within_construct do |c|
164
+ c.file 'pages/index.haml'
165
+ c.file 'pages/about/us.haml'
166
+ c.file 'pages/contact/us.erb'
167
+ Massimo::Page.all.map(&:filename).should =~ %w( index.haml us.haml us.erb)
168
+ end
169
+ end
170
+
171
+ it 'should skip files with prefixed underscores' do
172
+ within_construct do |c|
173
+ c.file 'stylesheets/main.sass'
174
+ c.file 'stylesheets/_base.sass'
175
+ c.file 'stylesheets/_mixins.sass'
176
+ Massimo::Stylesheet.all.map(&:filename).should =~ %w( main.sass )
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ describe '.processable?' do
183
+ it 'should be true be default' do
184
+ Massimo::Resource.should be_processable
185
+ end
186
+
187
+ context 'when a process in unprocessable' do
188
+ it 'should be false' do
189
+ class Unprocessable < Massimo::Resource
190
+ unprocessable
191
+ end
192
+ Unprocessable.should_not be_processable
193
+ end
194
+ end
195
+ end
196
+
197
+ describe '.unprocessable' do
198
+ it 'should overwrite #process to do nothing' do
199
+ class NewResource < Massimo::Resource
200
+ unprocessable
201
+ end
202
+ with_file 'resource.txt' do
203
+ dont_allow(File).open
204
+ NewResource.new('resource.txt').process
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Massimo::Server do
4
+ let(:app) { Massimo::Server.new(Massimo.site) }
5
+
6
+ it 'should serve up static files' do
7
+ with_file 'public/stylesheets/main.css', 'body { font-size: 12px; }' do
8
+ get '/stylesheets/main.css'
9
+ last_response.body.should == 'body { font-size: 12px; }'
10
+ end
11
+ end
12
+
13
+ it 'should serve up directory index files' do
14
+ with_file 'public/about-us/index.html', 'About Us' do
15
+ get '/about-us/'
16
+ last_response.body.should == 'About Us'
17
+ end
18
+ end
19
+
20
+ context 'when files have changed' do
21
+ it 'should process the site on request' do
22
+ with_file 'pages/index.haml' do
23
+ mock(Massimo.site).process
24
+ get '/'
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'when files have not changed' do
30
+ it 'should not process the site on request' do
31
+ dont_allow(Massimo.site).process
32
+ get '/'
33
+ end
34
+ end
35
+ end