machined 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +49 -0
- data/Rakefile +6 -0
- data/bin/machined +4 -0
- data/lib/machined.rb +23 -0
- data/lib/machined/cli.rb +99 -0
- data/lib/machined/context.rb +52 -0
- data/lib/machined/environment.rb +297 -0
- data/lib/machined/helpers/asset_tag_helpers.rb +135 -0
- data/lib/machined/helpers/locals_helpers.rb +57 -0
- data/lib/machined/helpers/output_helpers.rb +43 -0
- data/lib/machined/helpers/render_helpers.rb +138 -0
- data/lib/machined/processors/front_matter_processor.rb +35 -0
- data/lib/machined/processors/layout_processor.rb +71 -0
- data/lib/machined/server.rb +37 -0
- data/lib/machined/sprocket.rb +55 -0
- data/lib/machined/static_compiler.rb +71 -0
- data/lib/machined/templates/site/Gemfile.tt +10 -0
- data/lib/machined/templates/site/assets/images/.empty_directory +0 -0
- data/lib/machined/templates/site/assets/javascripts/main.js.coffee +0 -0
- data/lib/machined/templates/site/assets/stylesheets/main.css.scss +0 -0
- data/lib/machined/templates/site/config.ru +2 -0
- data/lib/machined/templates/site/machined.rb +17 -0
- data/lib/machined/templates/site/pages/index.html.erb +5 -0
- data/lib/machined/templates/site/public/.empty_directory +0 -0
- data/lib/machined/templates/site/views/layouts/main.html.erb +12 -0
- data/lib/machined/utils.rb +31 -0
- data/lib/machined/version.rb +3 -0
- data/machined.gemspec +39 -0
- data/spec/machined/cli_spec.rb +154 -0
- data/spec/machined/context_spec.rb +20 -0
- data/spec/machined/environment_spec.rb +202 -0
- data/spec/machined/helpers/asset_tag_helpers_spec.rb +95 -0
- data/spec/machined/helpers/locals_helper_spec.rb +37 -0
- data/spec/machined/helpers/output_helpers_spec.rb +81 -0
- data/spec/machined/helpers/render_helpers_spec.rb +53 -0
- data/spec/machined/processors/front_matter_processor_spec.rb +42 -0
- data/spec/machined/processors/layout_processor_spec.rb +32 -0
- data/spec/machined/server_spec.rb +77 -0
- data/spec/machined/sprocket_spec.rb +36 -0
- data/spec/machined/static_compiler_spec.rb +85 -0
- data/spec/machined/utils_spec.rb +31 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/helpers.rb +59 -0
- data/spec/support/match_paths_matcher.rb +20 -0
- metadata +389 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
require "rack"
|
2
|
+
|
3
|
+
module Machined
|
4
|
+
class Server
|
5
|
+
# A reference to the Machined environment which
|
6
|
+
# created this instance.
|
7
|
+
attr_reader :machined
|
8
|
+
|
9
|
+
# Creates a new Rack server that will serve
|
10
|
+
# up the processed files.
|
11
|
+
def initialize(machined)
|
12
|
+
@machined = machined
|
13
|
+
@files = Rack::File.new(machined.output_path)
|
14
|
+
remap
|
15
|
+
end
|
16
|
+
|
17
|
+
# Using the URLMap, determine which sprocket
|
18
|
+
# should handle the request and then...let it
|
19
|
+
# handle it.
|
20
|
+
def call(env)
|
21
|
+
response = @url_map.call(env)
|
22
|
+
response = @files.call(env) if response.first == 404
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
# Remaps the Machined environment's current
|
27
|
+
# sprockets using `Rack::URLMap`.
|
28
|
+
def remap
|
29
|
+
map = {}
|
30
|
+
machined.sprockets.each do |sprocket|
|
31
|
+
next unless sprocket.compile?
|
32
|
+
map[sprocket.config.url] = sprocket
|
33
|
+
end
|
34
|
+
@url_map = Rack::URLMap.new map
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "sprockets"
|
3
|
+
|
4
|
+
module Machined
|
5
|
+
class Sprocket < Sprockets::Environment
|
6
|
+
# Default options for a Machined sprocket.
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:root => ".",
|
9
|
+
:assets => false,
|
10
|
+
:compile => true
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# A reference to the Machined environment which
|
14
|
+
# created this instance.
|
15
|
+
attr_reader :machined
|
16
|
+
|
17
|
+
# A reference to the configuration.
|
18
|
+
attr_reader :config
|
19
|
+
|
20
|
+
# Creates a new Machined sprocket. The API is
|
21
|
+
# a bit different than `Sprockets::Environment` to
|
22
|
+
# allow for per-Sprockets-environment configuration
|
23
|
+
# and to keep a reference to the Machined environment.
|
24
|
+
def initialize(machined, options = {})
|
25
|
+
@machined = machined
|
26
|
+
@config = OpenStruct.new DEFAULT_OPTIONS.dup.merge(options)
|
27
|
+
|
28
|
+
super config.root
|
29
|
+
|
30
|
+
@context_class = Class.new Context
|
31
|
+
use_all_templates unless config.assets
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true, if this sprocket should be
|
35
|
+
# compiled. Nine times out of ten, you will want
|
36
|
+
# your sprocket compiled, but sometimes - like
|
37
|
+
# the default views sprocket - it is used as
|
38
|
+
# a uncompiled resource.
|
39
|
+
def compile?
|
40
|
+
config.compile && config.url
|
41
|
+
end
|
42
|
+
|
43
|
+
# Loops through the available Tilt templates
|
44
|
+
# and registers them as processor engines for
|
45
|
+
# Sprockets. By default, Sprockets cherry picks
|
46
|
+
# templates that work for web assets. We need to
|
47
|
+
# allow use of Haml, Markdown, etc.
|
48
|
+
def use_all_templates
|
49
|
+
Utils.available_templates.each do |ext, template|
|
50
|
+
next if engines(ext)
|
51
|
+
register_engine ext, template
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Machined
|
4
|
+
class StaticCompiler
|
5
|
+
# A reference to the Machined environment which
|
6
|
+
# created this instance.
|
7
|
+
attr_reader :machined
|
8
|
+
|
9
|
+
# Creates a new instance, which will compile
|
10
|
+
# the assets to the given +output_path+.
|
11
|
+
def initialize(machined)
|
12
|
+
@machined = machined
|
13
|
+
end
|
14
|
+
|
15
|
+
# Loop through and compile each available
|
16
|
+
# asset to the appropriate output path.
|
17
|
+
def compile
|
18
|
+
compiled_assets = {}
|
19
|
+
machined.sprockets.each do |sprocket|
|
20
|
+
next unless sprocket.compile?
|
21
|
+
sprocket.each_logical_path do |logical_path|
|
22
|
+
url = File.join(sprocket.config.url, logical_path)
|
23
|
+
next unless compiled_assets[url].nil? && compile?(url)
|
24
|
+
|
25
|
+
if asset = sprocket.find_asset(logical_path)
|
26
|
+
compiled_assets[url] = write_asset(asset)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
compiled_assets
|
31
|
+
end
|
32
|
+
|
33
|
+
# Determines if we should precompile the asset
|
34
|
+
# with the given url. By default, we skip over any
|
35
|
+
# files that begin with "_", like partials.
|
36
|
+
def compile?(url)
|
37
|
+
File.basename(url) !~ /^_/
|
38
|
+
end
|
39
|
+
|
40
|
+
# Writes the asset to its destination, also
|
41
|
+
# writing a gzipped version if necessary.
|
42
|
+
def write_asset(asset)
|
43
|
+
filename = path_for(asset)
|
44
|
+
FileUtils.mkdir_p File.dirname(filename)
|
45
|
+
asset.write_to filename
|
46
|
+
asset.write_to "#{filename}.gz" if gzip?(filename)
|
47
|
+
asset.digest
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# Gets the full output path for the given asset.
|
53
|
+
# If it's supposed to include a digest, it will return the
|
54
|
+
# digest_path.
|
55
|
+
def path_for(asset) # :nodoc:
|
56
|
+
path = digest?(asset) ? asset.digest_path : asset.logical_path
|
57
|
+
File.join(machined.output_path, asset.environment.config.url, path)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Determines if we should use the digest_path for the given
|
61
|
+
# asset.
|
62
|
+
def digest?(asset) # :nodoc:
|
63
|
+
machined.config.digest_assets && asset.environment.config.assets
|
64
|
+
end
|
65
|
+
|
66
|
+
# Determines if we should gzip the asset.
|
67
|
+
def gzip?(filename) # :nodoc:
|
68
|
+
machined.config.gzip_assets && filename =~ /\.(css|js)$/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.require :default, config.environment.to_sym
|
3
|
+
|
4
|
+
if config.environment == "production"
|
5
|
+
# Compress javascripts and stylesheets
|
6
|
+
config.compress = true
|
7
|
+
|
8
|
+
# Generate digests for assets URLs
|
9
|
+
# config.digest_assets = true
|
10
|
+
|
11
|
+
# Create gzipped versions of javascripts and stylesheets
|
12
|
+
# config.gzip_assets = true
|
13
|
+
end
|
14
|
+
|
15
|
+
helpers do
|
16
|
+
# Define helper methods here
|
17
|
+
end
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "sprockets"
|
3
|
+
require "tilt"
|
4
|
+
|
5
|
+
module Machined
|
6
|
+
module Utils
|
7
|
+
# Returns a hash of the Tilt templates
|
8
|
+
# that are registered and available to use, where
|
9
|
+
# the key is the extension the template's registered for.
|
10
|
+
def self.available_templates
|
11
|
+
@available_templates ||= {}.tap do |templates|
|
12
|
+
Tilt.mappings.each_key do |ext|
|
13
|
+
begin
|
14
|
+
templates[Sprockets::Utils.normalize_extension(ext)] = Tilt[ext]
|
15
|
+
rescue LoadError
|
16
|
+
# safely ignore...
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns an `Array` of the child directories that
|
23
|
+
# exist within the given +path+. If the path itself
|
24
|
+
# does not exist, an emtpy array is returned.
|
25
|
+
def self.existent_directories(path)
|
26
|
+
pathname = Pathname.new path
|
27
|
+
pathname.directory? or return []
|
28
|
+
pathname.children.select &:directory?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/machined.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "machined/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "machined"
|
7
|
+
s.version = Machined::VERSION
|
8
|
+
s.authors = ["Pete Browne"]
|
9
|
+
s.email = ["me@petebrowne.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{A static site generator and Rack server built using Sprockets 2.0}
|
12
|
+
s.description = %q{Why another static site generator? Machined is for the developers who know and love the asset pipeline of Rails 3.1 and want to develop blazingly fast static websites. It's built from the ground up using Sprockets 2.0.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "machined"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "sprockets", "~> 2.0"
|
22
|
+
s.add_dependency "sprockets-sass", "~> 0.3"
|
23
|
+
s.add_dependency "padrino-helpers", "~> 0.10"
|
24
|
+
s.add_dependency "activesupport", "~> 3.1"
|
25
|
+
s.add_dependency "i18n", "~> 0.6"
|
26
|
+
s.add_dependency "thor", "~> 0.14"
|
27
|
+
s.add_dependency "crush", "~> 0.3"
|
28
|
+
s.add_development_dependency "rspec", "~> 2.6"
|
29
|
+
s.add_development_dependency "rack-test", "~> 0.6"
|
30
|
+
s.add_development_dependency "test-construct", "~> 1.2"
|
31
|
+
s.add_development_dependency 'unindent', "~> 1.0"
|
32
|
+
s.add_development_dependency "haml"
|
33
|
+
s.add_development_dependency "sass"
|
34
|
+
s.add_development_dependency "slim"
|
35
|
+
s.add_development_dependency "erubis"
|
36
|
+
s.add_development_dependency "rdiscount"
|
37
|
+
s.add_development_dependency "uglifier"
|
38
|
+
s.add_development_dependency "rake"
|
39
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Machined::CLI do
|
4
|
+
describe "#compile" do
|
5
|
+
it "compiles the site" do
|
6
|
+
machined.should_receive(:compile)
|
7
|
+
Machined::Environment.should_receive(:new).with(:root => ".", :output_path => "public", :environment => "production", :config_path => "machined.rb").and_return(machined)
|
8
|
+
machined_cli "compile -e production"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#new" do
|
13
|
+
it "creates a machined site directory" do
|
14
|
+
within_construct do |c|
|
15
|
+
machined_cli "new my_site"
|
16
|
+
File.directory?("my_site").should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "creates source directories" do
|
21
|
+
within_construct do |c|
|
22
|
+
machined_cli "new my_site"
|
23
|
+
File.directory?("my_site/pages").should be_true
|
24
|
+
File.directory?("my_site/views").should be_true
|
25
|
+
File.directory?("my_site/assets/images").should be_true
|
26
|
+
File.directory?("my_site/assets/javascripts").should be_true
|
27
|
+
File.directory?("my_site/assets/stylesheets").should be_true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates an output path" do
|
32
|
+
within_construct do |c|
|
33
|
+
machined_cli "new my_site"
|
34
|
+
File.directory?("my_site/public").should be_true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "creates an default index page" do
|
39
|
+
within_construct do |c|
|
40
|
+
machined_cli "new my_site"
|
41
|
+
File.read("my_site/pages/index.html.erb").should == <<-CONTENT.unindent
|
42
|
+
---
|
43
|
+
title: Home Page
|
44
|
+
---
|
45
|
+
<h1><%= title %></h1>
|
46
|
+
<p>Find me in pages/index.erb</p>
|
47
|
+
CONTENT
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'creates a default layout' do
|
52
|
+
within_construct do |c|
|
53
|
+
machined_cli "new my_site"
|
54
|
+
File.read("my_site/views/layouts/main.html.erb").should == <<-CONTENT.unindent
|
55
|
+
<!doctype html>
|
56
|
+
<html>
|
57
|
+
<head lang="en">
|
58
|
+
<meta charset="utf-8">
|
59
|
+
<title><%= title %></title>
|
60
|
+
<%= stylesheet_link_tag "main" %>
|
61
|
+
<%= javascript_include_tag "main" %>
|
62
|
+
</head>
|
63
|
+
<body>
|
64
|
+
<%= yield %>
|
65
|
+
</body>
|
66
|
+
</html>
|
67
|
+
CONTENT
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "creates a default javascript file" do
|
72
|
+
within_construct do |c|
|
73
|
+
machined_cli "new my_site"
|
74
|
+
File.exist?("my_site/assets/javascripts/main.js.coffee").should be_true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "creates a default stylesheet file" do
|
79
|
+
within_construct do |c|
|
80
|
+
machined_cli "new my_site"
|
81
|
+
File.exist?("my_site/assets/stylesheets/main.css.scss").should be_true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "creates a default Gemfile" do
|
86
|
+
within_construct do |c|
|
87
|
+
machined_cli "new my_site"
|
88
|
+
File.read("my_site/Gemfile").should == <<-CONTENT.unindent
|
89
|
+
source :rubygems
|
90
|
+
|
91
|
+
gem "machined", "#{Machined::VERSION}"
|
92
|
+
|
93
|
+
gem "sass", "~> 3.1"
|
94
|
+
gem "coffee-script", "~> 2.2"
|
95
|
+
|
96
|
+
group :production do
|
97
|
+
gem "uglifier", "~> 1.0"
|
98
|
+
end
|
99
|
+
CONTENT
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "creates a default config file" do
|
104
|
+
within_construct do |c|
|
105
|
+
machined_cli "new my_site"
|
106
|
+
File.read("my_site/machined.rb").should == <<-CONTENT.unindent
|
107
|
+
require "bundler"
|
108
|
+
Bundler.require :default, config.environment.to_sym
|
109
|
+
|
110
|
+
if config.environment == "production"
|
111
|
+
# Compress javascripts and stylesheets
|
112
|
+
config.compress = true
|
113
|
+
|
114
|
+
# Generate digests for assets URLs
|
115
|
+
# config.digest_assets = true
|
116
|
+
|
117
|
+
# Create gzipped versions of javascripts and stylesheets
|
118
|
+
# config.gzip_assets = true
|
119
|
+
end
|
120
|
+
|
121
|
+
helpers do
|
122
|
+
# Define helper methods here
|
123
|
+
end
|
124
|
+
CONTENT
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "creates a default rackup file" do
|
129
|
+
within_construct do |c|
|
130
|
+
machined_cli "new my_site"
|
131
|
+
File.read("my_site/config.ru").should == <<-CONTENT.unindent
|
132
|
+
require "machined"
|
133
|
+
run Machined::Environment.new
|
134
|
+
CONTENT
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#server" do
|
140
|
+
it "should start a Rack server" do
|
141
|
+
app = machined
|
142
|
+
Machined::Environment.should_receive(:new).with(:root => ".", :output_path => "site", :environment => "production", :config_path => "machined.rb").and_return(app)
|
143
|
+
Rack::Server.should_receive(:start).with(hash_including(:app => app, :environment => "production", :Port => 5000))
|
144
|
+
machined_cli "server -o site -e production -p 5000"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "#version" do
|
149
|
+
it "prints out the current version number" do
|
150
|
+
output = machined_cli "version"
|
151
|
+
output.strip.should == Machined::VERSION
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|