massimo 0.4.6 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/massimo +5 -3
- data/lib/massimo/cli.rb +101 -0
- data/lib/massimo/config.rb +56 -0
- data/lib/massimo/helpers.rb +12 -19
- data/lib/massimo/javascript.rb +18 -19
- data/lib/massimo/page.rb +63 -70
- data/lib/massimo/resource.rb +92 -0
- data/lib/massimo/server.rb +27 -0
- data/lib/massimo/site.rb +64 -101
- data/lib/massimo/stylesheet.rb +13 -35
- data/lib/massimo/view.rb +5 -32
- data/lib/massimo/watcher.rb +52 -0
- data/lib/massimo.rb +22 -31
- metadata +172 -117
- data/.document +0 -5
- data/.gitignore +0 -25
- data/Gemfile +0 -13
- data/Rakefile +0 -62
- data/lib/massimo/command.rb +0 -243
- data/lib/massimo/resource/base.rb +0 -74
- data/lib/massimo/resource/collection.rb +0 -56
- data/lib/massimo/resource/processing.rb +0 -67
- data/lib/massimo/templates.rb +0 -22
- data/massimo.gemspec +0 -135
- data/test/assertions.rb +0 -8
- data/test/helper.rb +0 -64
- data/test/source/config.yml +0 -4
- data/test/source/helpers/test_helper.rb +0 -5
- data/test/source/javascripts/_plugin.js +0 -1
- data/test/source/javascripts/application.js +0 -3
- data/test/source/javascripts/lib.js +0 -1
- data/test/source/lib/site.rb +0 -5
- data/test/source/pages/_skipped_page.haml +0 -0
- data/test/source/pages/about_us.erb +0 -5
- data/test/source/pages/erb.erb +0 -5
- data/test/source/pages/erb_with_layout.erb +0 -4
- data/test/source/pages/feed.haml +0 -6
- data/test/source/pages/haml.haml +0 -5
- data/test/source/pages/html.html +0 -4
- data/test/source/pages/index.erb +0 -4
- data/test/source/pages/markdown.markdown +0 -5
- data/test/source/pages/posts/first-post.haml +0 -1
- data/test/source/pages/with_extension.haml +0 -4
- data/test/source/pages/with_meta_data.haml +0 -7
- data/test/source/pages/with_title.haml +0 -4
- data/test/source/pages/with_url.haml +0 -4
- data/test/source/pages/without_extension.haml +0 -0
- data/test/source/pages/without_meta_data.haml +0 -1
- data/test/source/pages/without_title.haml +0 -1
- data/test/source/pages/without_url.haml +0 -1
- data/test/source/stylesheets/_base.sass +0 -2
- data/test/source/stylesheets/application.sass +0 -4
- data/test/source/stylesheets/basic.css +0 -3
- data/test/source/stylesheets/less_file.less +0 -5
- data/test/source/views/layouts/application.haml +0 -2
- data/test/source/views/with_helper.haml +0 -1
- data/test/source/views/with_locals.haml +0 -1
- data/test/source/views/without_locals.haml +0 -1
- data/test/test_helpers.rb +0 -25
- data/test/test_javascript.rb +0 -30
- data/test/test_page.rb +0 -142
- data/test/test_resource.rb +0 -70
- data/test/test_site.rb +0 -125
- data/test/test_stylesheet.rb +0 -40
- data/test/test_view.rb +0 -50
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/bin/massimo
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require File.expand_path("../../lib/massimo/command", __FILE__)
|
3
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
5
4
|
|
6
|
-
|
5
|
+
require 'massimo'
|
6
|
+
require 'massimo/cli'
|
7
|
+
|
8
|
+
Massimo::CLI.start
|
data/lib/massimo/cli.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module Massimo
|
6
|
+
class CLI < Thor
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
default_task :build
|
10
|
+
class_option 'config', :desc => 'Path to the config file', :aliases => '-c'
|
11
|
+
class_option 'source_path', :desc => 'Path to the source dir', :aliases => '-s'
|
12
|
+
class_option 'output_path', :desc => 'Path to the output dir', :aliases => '-o'
|
13
|
+
|
14
|
+
desc 'build', 'Builds the site'
|
15
|
+
def build
|
16
|
+
site.process
|
17
|
+
say 'massimo has built your site'
|
18
|
+
end
|
19
|
+
map 'b' => :build
|
20
|
+
|
21
|
+
desc 'watch', 'Watches your files for changes and rebuilds'
|
22
|
+
def watch
|
23
|
+
begin
|
24
|
+
say 'massimo is watching your files for changes'
|
25
|
+
Massimo::Watcher.start(site)
|
26
|
+
rescue Interrupt
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
map 'w' => :watch
|
31
|
+
|
32
|
+
desc 'server [PORT]', 'Runs a local web server and processes the site on save'
|
33
|
+
def server(port = 3000)
|
34
|
+
say "massimo is serving your site at http://localhost:#{port}"
|
35
|
+
Massimo::Server.start(site, port.to_i)
|
36
|
+
end
|
37
|
+
map 's' => :server
|
38
|
+
|
39
|
+
desc 'generate SITE_OR_RESOURCE [FILE]', 'Generates a new site. Optionally generates a resource file.'
|
40
|
+
method_option 'page_ext',
|
41
|
+
:desc => 'The extension used for generated Pages and Views',
|
42
|
+
:default => 'haml',
|
43
|
+
:aliases => '--page'
|
44
|
+
method_option 'javascript_ext',
|
45
|
+
:desc => 'The extension used for generated Javascripts',
|
46
|
+
:default => 'js',
|
47
|
+
:aliases => '--js'
|
48
|
+
method_option 'stylesheet_ext',
|
49
|
+
:desc => 'The extension used for generated Stylesheets',
|
50
|
+
:default => 'sass',
|
51
|
+
:aliases => '--css'
|
52
|
+
def generate(site_or_resource, file = nil)
|
53
|
+
require 'active_support/inflector'
|
54
|
+
|
55
|
+
if file
|
56
|
+
create_file File.join(site.config.path_for(resource.pluralize), file)
|
57
|
+
else
|
58
|
+
empty_directory site_or_resource
|
59
|
+
inside site_or_resource do
|
60
|
+
site.resources.each do |resource|
|
61
|
+
empty_directory(resource.path)
|
62
|
+
end
|
63
|
+
create_file File.join(Massimo::Page.path, "index.#{options[:page_ext]}")
|
64
|
+
create_file File.join(Massimo::Javascript.path, "main.#{options[:javascript_ext]}")
|
65
|
+
create_file File.join(Massimo::Stylesheet.path, "main.#{options[:stylesheet_ext]}")
|
66
|
+
create_file File.join(Massimo::View.path, "layouts/main.#{options[:page_ext]}")
|
67
|
+
empty_directory site.config.output_path
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
map 'g' => :generate
|
72
|
+
|
73
|
+
desc 'version', 'Displays current version'
|
74
|
+
def version
|
75
|
+
say Massimo::VERSION
|
76
|
+
end
|
77
|
+
map %w( -v --version ) => :version
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def site
|
82
|
+
@site ||= begin
|
83
|
+
site = Massimo::Site.new config_file(:yml)
|
84
|
+
if config_rb = config_file(:rb)
|
85
|
+
site.instance_eval File.read(config_rb)
|
86
|
+
end
|
87
|
+
site.config.source_path = options[:source_path] if options[:source_path]
|
88
|
+
site.config.output_path = options[:output_path] if options[:output_path]
|
89
|
+
site
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def config_file(ext)
|
94
|
+
if options[:config] && File.extname(options[:config]) == ".#{ext}"
|
95
|
+
options[:config]
|
96
|
+
elsif File.exist?("config.#{ext}")
|
97
|
+
"config.#{ext}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Massimo
|
6
|
+
class Config < OpenStruct
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:source_path => '.',
|
9
|
+
:output_path => 'public',
|
10
|
+
:resources_path => '.',
|
11
|
+
:resources_url => '/',
|
12
|
+
:javascripts_url => '/javascripts',
|
13
|
+
:stylesheets_url => '/stylesheets',
|
14
|
+
:resources_url => '/'
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def initialize(options = nil)
|
18
|
+
hash = DEFAULT_OPTIONS.dup
|
19
|
+
|
20
|
+
options = YAML.load_file(options) if options.is_a?(String)
|
21
|
+
hash.merge!(options.symbolize_keys) if options.is_a?(Hash)
|
22
|
+
|
23
|
+
super hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def source_path
|
27
|
+
File.expand_path(super)
|
28
|
+
end
|
29
|
+
|
30
|
+
def output_path
|
31
|
+
File.expand_path(super)
|
32
|
+
end
|
33
|
+
|
34
|
+
def path_for(resource_name)
|
35
|
+
path_method = "#{resource_name}_path"
|
36
|
+
if resource_path = (respond_to?(path_method) and send(path_method))
|
37
|
+
File.expand_path(resource_path)
|
38
|
+
else
|
39
|
+
File.join(source_path, resource_name.to_s)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def url_for(resource_name)
|
44
|
+
url_method = "#{resource_name}_url"
|
45
|
+
if resource_url = (respond_to?(url_method) and send(url_method))
|
46
|
+
resource_url
|
47
|
+
else
|
48
|
+
resources_url
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def files_in(resource_name, extension = '*')
|
53
|
+
Dir.glob(File.join(path_for(resource_name), "**/*.#{extension}"))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/massimo/helpers.rb
CHANGED
@@ -1,28 +1,21 @@
|
|
1
|
-
|
1
|
+
require 'rack/utils' # needed for sinatra_more...
|
2
|
+
require 'sinatra_more/markup_plugin'
|
2
3
|
|
3
4
|
module Massimo
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
include SinatraMore::FormatHelpers
|
11
|
-
end
|
12
|
-
|
13
|
-
#
|
14
|
-
def initialize(modules = nil)
|
15
|
-
extend(*modules) unless modules.nil? || modules.empty?
|
16
|
-
end
|
5
|
+
module Helpers
|
6
|
+
include SinatraMore::OutputHelpers
|
7
|
+
include SinatraMore::TagHelpers
|
8
|
+
include SinatraMore::AssetTagHelpers
|
9
|
+
include SinatraMore::FormHelpers
|
10
|
+
include SinatraMore::FormatHelpers
|
17
11
|
|
18
|
-
# Gets the site instance
|
19
12
|
def site
|
20
|
-
Massimo
|
13
|
+
Massimo.site
|
21
14
|
end
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
def render(view_name, locals = {})
|
17
|
+
view = Massimo::View.find(view_name)
|
18
|
+
view && view.render(locals)
|
26
19
|
end
|
27
20
|
end
|
28
21
|
end
|
data/lib/massimo/javascript.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
|
-
require "jsmin"
|
2
|
-
require "sprockets"
|
3
|
-
require "massimo/resource/base"
|
4
|
-
|
5
1
|
module Massimo
|
6
|
-
class Javascript < Massimo::Resource
|
7
|
-
processable!
|
8
|
-
|
9
|
-
# Concat the Javascript using Sprockets, then minify using JSmin
|
2
|
+
class Javascript < Massimo::Resource
|
10
3
|
def render
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
4
|
+
case source_path.extname.to_s
|
5
|
+
when '.coffee'
|
6
|
+
require 'coffee-script' unless defined?(CoffeeScript)
|
7
|
+
CoffeeScript.compile(content)
|
8
|
+
else
|
9
|
+
require 'sprockets' unless defined?(Sprockets)
|
10
|
+
secretary = Sprockets::Secretary.new(
|
11
|
+
:assert_root => Massimo.config.output_path,
|
12
|
+
:source_files => [ source_path.to_s ]
|
13
|
+
)
|
14
|
+
secretary.install_assets
|
15
|
+
secretary.concatenation.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def extension
|
20
|
+
@extension ||= '.js'
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
data/lib/massimo/page.rb
CHANGED
@@ -1,97 +1,90 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'tilt'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
Tilt.register 'html', Tilt::StringTemplate
|
5
7
|
|
6
8
|
module Massimo
|
7
|
-
class Page <
|
8
|
-
|
9
|
+
class Page < Resource
|
10
|
+
def render
|
11
|
+
template = Tilt.new(source_path.basename.to_s, @line || 1) { content }
|
12
|
+
meta_data = @meta_data.merge(self.class.resource_name.singularize.to_sym => self)
|
13
|
+
output = template.render(Massimo.site.template_scope, meta_data)
|
14
|
+
if found_layout = Massimo::View.find("layouts/#{layout}")
|
15
|
+
output = found_layout.render(:page => self) { output }
|
16
|
+
end
|
17
|
+
output
|
18
|
+
end
|
9
19
|
|
10
|
-
|
20
|
+
def title
|
21
|
+
@meta_data[:title] ||= source_path.basename.to_s.chomp(source_path.extname.to_s).titleize
|
22
|
+
end
|
11
23
|
|
12
|
-
|
13
|
-
|
14
|
-
super(source_path, {
|
15
|
-
:title => File.basename(source_path).gsub(File.extname(source_path), "").titleize,
|
16
|
-
:extension => ".html",
|
17
|
-
:url => source_path.gsub(self.class.dir, "").gsub(File.extname(source_path), "").dasherize,
|
18
|
-
:layout => "application"
|
19
|
-
})
|
24
|
+
def extension
|
25
|
+
@meta_data[:extension] ||= '.html'
|
20
26
|
end
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
def url
|
29
|
+
@meta_data[:url] ||= begin
|
30
|
+
url = super
|
31
|
+
url.chomp!('index.html')
|
32
|
+
url.sub!(/\.html$/, '/')
|
33
|
+
url
|
27
34
|
end
|
28
|
-
output
|
29
35
|
end
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
def layout
|
38
|
+
@meta_data[:layout] = 'main' if @meta_data[:layout].nil?
|
39
|
+
@meta_data[:layout]
|
40
|
+
end
|
41
|
+
|
42
|
+
def output_path
|
43
|
+
@output_path ||= begin
|
44
|
+
output_path = super.to_s
|
45
|
+
output_path << "index.html" if output_path =~ /\/$/
|
46
|
+
Pathname.new output_path
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
50
|
protected
|
37
51
|
|
38
|
-
|
39
|
-
# `@body` attributes.
|
40
|
-
def read_source!
|
41
|
-
# read the source file and setup some values for the loop
|
42
|
-
source = super()
|
52
|
+
def read_source
|
43
53
|
@line = nil
|
54
|
+
@content = ''
|
44
55
|
front_matter = false
|
45
|
-
meta_data =
|
46
|
-
body = ""
|
56
|
+
meta_data = ''
|
47
57
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
front_matter = !front_matter
|
53
|
-
else
|
54
|
-
if front_matter
|
55
|
-
meta_data << line
|
58
|
+
source_path.open do |file|
|
59
|
+
file.each do |line|
|
60
|
+
if line =~ /\A---\s*\Z/
|
61
|
+
front_matter = !front_matter
|
56
62
|
else
|
57
|
-
|
58
|
-
|
63
|
+
if front_matter
|
64
|
+
meta_data << line
|
65
|
+
else
|
66
|
+
@line ||= file.lineno
|
67
|
+
@content << line
|
68
|
+
end
|
59
69
|
end
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
63
|
-
|
64
|
-
meta_data = YAML.load(meta_data)
|
65
|
-
@meta_data.merge!(meta_data.symbolize_keys) if meta_data
|
66
|
-
@body = body
|
73
|
+
@meta_data = (YAML.load(meta_data) || {}).symbolize_keys
|
67
74
|
end
|
68
75
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
def method_missing(method, *args, &block)
|
77
|
+
if args.length == 0
|
78
|
+
read_source
|
79
|
+
method_name = method.to_s
|
80
|
+
if method_name.chomp! '?'
|
81
|
+
!!@meta_data[method_name.to_sym]
|
82
|
+
else
|
83
|
+
@meta_data[method_name.to_sym]
|
84
|
+
end
|
85
|
+
else
|
86
|
+
super
|
79
87
|
end
|
80
88
|
end
|
81
|
-
|
82
|
-
# Determines if this is an index page
|
83
|
-
def index?
|
84
|
-
@source_path.basename.to_s =~ /^index/
|
85
|
-
end
|
86
|
-
|
87
|
-
# Determines if this an HTML page.
|
88
|
-
def html?
|
89
|
-
extension =~ /(html|php)$/
|
90
|
-
end
|
91
|
-
|
92
|
-
# Finds the Layout View if it exists
|
93
|
-
def find_layout
|
94
|
-
site.find_view("layouts/#{layout}") unless layout == false
|
95
|
-
end
|
96
89
|
end
|
97
90
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Massimo
|
6
|
+
class Resource
|
7
|
+
class << self
|
8
|
+
def resource_name
|
9
|
+
self.name.underscore.sub(/.*\//, '').pluralize
|
10
|
+
end
|
11
|
+
|
12
|
+
def path
|
13
|
+
Massimo.config.path_for resource_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def url
|
17
|
+
Massimo.config.url_for resource_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def find(name)
|
21
|
+
resource_path = Dir.glob(File.join(path, "#{name}.*")).first
|
22
|
+
resource_path && self.new(resource_path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def all
|
26
|
+
files = Massimo.config.files_in resource_name
|
27
|
+
files.reject! { |file| File.basename(file) =~ /^_/ }
|
28
|
+
files.map { |file| self.new(file) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def processable?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def unprocessable
|
38
|
+
def self.processable?; false; end
|
39
|
+
define_method(:process) { false }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader :source_path, :content
|
44
|
+
|
45
|
+
def initialize(source)
|
46
|
+
@source_path = source.is_a?(Pathname) ? source.expand_path : Pathname.new(source).expand_path
|
47
|
+
read_source
|
48
|
+
end
|
49
|
+
|
50
|
+
def filename
|
51
|
+
@filename ||= source_path.basename.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def extension
|
55
|
+
@extension ||= source_path.extname
|
56
|
+
end
|
57
|
+
|
58
|
+
def url
|
59
|
+
@url ||= begin
|
60
|
+
url = source_path.to_s.sub(/^#{Regexp.escape(self.class.path)}/, '')
|
61
|
+
url = url.sub(/\.[^\.]+$/, extension)
|
62
|
+
url = File.join(self.class.url, url) unless url.include? self.class.url
|
63
|
+
url = url.dasherize
|
64
|
+
url
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# The path to the output file.
|
69
|
+
def output_path
|
70
|
+
@output_path ||= Pathname.new File.join(Massimo.config.output_path, url)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Runs the content through any necessary filters, templates, etc.
|
74
|
+
def render
|
75
|
+
content
|
76
|
+
end
|
77
|
+
|
78
|
+
# Writes the rendered content to the output file.
|
79
|
+
def process
|
80
|
+
FileUtils.mkdir_p(output_path.dirname)
|
81
|
+
output_path.open('w') do |f|
|
82
|
+
f.write render
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def read_source
|
89
|
+
@content = source_path.read
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Massimo
|
4
|
+
class Server
|
5
|
+
class << self
|
6
|
+
def start(site, port = 3000)
|
7
|
+
app = Rack::Builder.new do
|
8
|
+
use Rack::ShowExceptions
|
9
|
+
run Massimo::Server.new(site)
|
10
|
+
end
|
11
|
+
Rack::Handler::WEBrick.run(app, :Port => port)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(site)
|
16
|
+
@site = site
|
17
|
+
@file_server = Rack::File.new(site.config.output_path)
|
18
|
+
@watcher = Massimo::Watcher.new(site)
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
@watcher.process
|
23
|
+
env['PATH_INFO'] << 'index.html' if env['PATH_INFO'] =~ /\/$/
|
24
|
+
@file_server.call(env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|