nanoc 1.4 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,10 @@
1
+ == 1.5
2
+
3
+ * Added support for custom filters
4
+ * Improved Liquid support -- Liquid is now a first-class nanoc citizen
5
+ * Deprecated assets -- use something like rsync instead
6
+ * Added eruby_engine option, which can be 'erb' or 'erubis'
7
+
1
8
  == 1.4
2
9
 
3
10
  * nanoc now supports ERB (as well as Erubis); Erubis no longer is a dependency
data/README CHANGED
@@ -7,31 +7,9 @@ Markdown, etc.
7
7
 
8
8
  == Documentation
9
9
 
10
- nanoc has a web site at <http://stoneship.org/software/nanoc/>, which contains
11
- a "Getting Started" guide as well as a reference for nanoc.
10
+ nanoc has a web site at <http://nanoc.stoneship.org/>, which contains a
11
+ "Getting Started" guide as well as a reference for nanoc.
12
12
 
13
13
  == Contact
14
14
 
15
15
  You can reach me at <denis.defreyne@stoneship.org>.
16
-
17
- == Copyright
18
-
19
- Copyright (c) 2007 Denis Defreyne
20
-
21
- Permission is hereby granted, free of charge, to any person obtaining a copy
22
- of this software and associated documentation files (the "Software"), to deal
23
- in the Software without restriction, including without limitation the rights
24
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
- copies of the Software, and to permit persons to whom the Software is
26
- furnished to do so, subject to the following conditions:
27
-
28
- The above copyright notice and this permission notice shall be included in all
29
- copies or substantial portions of the Software.
30
-
31
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
- SOFTWARE.
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ NAME = 'nanoc'
12
12
  VERS = Nanoc::VERSION
13
13
  SUMMARY = 'a CMS that doesn\'t run on your server'
14
14
 
15
- HOMEPAGE = 'http://stoneship.org/software/nanoc'
15
+ HOMEPAGE = 'http://nanoc.stoneship.org/'
16
16
  EMAIL = 'denis.defreyne@stoneship.org'
17
17
 
18
18
  #####
data/bin/nanoc CHANGED
@@ -69,7 +69,7 @@ case command
69
69
  $stderr.puts 'Usage: nanoc create_site [site_name]'
70
70
  exit
71
71
  end
72
- Nanoc::Creator.create_site(ARGV[1])
72
+ $nanoc_creator.create_site(ARGV[1])
73
73
 
74
74
  # Create page
75
75
  when 'create_page', 'cp'
@@ -77,7 +77,7 @@ case command
77
77
  $stderr.puts 'Usage: nanoc create_page [page_name]'
78
78
  exit
79
79
  end
80
- Nanoc::Creator.create_page(ARGV[1], :template => unprocessed_opts['--template'])
80
+ $nanoc_creator.create_page(ARGV[1], :template => unprocessed_opts['--template'])
81
81
 
82
82
  # Create template
83
83
  when 'create_template', 'ct'
@@ -85,7 +85,7 @@ case command
85
85
  $stderr.puts 'Usage: nanoc create_template [template_name]'
86
86
  exit
87
87
  end
88
- Nanoc::Creator.create_template(ARGV[1])
88
+ $nanoc_creator.create_template(ARGV[1])
89
89
 
90
90
  # Process site and generate output
91
91
  when 'compile', 'compile_site', 'co'
@@ -93,7 +93,7 @@ case command
93
93
  $stderr.puts 'Usage: nanoc compile'
94
94
  exit
95
95
  end
96
- Nanoc::Compiler.new.run
96
+ $nanoc_compiler.run
97
97
 
98
98
  else
99
99
  puts 'Unrecognised command \'' + command + '\''
data/lib/nanoc.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Nanoc
2
- VERSION = '1.4'
2
+
3
+ VERSION = '1.5'
3
4
 
4
5
  def self.ensure_in_site
5
6
  unless in_site?
@@ -23,9 +24,16 @@ module Nanoc
23
24
 
24
25
  true
25
26
  end
27
+
26
28
  end
27
29
 
28
- require File.dirname(__FILE__) + '/page.rb'
29
- require File.dirname(__FILE__) + '/creator.rb'
30
- require File.dirname(__FILE__) + '/compiler.rb'
31
- require File.dirname(__FILE__) + '/enhancements.rb'
30
+ require File.dirname(__FILE__) + '/nanoc/creator.rb'
31
+ require File.dirname(__FILE__) + '/nanoc/compiler.rb'
32
+
33
+ $nanoc_creator = Nanoc::Creator.new
34
+ $nanoc_compiler = Nanoc::Compiler.new
35
+
36
+ require File.dirname(__FILE__) + '/nanoc/core_ext.rb'
37
+ require File.dirname(__FILE__) + '/nanoc/enhancements.rb'
38
+ require File.dirname(__FILE__) + '/nanoc/filters.rb'
39
+ require File.dirname(__FILE__) + '/nanoc/page.rb'
@@ -1,7 +1,10 @@
1
1
  module Nanoc
2
2
  class Compiler
3
3
 
4
- DEFAULT_CONFIG = { :output_dir => 'output' }
4
+ DEFAULT_CONFIG = {
5
+ :output_dir => 'output',
6
+ :eruby_engine => 'erb'
7
+ }
5
8
 
6
9
  FILE_TYPES = {
7
10
  '.erb' => :eruby,
@@ -21,13 +24,17 @@ module Nanoc
21
24
  }
22
25
 
23
26
  def initialize
27
+ @filters = {}
28
+ end
29
+
30
+ def run
31
+ # Make sure we're in a nanoc site
24
32
  Nanoc.ensure_in_site
25
33
 
34
+ # Load some configuration stuff
26
35
  @config = DEFAULT_CONFIG.merge(YAML.load_file_and_clean('config.yaml'))
27
36
  @global_page = PAGE_DEFAULTS.merge(YAML.load_file_and_clean('meta.yaml'))
28
- end
29
37
 
30
- def run
31
38
  # Require all Ruby source files in lib/
32
39
  Dir['lib/*.rb'].each { |f| require f }
33
40
 
@@ -37,33 +44,56 @@ module Nanoc
37
44
  # Copy assets to output directory
38
45
  copy_assets
39
46
 
40
- # Compile all pages
41
- pages = compile_pages(uncompiled_pages)
47
+ # Compile and layout pages
48
+ pages = find_uncompiled_pages
49
+ pages = layout(compile(pages))
50
+ end
42
51
 
43
- # Put pages in their layouts
44
- pages.each do |page|
45
- # Skip pages that should not be outputed
46
- next if page.skip_output
52
+ def register_filter(name, &block)
53
+ @filters[name.to_sym] = block
54
+ end
47
55
 
48
- begin
49
- # Prepare layout content
50
- content = layouted_page(page, pages)
56
+ def filter_named(name)
57
+ @filters[name.to_sym]
58
+ end
51
59
 
52
- # Write page with layout
53
- FileManager.create_file(path_for_page(page)) { content }
54
- rescue => exception
55
- p = page[:_content_filename]
56
- l = page[:layout]
57
- handle_exception(exception, "layouting page '#{p}' in layout '#{l}'")
58
- end
60
+ def config
61
+ @config
62
+ end
63
+
64
+ private
59
65
 
66
+ # Returns the path for the given page
67
+ def path_for_page(page)
68
+ if page.attributes[:custom_path].nil?
69
+ @config[:output_dir] + page.attributes[:path] +
70
+ page.attributes[:filename] + '.' + page.attributes[:extension]
71
+ else
72
+ @config[:output_dir] + page.attributes[:custom_path]
60
73
  end
61
74
  end
62
75
 
63
- private
76
+ # Returns the layout for the given page
77
+ def layout_for_page(page)
78
+ if page.attributes[:layout].nil?
79
+ { :type => :eruby, :content => "<%= @page.content %>" }
80
+ else
81
+ filenames = Dir["layouts/#{page.attributes[:layout]}.*"]
82
+ filenames.ensure_single('layout files', page.attributes[:layout])
83
+ filename = filenames[0]
84
+
85
+ { :type => FILE_TYPES[File.extname(filename)], :content => File.read(filename) }
86
+ end
87
+ end
64
88
 
65
- # Copies the contents of the assets directory into the output directory
66
89
  def copy_assets
90
+ # Check for assets
91
+ if Dir['assets/*'].size > 0
92
+ deprecate 'Asset-copying functionality is deprecated as of nanoc 1.5,' +
93
+ 'and will be removed in nanoc 1.6. Please use a Rake task that' +
94
+ 'copies assets using something like rsync instead.'
95
+ end
96
+
67
97
  # Remove existing assets
68
98
  Dir['assets/*'].each do |f|
69
99
  FileUtils.remove_entry_secure(f.sub('assets/', @config[:output_dir] + '/'), true)
@@ -75,8 +105,7 @@ module Nanoc
75
105
  end
76
106
  end
77
107
 
78
- # Returns a list of uncompiled pages
79
- def uncompiled_pages
108
+ def find_uncompiled_pages
80
109
  # Read all meta files
81
110
  pages = Dir['content/**/meta.yaml'].collect do |filename|
82
111
  # Read the meta file
@@ -101,30 +130,7 @@ module Nanoc
101
130
  pages
102
131
  end
103
132
 
104
- # Returns the layout for the given page
105
- def layout_for_page(a_page)
106
- if a_page[:layout].nil?
107
- { :type => :eruby, :content => "<%= @page[:content] %>" }
108
- else
109
- filenames = Dir["layouts/#{a_page[:layout]}.*"]
110
- filenames.ensure_single('layout files', a_page[:layout])
111
- filename = filenames[0]
112
-
113
- { :type => FILE_TYPES[File.extname(filename)], :content => File.read(filename) }
114
- end
115
- end
116
-
117
- # Returns the path for the given page
118
- def path_for_page(a_page)
119
- if a_page[:custom_path].nil?
120
- @config[:output_dir] + a_page[:path] + a_page[:filename] + '.' + a_page[:extension]
121
- else
122
- @config[:output_dir] + a_page[:custom_path]
123
- end
124
- end
125
-
126
- # Compiles the given pages and returns the compiled pages
127
- def compile_pages(pages)
133
+ def compile(pages)
128
134
  # Create page objects from given pages
129
135
  given_pages = []
130
136
  pages.each { |page| given_pages << Page.new(page) }
@@ -135,15 +141,20 @@ module Nanoc
135
141
  given_pages
136
142
  end
137
143
 
138
- # Layouts the page
139
- def layouted_page(a_page, a_pages)
144
+ def layouted_page(page, pages)
140
145
  # Find layout
141
- layout = layout_for_page(a_page)
146
+ layout = layout_for_page(page)
142
147
 
143
148
  # Build params
144
- assigns = { :page => a_page.merge(:_content_filename => nil), :pages => a_pages }
145
- params = { :assigns => assigns }
146
- params[:haml_options] = (a_page[:haml_options] || {}).symbolize_keys
149
+ if layout[:type] == :liquid
150
+ public_page = page.to_liquid
151
+ public_pages = pages.map { |p| p.to_liquid }
152
+ else
153
+ public_page = page.to_proxy
154
+ public_pages = pages.map { |p| p.to_proxy }
155
+ end
156
+ params = { :assigns => { :page => public_page, :pages => public_pages } }
157
+ params[:haml_options] = (page.attributes[:haml_options] || {}).symbolize_keys
147
158
 
148
159
  # Layout
149
160
  case layout[:type]
@@ -162,5 +173,21 @@ module Nanoc
162
173
  content
163
174
  end
164
175
 
176
+ def layout(pages)
177
+ pages.reject { |page| page.attributes[:skip_output] }.each do |page|
178
+ begin
179
+ # Prepare layout content
180
+ content = layouted_page(page, pages)
181
+
182
+ # Write page with layout
183
+ FileManager.create_file(path_for_page(page)) { content }
184
+ rescue => exception
185
+ p = page.attributes[:_content_filename]
186
+ l = page.attributes[:layout]
187
+ handle_exception(exception, "layouting page '#{p}' in layout '#{l}'")
188
+ end
189
+ end
190
+ end
191
+
165
192
  end
166
193
  end
@@ -0,0 +1 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'core_ext', '*.rb')].each { |f| require f }
@@ -0,0 +1,17 @@
1
+ class Array
2
+ # Ensures that the array contains only one element
3
+ def ensure_single(a_noun, a_context)
4
+ if self.size != 1
5
+ $stderr.puts "ERROR: expected 1 #{a_noun}, found #{self.size} (#{a_context})" unless $quiet
6
+ exit
7
+ end
8
+ end
9
+
10
+ # Pushes the object on the stack, yields, and pops stack
11
+ def pushing(obj)
12
+ push(obj)
13
+ yield
14
+ ensure
15
+ pop
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ class Hash
2
+ # Cleans up the hash by performing the following operations:
3
+ # * Values with keys ending in _at and _on are converted into Times and
4
+ # Dates, respectively
5
+ # * All keys are converted to symbols
6
+ # * Value strings 'true', 'false', and 'none' are converted into
7
+ # true, false, and nil, respectively
8
+ def clean
9
+ symbolize_keys.inject({}) do |hash, (key, value)|
10
+ if key.to_s =~ /_on$/
11
+ hash.merge(key => Date.parse(value))
12
+ elsif key.to_s =~ /_at$/
13
+ hash.merge(key => Time.parse(value))
14
+ elsif value == 'true'
15
+ hash.merge(key => true)
16
+ elsif value == 'false'
17
+ hash.merge(key => false)
18
+ elsif value == 'none'
19
+ hash.merge(key => nil)
20
+ else
21
+ hash.merge(key => value)
22
+ end
23
+ end
24
+ end
25
+
26
+ # Converts all keys in the hash to symbols and returns the result
27
+ def symbolize_keys
28
+ inject({}) do |hash, (key, value)|
29
+ new_value = value.respond_to?(:symbolize_keys) ? value.symbolize_keys : value
30
+ hash.merge({ key.to_sym => new_value })
31
+ end
32
+ end
33
+
34
+ # Converts all keys in the hash to strings and returns the result
35
+ def stringify_keys
36
+ inject({}) do |hash, (key, value)|
37
+ new_value = value.respond_to?(:stringify_keys) ? value.stringify_keys : value
38
+ hash.merge({ key.to_s => new_value })
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ class String
2
+
3
+ # Returns true if the string starts with str
4
+ def starts_with?(str)
5
+ str == self[0, str.length]
6
+ end
7
+
8
+ # Returns true if the string ends with str
9
+ def ends_with?(str)
10
+ str == self[-str.length, str.length]
11
+ end
12
+
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'yaml'
2
+
3
+ module YAML
4
+ # Loads a YAML file, cleans it using Hash#clean, and returns the result
5
+ def self.load_file_and_clean(a_filename)
6
+ (YAML.load_file(a_filename) || {}).clean
7
+ end
8
+ end
@@ -2,7 +2,7 @@ module Nanoc
2
2
 
3
3
  class Creator
4
4
 
5
- def self.create_site(a_sitename)
5
+ def create_site(a_sitename)
6
6
  ensure_nonexistant(a_sitename)
7
7
 
8
8
  FileManager.create_dir a_sitename do
@@ -38,10 +38,10 @@ module Nanoc
38
38
  FileManager.create_file 'default.erb' do
39
39
  "<html>\n" +
40
40
  " <head>\n" +
41
- " <title><%= @page[:title] %></title>\n" +
41
+ " <title><%= @page.title %></title>\n" +
42
42
  " </head>\n" +
43
43
  " <body>\n" +
44
- "<%= @page[:content] %>\n" +
44
+ "<%= @page.content %>\n" +
45
45
  " </body>\n" +
46
46
  "</html>\n"
47
47
  end
@@ -53,7 +53,7 @@ module Nanoc
53
53
  "\# before nanoc starts compiling.\n" +
54
54
  "\n" +
55
55
  "def html_escape(a_string)\n" +
56
- " a_string.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;').gsub('\\'', '&apos;').gsub('\"', '&quot;')\n" +
56
+ " a_string.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;').gsub('\"', '&quot;')\n" +
57
57
  "end\n" +
58
58
  "alias h html_escape\n"
59
59
  end
@@ -95,7 +95,7 @@ module Nanoc
95
95
  end
96
96
  end
97
97
 
98
- def self.create_page(a_pagename, a_params={})
98
+ def create_page(a_pagename, a_params={})
99
99
  Nanoc.ensure_in_site
100
100
  ensure_nonexistant(File.join(['content', a_pagename]))
101
101
 
@@ -135,7 +135,7 @@ module Nanoc
135
135
  end
136
136
  end
137
137
 
138
- def self.create_template(a_templatename)
138
+ def create_template(a_templatename)
139
139
  Nanoc.ensure_in_site
140
140
  ensure_nonexistant(File.join(['templates', a_templatename]))
141
141
 
@@ -156,7 +156,7 @@ module Nanoc
156
156
 
157
157
  private
158
158
 
159
- def self.ensure_nonexistant(filename)
159
+ def ensure_nonexistant(filename)
160
160
  if File.exist?(filename)
161
161
  $stderr.puts "ERROR: A file or directory named #{filename} already exists." unless $quiet
162
162
  exit