machined 0.1.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 (48) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +20 -0
  4. data/README.md +49 -0
  5. data/Rakefile +6 -0
  6. data/bin/machined +4 -0
  7. data/lib/machined.rb +23 -0
  8. data/lib/machined/cli.rb +99 -0
  9. data/lib/machined/context.rb +52 -0
  10. data/lib/machined/environment.rb +297 -0
  11. data/lib/machined/helpers/asset_tag_helpers.rb +135 -0
  12. data/lib/machined/helpers/locals_helpers.rb +57 -0
  13. data/lib/machined/helpers/output_helpers.rb +43 -0
  14. data/lib/machined/helpers/render_helpers.rb +138 -0
  15. data/lib/machined/processors/front_matter_processor.rb +35 -0
  16. data/lib/machined/processors/layout_processor.rb +71 -0
  17. data/lib/machined/server.rb +37 -0
  18. data/lib/machined/sprocket.rb +55 -0
  19. data/lib/machined/static_compiler.rb +71 -0
  20. data/lib/machined/templates/site/Gemfile.tt +10 -0
  21. data/lib/machined/templates/site/assets/images/.empty_directory +0 -0
  22. data/lib/machined/templates/site/assets/javascripts/main.js.coffee +0 -0
  23. data/lib/machined/templates/site/assets/stylesheets/main.css.scss +0 -0
  24. data/lib/machined/templates/site/config.ru +2 -0
  25. data/lib/machined/templates/site/machined.rb +17 -0
  26. data/lib/machined/templates/site/pages/index.html.erb +5 -0
  27. data/lib/machined/templates/site/public/.empty_directory +0 -0
  28. data/lib/machined/templates/site/views/layouts/main.html.erb +12 -0
  29. data/lib/machined/utils.rb +31 -0
  30. data/lib/machined/version.rb +3 -0
  31. data/machined.gemspec +39 -0
  32. data/spec/machined/cli_spec.rb +154 -0
  33. data/spec/machined/context_spec.rb +20 -0
  34. data/spec/machined/environment_spec.rb +202 -0
  35. data/spec/machined/helpers/asset_tag_helpers_spec.rb +95 -0
  36. data/spec/machined/helpers/locals_helper_spec.rb +37 -0
  37. data/spec/machined/helpers/output_helpers_spec.rb +81 -0
  38. data/spec/machined/helpers/render_helpers_spec.rb +53 -0
  39. data/spec/machined/processors/front_matter_processor_spec.rb +42 -0
  40. data/spec/machined/processors/layout_processor_spec.rb +32 -0
  41. data/spec/machined/server_spec.rb +77 -0
  42. data/spec/machined/sprocket_spec.rb +36 -0
  43. data/spec/machined/static_compiler_spec.rb +85 -0
  44. data/spec/machined/utils_spec.rb +31 -0
  45. data/spec/spec_helper.rb +16 -0
  46. data/spec/support/helpers.rb +59 -0
  47. data/spec/support/match_paths_matcher.rb +20 -0
  48. metadata +389 -0
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Context do
4
+ describe "#machined" do
5
+ it "returns a reference to the Machined environment" do
6
+ with_context do |context, output|
7
+ context.machined.should be(machined)
8
+ end
9
+ end
10
+ end
11
+
12
+ describe "#config" do
13
+ it "returns a reference to the Machined environment's configuration" do
14
+ with_context do |context, output|
15
+ machined.config.layout = "application"
16
+ context.config.layout.should == "application"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,202 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Environment do
4
+ describe "#initialize" do
5
+ it "loads configuration from a config file" do
6
+ within_construct do |c|
7
+ c.file "machined.rb", <<-CONTENT.unindent
8
+ config.output_path = "site"
9
+ append_sprocket :updates
10
+ CONTENT
11
+ machined.config.output_path.should == "site"
12
+ machined.updates.should be_a(Machined::Sprocket)
13
+ end
14
+ end
15
+ end
16
+
17
+ describe "#append_sprocket" do
18
+ it "creates a new Sprockets environment" do
19
+ sprocket = machined.append_sprocket :updates
20
+ sprocket.should be_a(Sprockets::Environment)
21
+ end
22
+
23
+ it "appends the sprocket to #sprockets" do
24
+ sprocket = machined.append_sprocket :updates
25
+ machined.sprockets.last.should be(sprocket)
26
+ end
27
+
28
+ it "adds a method with the given name which returns the sprocket" do
29
+ sprocket = machined.append_sprocket :updates
30
+ machined.updates.should be(sprocket)
31
+ Machined::Environment.method_defined?(:updates).should be_false
32
+ end
33
+
34
+ it "yields the sprocket for configuration" do
35
+ yielded_sprocket = nil
36
+ sprocket = machined.append_sprocket :updates do |updates|
37
+ yielded_sprocket = updates
38
+ end
39
+ yielded_sprocket.should be(sprocket)
40
+ end
41
+
42
+ it "initializes the sprocket with a reference to the Machined environment" do
43
+ sprocket = machined.append_sprocket :updates
44
+ sprocket.machined.should be(machined)
45
+ end
46
+
47
+ it "initializes the sprocket with configuration" do
48
+ sprocket = machined.append_sprocket :updates, :root => "spec/machined"
49
+ sprocket.root.should == File.expand_path("spec/machined")
50
+ end
51
+ end
52
+
53
+ describe "#prepend_sprocket" do
54
+ it "creates a new Sprockets environment" do
55
+ sprocket = machined.prepend_sprocket :updates
56
+ sprocket.should be_a(Sprockets::Environment)
57
+ end
58
+
59
+ it "prepends the sprocket to #sprockets" do
60
+ sprocket = machined.prepend_sprocket :updates
61
+ machined.sprockets.first.should be(sprocket)
62
+ end
63
+ end
64
+
65
+ describe "#helpers" do
66
+ it "adds methods defined in the given block to the Context" do
67
+ machined.helpers do
68
+ def hello
69
+ "world"
70
+ end
71
+ end
72
+ with_context do |context, output|
73
+ context.hello.should == "world"
74
+ end
75
+ end
76
+
77
+ it "adds methods defined in the given module to the Context" do
78
+ helper = Module.new do
79
+ def hello
80
+ "world"
81
+ end
82
+ end
83
+ machined.helpers helper
84
+ with_context do |context, output|
85
+ context.hello.should == "world"
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "default assets sprocket" do
91
+ it "appends the standard asset paths" do
92
+ within_construct do |c|
93
+ c.directory "assets/images"
94
+ c.directory "assets/javascripts"
95
+ c.directory "assets/stylesheets"
96
+ c.directory "vendor/assets/images"
97
+ c.directory "vendor/assets/javascripts"
98
+ c.directory "vendor/assets/stylesheets"
99
+
100
+ machined.assets.paths.should match_paths(%w(
101
+ assets/images
102
+ assets/javascripts
103
+ assets/stylesheets
104
+ vendor/assets/images
105
+ vendor/assets/javascripts
106
+ vendor/assets/stylesheets
107
+ )).with_root(c)
108
+ end
109
+ end
110
+
111
+ it "appends the available asset paths" do
112
+ within_construct do |c|
113
+ c.directory "assets/css"
114
+ c.directory "assets/img"
115
+ c.directory "assets/js"
116
+ c.directory "assets/plugins"
117
+
118
+ machined.assets.paths.should match_paths(%w(
119
+ assets/css
120
+ assets/img
121
+ assets/js
122
+ assets/plugins
123
+ )).with_root(c)
124
+ end
125
+ end
126
+
127
+ it "compiles web assets" do
128
+ within_construct do |c|
129
+ c.file "assets/javascripts/main.js", "//= require dep"
130
+ c.file "assets/javascripts/dep.js", "var app = {};"
131
+ c.file "assets/stylesheets/main.css.scss", "@import 'dep';\nbody { color: $color; }"
132
+ c.file "assets/stylesheets/_dep.scss", "$color: red;"
133
+
134
+ machined.assets["main.js"].to_s.should == "var app = {};\n"
135
+ machined.assets["main.css"].to_s.should == "body {\n color: red; }\n"
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "default pages sprocket" do
141
+ it "appends the pages path" do
142
+ within_construct do |c|
143
+ c.directory "pages"
144
+ machined.pages.paths.should match_paths(%w(pages)).with_root(c)
145
+ end
146
+ end
147
+
148
+ it "compiles html pages" do
149
+ within_construct do |c|
150
+ c.file "pages/index.html.haml", "%h1 Hello World"
151
+ machined.pages["index.html"].to_s.should == "<h1>Hello World</h1>\n"
152
+ end
153
+ end
154
+ end
155
+
156
+ describe "default views sprocket" do
157
+ it "appends the views path" do
158
+ within_construct do |c|
159
+ c.directory "views"
160
+ machined.views.paths.should match_paths(%w(views)).with_root(c)
161
+ end
162
+ end
163
+
164
+ it "compiles html pages" do
165
+ within_construct do |c|
166
+ c.file "views/layouts/main.html.haml", "%h1 Hello World"
167
+ machined.views["layouts/main.html"].to_s.should == "<h1>Hello World</h1>\n"
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "compression" do
173
+ context "with compress set to true" do
174
+ it "compresses javascripts and stylesheets" do
175
+ within_construct do |c|
176
+ c.file "assets/javascripts/main.js", "//= require dep"
177
+ c.file "assets/javascripts/dep.js", "var app = {};"
178
+ c.file "assets/stylesheets/main.css.scss", "@import 'dep';\nbody { color: $color; }"
179
+ c.file "assets/stylesheets/_dep.scss", "$color: red;"
180
+
181
+ Crush::Uglifier.should_receive(:compress).with("var app = {};\n").and_return("compressed")
182
+ Crush::Sass::Engine.should_receive(:compress).with("body {\n color: red; }\n").and_return("compressed")
183
+
184
+ machined :compress => true
185
+ machined.assets["main.js"].to_s.should == "compressed"
186
+ machined.assets["main.css"].to_s.should == "compressed"
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ context "with a js_compressor set" do
193
+ it "compresses using that compressor" do
194
+ within_construct do |c|
195
+ c.file "assets/javascripts/main.js", "var app = {};"
196
+ c.file "machined.rb", "config.js_compressor = :packr"
197
+ Crush::Packr.should_receive(:compress).with("var app = {};\n").and_return("compressed")
198
+ machined.assets["main.js"].to_s.should == "compressed"
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,95 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Helpers::AssetTagHelpers do
4
+ include Machined::Helpers::AssetTagHelpers
5
+
6
+ describe "#asset_path" do
7
+ context "with URIs" do
8
+ it "returns URIs untouched" do
9
+ machined
10
+ asset_path(:js, "https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js").should ==
11
+ "https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"
12
+ asset_path(:js, "http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js").should ==
13
+ "http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"
14
+ asset_path(:js, "//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js").should ==
15
+ "//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"
16
+ end
17
+ end
18
+
19
+ context "with regular files" do
20
+ it "returns absolute paths" do
21
+ machined
22
+ asset_path(:js, "/path/to/file.js").should == "/path/to/file.js"
23
+ asset_path(:images, "/path/to/file.jpg").should == "/path/to/file.jpg"
24
+ end
25
+
26
+ it "appends the extension for javascripts and stylesheets" do
27
+ machined
28
+ asset_path(:js, "/path/to/file").should == "/path/to/file.js"
29
+ asset_path(:css, "/path/to/file").should == "/path/to/file.css"
30
+ asset_path(:images, "/path/to/file").should_not == "/path/to/file.jpg"
31
+ end
32
+
33
+ it "prepends a base URL if missing" do
34
+ machined
35
+ asset_path(:css, "main").should == "/stylesheets/main.css"
36
+ asset_path(:js, "main").should == "/javascripts/main.js"
37
+ asset_path(:images, "logo.jpg").should == "/images/logo.jpg"
38
+ end
39
+
40
+ it "appends a timestamp if the file exists in the output path" do
41
+ within_construct do |c|
42
+ file1 = c.file "public/javascripts/main.js"
43
+ file2 = c.file "public/favicon.ico"
44
+
45
+ mtime1 = Time.now - 600
46
+ file1.utime mtime1, mtime1
47
+ mtime2 = Time.now - 60
48
+ file2.utime mtime2, mtime2
49
+
50
+ machined
51
+ asset_path(:js, "main").should == "/javascripts/main.js?#{mtime1.to_i}"
52
+ asset_path(:images, "/favicon.ico").should == "/favicon.ico?#{mtime2.to_i}"
53
+ end
54
+ end
55
+ end
56
+
57
+ context "with assets" do
58
+ it "prepends a base URL if missing" do
59
+ within_construct do |c|
60
+ c.file "assets/images/logo.jpg"
61
+ c.file "assets/javascripts/main.js"
62
+ c.file "assets/stylesheets/main.css"
63
+
64
+ machined
65
+ asset_path(:css, "main").should =~ %r(^/assets/main\.css)
66
+ asset_path(:js, "main").should =~ %r(^/assets/main\.js)
67
+ asset_path(:images, "logo.jpg").should =~ %r(^/assets/logo\.jpg)
68
+ end
69
+ end
70
+
71
+ it "appends the timestamp of the asset's mtime" do
72
+ within_construct do |c|
73
+ c.file "assets/javascripts/main.js", "//= require dep"
74
+ file = c.file "assets/javascripts/dep.js"
75
+
76
+ mtime = Time.now + 600
77
+ file.utime mtime, mtime
78
+
79
+ asset_path(:js, "main").should == "/assets/main.js?#{mtime.to_i}"
80
+ end
81
+ end
82
+
83
+ it "uses the digest path if configured" do
84
+ within_construct do |c|
85
+ c.file "assets/javascrtips/main.js"
86
+
87
+ machined :digest_assets => true
88
+
89
+ asset = machined.assets["main.js"]
90
+ asset_path(:js, "main").should == "/assets/main-#{asset.digest}.js"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Helpers::LocalsHelpers do
4
+ describe "#locals=" do
5
+ it "sets psuedo local variables" do
6
+ with_context do |context, output|
7
+ context.locals = { :title => "Hello World", :body => nil }
8
+ context.title.should == "Hello World"
9
+ context.body.should be_nil
10
+ end
11
+ end
12
+
13
+ it "responds_to the local variable name" do
14
+ with_context do |context, output|
15
+ context.locals = { :title => "Hello World", :body => nil }
16
+ context.respond_to?(:title).should be_true
17
+ context.respond_to?(:body).should be_true
18
+ end
19
+ end
20
+
21
+ it "still raises errors if the method doesn't exist" do
22
+ with_context do |context, output|
23
+ expect { context.not_a_local }.to raise_error(NoMethodError)
24
+ context.respond_to?(:not_a_local).should be_false
25
+ end
26
+ end
27
+
28
+ it "clears local variables when set to nil" do
29
+ with_context do |context, output|
30
+ context.locals = { :title => "Hello World" }
31
+ context.locals = nil
32
+ expect { context.title }.to raise_error(NoMethodError)
33
+ context.respond_to?(:title).should be_false
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Helpers::OutputHelpers do
4
+ describe "#current_engine" do
5
+ it "returns :haml within a Haml template" do
6
+ within_construct do |c|
7
+ c.file "pages/index.haml", "= current_engine.inspect"
8
+ machined.pages["index"].to_s.should == ":haml\n"
9
+ end
10
+ end
11
+
12
+ it "returns :erb within an ERB template" do
13
+ within_construct do |c|
14
+ c.file "pages/index.erb", "<%= current_engine.inspect %>"
15
+ machined.pages["index"].to_s.should == ":erb"
16
+ end
17
+ end
18
+
19
+ it "returns :erubis within an Erubis template" do
20
+ within_construct do |c|
21
+ c.file "pages/index.erubis", "<%= current_engine.inspect %>"
22
+ machined.pages["index"].to_s.should == ":erubis"
23
+ end
24
+ end
25
+
26
+ it "returns :slim within a Slim template" do
27
+ within_construct do |c|
28
+ c.file "pages/index.slim", "= current_engine.inspect"
29
+ machined.pages["index"].to_s.should == ":slim"
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "#capture and #concat" do
35
+ it "captures blocks in haml" do
36
+ within_construct do |c|
37
+ c.file "pages/index.haml", <<-CONTENT.unindent
38
+ - content_tag :h1 do
39
+ Hello World
40
+ CONTENT
41
+
42
+ machined.pages["index"].to_s.strip.should == "<h1>Hello World\n</h1>"
43
+ end
44
+ end
45
+
46
+ it "captures blocks in erb" do
47
+ within_construct do |c|
48
+ c.file "pages/index.erb", <<-CONTENT.unindent
49
+ <% content_tag :h1 do %>
50
+ Hello World
51
+ <% end %>
52
+ CONTENT
53
+
54
+ machined.pages["index"].to_s.strip.should == "<h1> Hello World\n</h1>"
55
+ end
56
+ end
57
+
58
+ it "captures blocks in erubis" do
59
+ within_construct do |c|
60
+ c.file "pages/index.erubis", <<-CONTENT.unindent
61
+ <% content_tag :h1 do %>
62
+ Hello World
63
+ <% end %>
64
+ CONTENT
65
+
66
+ machined.pages["index"].to_s.strip.should == "<h1> Hello World\n</h1>"
67
+ end
68
+ end
69
+
70
+ it "captures blocks in slim" do
71
+ within_construct do |c|
72
+ c.file "pages/index.slim", <<-CONTENT.unindent
73
+ - content_tag :h1 do
74
+ | Hello World
75
+ CONTENT
76
+
77
+ machined.pages["index"].to_s.strip.should == "<h1>Hello World</h1>"
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ describe Machined::Helpers::RenderHelpers do
4
+ describe "#render" do
5
+ it "renders partials" do
6
+ within_construct do |c|
7
+ c.file "pages/index.html.erb", <<-CONTENT.unindent
8
+ <%= render "partial1" %>
9
+ <%= render "partial2" %>
10
+ <%= render "partials/partial3" %>
11
+ CONTENT
12
+ c.file "views/partial1.md", "# Hello World"
13
+ c.file "views/_partial2.haml", "%p Here's some Content..."
14
+ c.file "views/partials/_partial3.html", "<p>And some more</p>\n"
15
+
16
+ # puts machined.views.paths.inspect
17
+ machined.pages["index.html"].to_s.should == <<-CONTENT.unindent
18
+ <h1>Hello World</h1>
19
+ <p>Here's some Content...</p>
20
+ <p>And some more</p>
21
+ CONTENT
22
+ end
23
+ end
24
+
25
+ it "renders partials with locals" do
26
+ within_construct do |c|
27
+ c.file "pages/index.html.erb", %(<%= render "partial", :text => "Hello World" %>)
28
+ c.file "views/partial.haml", "%h1= text"
29
+
30
+ machined.pages["index.html"].to_s.should == "<h1>Hello World</h1>\n"
31
+ end
32
+ end
33
+
34
+ it "renders partial collections" do
35
+ within_construct do |c|
36
+ c.file "pages/index.html.erb", %(<%= render "number", :collection => [1,2,3] %>)
37
+ c.file "views/number.haml", "= number\n= number_counter"
38
+
39
+ machined.pages["index.html"].to_s.should == "1\n1\n2\n2\n3\n3\n"
40
+ end
41
+ end
42
+
43
+ it "raises a Sprockets::FileNotFound error if the partial is missing" do
44
+ within_construct do |c|
45
+ c.file "pages/index.html.erb", %(<%= render "partial" %>)
46
+
47
+ expect {
48
+ machined.pages["index.html"].to_s
49
+ }.to raise_error(Sprockets::FileNotFound)
50
+ end
51
+ end
52
+ end
53
+ end