nanoc 1.4 → 1.5

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.
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