nanoc 1.3.1 → 1.4

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,12 @@
1
+ == 1.4
2
+
3
+ * nanoc now supports ERB (as well as Erubis); Erubis no longer is a dependency
4
+ * meta.yaml can now have haml_options property, which is passed to Haml
5
+ * Pages can now have a 'filename' property, which defaults to 'index' [Dennis
6
+ Sutch]
7
+ * Pages now know in what order they should be compiled, eliminating the need
8
+ for custom page ordering [Dennis Sutch]
9
+
1
10
  == 1.3.1
2
11
 
3
12
  * The contents of the 'assets' directory are now copied into the output
@@ -16,9 +25,9 @@
16
25
  == 1.2
17
26
 
18
27
  * Sites now have an 'assets' directory, whose contents are copied to the
19
- 'output' directory when compiling
28
+ 'output' directory when compiling [Soryu]
20
29
  * Added support for non-eRuby layouts (Markaby, Haml, Liquid, ...)
21
- * Added many more filters
30
+ * Added more filters (Markaby, Haml, Liquid, RDoc [Dmitry Bilunov])
22
31
  * Improved error reporting
23
32
  * Accessing page attributes using instance variables, and not through @page,
24
33
  is no longer possible
data/Rakefile CHANGED
@@ -29,7 +29,6 @@ spec = Gem::Specification.new do |s|
29
29
  s.homepage = HOMEPAGE
30
30
  s.email = EMAIL
31
31
 
32
- s.add_dependency('erubis')
33
32
  s.required_ruby_version = '>= 1.8.2'
34
33
 
35
34
  s.has_rdoc = false
data/bin/nanoc CHANGED
@@ -26,7 +26,7 @@ Description:
26
26
  The 'nanoc' command is used for creating nanoc-powered sites, as well as
27
27
  managing them: creating pages and templates and compiling the site.
28
28
 
29
- Read more about nanoc on the site: <http://stoneship.org/software/nanoc/>
29
+ Read more about nanoc on the site: <http://nanoc.stoneship.org/>
30
30
  EOT
31
31
 
32
32
  # Parse options
data/lib/compiler.rb CHANGED
@@ -13,11 +13,11 @@ module Nanoc
13
13
 
14
14
  PAGE_DEFAULTS = {
15
15
  :custom_path => nil,
16
+ :filename => 'index',
16
17
  :extension => 'html',
17
18
  :filters => [],
18
19
  :is_draft => false,
19
- :layout => 'default',
20
- :order => 0
20
+ :layout => 'default'
21
21
  }
22
22
 
23
23
  def initialize
@@ -31,6 +31,9 @@ module Nanoc
31
31
  # Require all Ruby source files in lib/
32
32
  Dir['lib/*.rb'].each { |f| require f }
33
33
 
34
+ # Create output assets directory if necessary
35
+ FileUtils.mkdir_p(@config[:output_dir])
36
+
34
37
  # Copy assets to output directory
35
38
  copy_assets
36
39
 
@@ -49,28 +52,27 @@ module Nanoc
49
52
  # Write page with layout
50
53
  FileManager.create_file(path_for_page(page)) { content }
51
54
  rescue => exception
52
- $stderr.puts "Exception occured while layouting page " +
53
- "'#{page[:_content_filename]}' in layout '#{page[:layout]}':" unless $quiet
54
- $stderr.puts exception unless $quiet
55
- $stderr.puts exception.backtrace.join("\n") unless $quiet
56
- exit
55
+ p = page[:_content_filename]
56
+ l = page[:layout]
57
+ handle_exception(exception, "layouting page '#{p}' in layout '#{l}'")
57
58
  end
58
59
 
59
60
  end
60
61
  end
61
62
 
62
- private
63
+ private
63
64
 
64
65
  # Copies the contents of the assets directory into the output directory
65
66
  def copy_assets
66
- # Create output assets directory if necessary
67
- FileUtils.mkdir_p(@config[:output_dir])
68
-
69
67
  # Remove existing assets
70
- Dir['assets/*'].each { |f| FileUtils.remove_entry_secure(f.sub('assets/', @config[:output_dir] + '/'), true) }
68
+ Dir['assets/*'].each do |f|
69
+ FileUtils.remove_entry_secure(f.sub('assets/', @config[:output_dir] + '/'), true)
70
+ end
71
71
 
72
72
  # Copy assets
73
- FileUtils.cp_r(Dir['assets/*'], @config[:output_dir]) if File.directory?('assets') and !Dir['assets/*'].empty?
73
+ if File.directory?('assets') and !Dir['assets/*'].empty?
74
+ FileUtils.cp_r(Dir['assets/*'], @config[:output_dir])
75
+ end
74
76
  end
75
77
 
76
78
  # Returns a list of uncompiled pages
@@ -84,7 +86,8 @@ module Nanoc
84
86
  page[:path] = filename.sub(/^content/, '').sub('meta.yaml', '')
85
87
 
86
88
  # Get the content filename
87
- content_filenames = Dir[filename.sub('meta.yaml', File.basename(File.dirname(filename)) + '.*')].reject { |f| f =~ /~$/ }
89
+ content_filenames = Dir[filename.sub('meta.yaml', File.basename(File.dirname(filename)) + '.*')]
90
+ content_filenames.reject! { |f| f =~ /~$/ }
88
91
  content_filenames += Dir["#{File.dirname(filename)}/index.*"] # fallback for nanoc 1.0
89
92
  content_filenames.ensure_single('content files', File.dirname(filename))
90
93
  page[:_content_filename] = content_filenames[0]
@@ -95,15 +98,6 @@ module Nanoc
95
98
  # Ignore drafts
96
99
  pages.reject! { |page| page[:is_draft] }
97
100
 
98
- # Sort pages by order and by path
99
- pages.sort! do |x,y|
100
- if x[:order].to_i == y[:order].to_i
101
- x[:path] <=> y[:path]
102
- else
103
- x[:order].to_i <=> y[:order].to_i
104
- end
105
- end
106
-
107
101
  pages
108
102
  end
109
103
 
@@ -123,66 +117,46 @@ module Nanoc
123
117
  # Returns the path for the given page
124
118
  def path_for_page(a_page)
125
119
  if a_page[:custom_path].nil?
126
- @config[:output_dir] + a_page[:path] + 'index.' + a_page[:extension]
120
+ @config[:output_dir] + a_page[:path] + a_page[:filename] + '.' + a_page[:extension]
127
121
  else
128
122
  @config[:output_dir] + a_page[:custom_path]
129
123
  end
130
124
  end
131
125
 
132
126
  # Compiles the given pages and returns the compiled pages
133
- def compile_pages(a_pages)
127
+ def compile_pages(pages)
134
128
  # Create page objects from given pages
135
- given_pages = []
136
- a_pages.each { |page| given_pages << Page.new(page) }
129
+ given_pages = []
130
+ pages.each { |page| given_pages << Page.new(page) }
137
131
 
138
- # Create arrays for two kinds of pages
139
- compiled_pages = []
140
- uncompiled_pages = []
141
- given_pages.each { |page| uncompiled_pages << page }
132
+ # Compile pages
133
+ Page.compile(given_pages)
142
134
 
143
- # Compile all pages
144
- given_pages.each do |page|
145
- # Read page
146
- content = File.read(page._content_filename)
147
-
148
- # Compile page
149
- begin
150
- content = content.filter(page.filters, :assigns => { :page => page, :pages => uncompiled_pages + compiled_pages })
151
- rescue Exception => exception
152
- $stderr.puts "Exception occured while compiling page " +
153
- "'#{page[:_content_filename]}':" unless $quiet
154
- $stderr.puts exception unless $quiet
155
- $stderr.puts exception.backtrace.join("\n") unless $quiet
156
- exit
157
- end
158
-
159
- # Move from uncompiled to compiled
160
- uncompiled_pages -= [ page ]
161
- compiled_pages += [ page ]
162
-
163
- # Create compiled page
164
- page[:content] = content
165
- end
166
-
167
- # Return all pages
168
- compiled_pages
135
+ given_pages
169
136
  end
170
137
 
171
138
  # Layouts the page
172
139
  def layouted_page(a_page, a_pages)
173
- context = { :page => a_page.merge(:_content_filename => nil), :pages => a_pages }
140
+ # Find layout
174
141
  layout = layout_for_page(a_page)
175
142
 
176
- content = nil
143
+ # 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
147
+
148
+ # Layout
177
149
  case layout[:type]
178
150
  when :eruby
179
- content = layout[:content].eruby(context)
151
+ content = layout[:content].eruby(params)
180
152
  when :haml
181
- content = layout[:content].haml(context)
153
+ content = layout[:content].haml(params)
182
154
  when :markaby
183
- content = layout[:content].markaby(context)
155
+ content = layout[:content].markaby(params)
184
156
  when :liquid
185
- content = layout[:content].liquid(context)
157
+ content = layout[:content].liquid(params)
158
+ else
159
+ content = nil
186
160
  end
187
161
 
188
162
  content
data/lib/creator.rb CHANGED
@@ -3,12 +3,7 @@ module Nanoc
3
3
  class Creator
4
4
 
5
5
  def self.create_site(a_sitename)
6
- # Make sure we're not accidentally overwriting anything
7
- if File.exist?(a_sitename)
8
- $stderr.puts 'ERROR: A file or directory named ' + a_sitename +
9
- ' already exists.' unless $quiet
10
- exit
11
- end
6
+ ensure_nonexistant(a_sitename)
12
7
 
13
8
  FileManager.create_dir a_sitename do
14
9
  FileManager.create_dir 'assets'
@@ -24,8 +19,8 @@ module Nanoc
24
19
  "\n" +
25
20
  "# Built-in\n" +
26
21
  "layout: \"default\"\n" +
27
- "order: 0\n" +
28
22
  "filters: []\n" +
23
+ "filename: \"index\"\n" +
29
24
  "extension: \"html\"\n" +
30
25
  "\n" +
31
26
  "# Custom\n"
@@ -102,13 +97,7 @@ module Nanoc
102
97
 
103
98
  def self.create_page(a_pagename, a_params={})
104
99
  Nanoc.ensure_in_site
105
-
106
- # Make sure we're not accidentally overwriting anything
107
- if File.exist?(File.join(['content', a_pagename]))
108
- $stderr.puts 'ERROR: A file or directory named ' + a_pagename +
109
- ' already exists.' unless $quiet
110
- exit
111
- end
100
+ ensure_nonexistant(File.join(['content', a_pagename]))
112
101
 
113
102
  # Sanitize page name
114
103
  if a_pagename =~ /^[\/\.]+/
@@ -117,9 +106,6 @@ module Nanoc
117
106
  end
118
107
 
119
108
  # Read template
120
- template_index = nil
121
- template_meta = nil
122
- template_content_filename = nil
123
109
  template = a_params[:template] || 'default'
124
110
  begin
125
111
  template_meta = File.read("templates/#{template}/meta.yaml")
@@ -137,7 +123,9 @@ module Nanoc
137
123
  # Create index and yaml file
138
124
  FileManager.create_dir 'content' do
139
125
  FileManager.create_dir a_pagename do
140
- FileManager.create_file "#{a_pagename.sub(/.*\/([^\/]+)/, '\1')}#{File.extname(template_content_filename)}" do
126
+ page_name = a_pagename.sub(/.*\/([^\/]+)/, '\1')
127
+ extension = File.extname(template_content_filename)
128
+ FileManager.create_file "#{page_name}#{extension}" do
141
129
  template_index
142
130
  end
143
131
  FileManager.create_file 'meta.yaml' do
@@ -149,13 +137,7 @@ module Nanoc
149
137
 
150
138
  def self.create_template(a_templatename)
151
139
  Nanoc.ensure_in_site
152
-
153
- # Make sure we're not accidentally overwriting anything
154
- if File.exist?(File.join(['templates', a_templatename]))
155
- $stderr.puts 'ERROR: A file or directory named ' + a_templatename +
156
- ' already exists.' unless $quiet
157
- exit
158
- end
140
+ ensure_nonexistant(File.join(['templates', a_templatename]))
159
141
 
160
142
  FileManager.create_dir 'templates' do
161
143
  FileManager.create_dir a_templatename do
@@ -172,5 +154,14 @@ module Nanoc
172
154
  end
173
155
  end
174
156
 
157
+ private
158
+
159
+ def self.ensure_nonexistant(filename)
160
+ if File.exist?(filename)
161
+ $stderr.puts "ERROR: A file or directory named #{filename} already exists." unless $quiet
162
+ exit
163
+ end
164
+ end
165
+
175
166
  end
176
167
  end
data/lib/enhancements.rb CHANGED
@@ -2,11 +2,12 @@ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
2
 
3
3
  try_require 'rubygems'
4
4
 
5
- require 'erubis'
5
+ require 'erb'
6
6
  require 'fileutils'
7
7
  require 'yaml'
8
8
 
9
9
  try_require 'bluecloth'
10
+ try_require 'erubis'
10
11
  try_require 'redcloth'
11
12
  try_require 'rubypants'
12
13
  try_require 'markaby'
@@ -15,6 +16,15 @@ try_require 'haml'
15
16
  try_require 'rdoc/markup/simple_markup'
16
17
  try_require 'rdoc/markup/simple_markup/to_html'
17
18
 
19
+ def handle_exception(exception, text)
20
+ unless $quiet or exception.class == SystemExit
21
+ $stderr.puts "ERROR: Exception occured while #{text}:\n"
22
+ $stderr.puts exception
23
+ $stderr.puts exception.backtrace.join("\n")
24
+ end
25
+ exit
26
+ end
27
+
18
28
  class Array
19
29
  # Ensures that the array contains only one element
20
30
  def ensure_single(a_noun, a_context)
@@ -54,6 +64,13 @@ class Hash
54
64
  end
55
65
  end
56
66
 
67
+ def symbolize_keys
68
+ inject({}) do |hash, (key, value)|
69
+ hash[key.intern] = value
70
+ hash
71
+ end
72
+ end
73
+
57
74
  def stringify_keys
58
75
  inject({}) do |hash, (key, value)|
59
76
  hash[key.to_s] = value
@@ -62,20 +79,33 @@ class Hash
62
79
  end
63
80
  end
64
81
 
82
+ class ERBContext
83
+ def initialize(hash)
84
+ hash.each_pair do |key, value|
85
+ instance_variable_set('@' + key.to_s, value)
86
+ end
87
+ end
88
+
89
+ def get_binding
90
+ binding
91
+ end
92
+ end
93
+
65
94
  class String
66
95
  # Runs the string through the filters as given by the array of
67
96
  # filter names. Available filters include 'markdown', 'smartypants' and 'eruby'.
68
97
  def filter(a_filters, a_params={})
98
+ assigns = a_params[:assigns]
69
99
  a_filters.inject(self) do |result, filter|
70
100
  case filter
71
101
  when 'eruby'
72
- result.replace(result.eruby(a_params[:assigns]))
102
+ result.replace(result.eruby(:assigns => assigns))
73
103
  when 'haml'
74
- result.replace(result.haml(a_params[:assigns]))
104
+ result.replace(result.haml(:assigns => assigns))
75
105
  when 'liquid'
76
- result.replace(result.liquid(a_params[:assigns]))
106
+ result.replace(result.liquid(:assigns => assigns))
77
107
  when 'markaby'
78
- result.replace(result.markaby(a_params[:assigns]))
108
+ result.replace(result.markaby(:assigns => assigns))
79
109
  when 'markdown', 'bluecloth'
80
110
  result.replace(result.markdown)
81
111
  when 'rdoc'
@@ -90,22 +120,36 @@ class String
90
120
  end
91
121
  end
92
122
 
93
- # Converts the string using eRuby.
94
- def eruby(a_assigns={})
95
- Erubis::Eruby.new(self).evaluate(a_assigns)
123
+ # Converts the string using eRuby
124
+ def eruby(a_params={})
125
+ erubis(a_params)
126
+ rescue NameError
127
+ erb(a_params)
128
+ end
129
+
130
+ # Converts the string using Erubis
131
+ def erubis(a_params={})
132
+ Erubis::Eruby.new(self).evaluate(a_params[:assigns] || {})
133
+ end
134
+
135
+ # Converts the string using ERB
136
+ def erb(a_params={})
137
+ ERB.new(self).result(ERBContext.new(a_params[:assigns] || {}).get_binding)
96
138
  end
97
139
 
98
140
  # Converts the string using Haml
99
- def haml(a_assigns={})
100
- Haml::Engine.new(self, :locals => a_assigns).to_html
141
+ def haml(a_params={})
142
+ options = (a_params[:haml_options] || {})
143
+ options[:locals] = a_params[:assigns] unless a_params[:assigns].nil?
144
+ Haml::Engine.new(self, options).to_html
101
145
  rescue NameError
102
146
  $stderr.puts 'ERROR: String#haml failed (Haml not installed?)' unless $quiet
103
147
  exit
104
148
  end
105
149
 
106
150
  # Converts the string using Liquid
107
- def liquid(a_assigns={})
108
- Liquid::Template.parse(self).render(a_assigns.stringify_keys)
151
+ def liquid(a_params={})
152
+ Liquid::Template.parse(self).render((a_params[:assigns] || {}).stringify_keys)
109
153
  rescue NameError
110
154
  $stderr.puts 'ERROR: String#liquid failed (Liquid not installed?)' unless $quiet
111
155
  exit
@@ -113,8 +157,8 @@ class String
113
157
 
114
158
  # Converts the string using Markaby
115
159
  # TODO perhaps add support for helpers
116
- def markaby(a_assigns={})
117
- Markaby::Builder.new(a_assigns).instance_eval(self).to_s
160
+ def markaby(a_params={})
161
+ Markaby::Builder.new((a_params[:assigns] || {})).instance_eval(self).to_s
118
162
  rescue NameError
119
163
  $stderr.puts 'ERROR: String#markaby failed (Markaby not installed?)' unless $quiet
120
164
  exit
@@ -228,5 +272,6 @@ class FileManager
228
272
  end
229
273
 
230
274
  def render(a_name, a_context={})
231
- File.read('layouts/' + a_name.to_s + '.erb').eruby(a_context.merge({ :page => @page, :pages => @pages }))
275
+ assigns = a_context.merge({ :page => @page, :pages => @pages })
276
+ File.read('layouts/' + a_name.to_s + '.erb').eruby(:assigns => assigns)
232
277
  end
data/lib/nanoc.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Nanoc
2
- VERSION = '1.3.1'
2
+ VERSION = '1.4'
3
3
 
4
4
  def self.ensure_in_site
5
5
  unless in_site?
@@ -15,7 +15,6 @@ module Nanoc
15
15
  return false unless File.directory?('content')
16
16
  return false unless File.directory?('layouts')
17
17
  return false unless File.directory?('lib')
18
- return false unless File.directory?('output')
19
18
  return false unless File.directory?('tasks')
20
19
  return false unless File.directory?('templates')
21
20
  return false unless File.exist?('config.yaml')
data/lib/page.rb CHANGED
@@ -1,20 +1,14 @@
1
1
  module Nanoc
2
2
  class Page
3
3
 
4
- def initialize(a_hash={})
5
- @attributes = a_hash
6
- end
7
-
8
- def [](a_key)
9
- @attributes[a_key]
10
- end
4
+ @@compilation_stack = []
11
5
 
12
- def []=(a_key, a_value)
13
- @attributes[a_key] = a_value
6
+ def initialize(hash={})
7
+ @attributes = hash
14
8
  end
15
9
 
16
- def merge(a_other)
17
- @attributes.merge(a_other.to_hash)
10
+ def merge(other)
11
+ @attributes.merge(other.to_hash)
18
12
  self
19
13
  end
20
14
 
@@ -22,8 +16,75 @@ module Nanoc
22
16
  @attributes
23
17
  end
24
18
 
25
- def method_missing(a_method, *a_args)
26
- @attributes[a_method.to_sym]
19
+ # Accessing data
20
+
21
+ def [](key)
22
+ @attributes[key]
23
+ end
24
+
25
+ def []=(key, value)
26
+ @attributes[key] = value
27
+ end
28
+
29
+ def method_missing(method, *args)
30
+ @attributes[method.to_sym]
31
+ end
32
+
33
+ def content
34
+ compile!
35
+ @attributes[:content]
36
+ end
37
+
38
+ # Compiling
39
+
40
+ def self.compile(pages)
41
+ @@pages = pages
42
+
43
+ # Compile all pages
44
+ pages.each do |page|
45
+ page.compile!
46
+ end
47
+ end
48
+
49
+ def compile!
50
+ # Check for recursive call
51
+ if @@compilation_stack.include?(self)
52
+ # Print compilation stack
53
+ unless $quiet
54
+ $stderr.puts 'ERROR: Recursive call to page content. Page compilation stack:'
55
+
56
+ # Determine relevant part of compilation stack
57
+ stack_begin = @@compilation_stack.index(self)
58
+ stack_end = @@compilation_stack.size
59
+ relevant_stack_part = @@compilation_stack.last(stack_end - stack_begin)
60
+
61
+ # Print relevant part of compilation stack
62
+ relevant_stack_part.each_with_index do |page, i|
63
+ $stderr.puts "#{i} #{page._content_filename}"
64
+ end
65
+ end
66
+ exit
67
+ # Compile if not yet compiled
68
+ elsif self[:content].nil?
69
+ # Add to stack
70
+ @@compilation_stack.push(self)
71
+
72
+ # Read page
73
+ content = File.read(self._content_filename)
74
+
75
+ # Compile page
76
+ begin
77
+ assigns = { :page => self, :pages => @@pages }
78
+ # TODO set more custom options
79
+ params = { :assigns => assigns }
80
+ params[:haml_options] = (self[:haml_options] || {}).symbolize_keys
81
+ content = content.filter(self.filters, params)
82
+ rescue Exception => exception
83
+ handle_exception(exception, "compiling page '#{self[:_content_filename]}'")
84
+ end
85
+ @attributes[:content] = content
86
+ @@compilation_stack.pop
87
+ end
27
88
  end
28
89
 
29
90
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: nanoc
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.3.1
7
- date: 2007-06-30 00:00:00 +02:00
6
+ version: "1.4"
7
+ date: 2007-07-06 00:00:00 +02:00
8
8
  summary: a CMS that doesn't run on your server
9
9
  require_paths:
10
10
  - lib
@@ -51,13 +51,5 @@ extensions: []
51
51
 
52
52
  requirements: []
53
53
 
54
- dependencies:
55
- - !ruby/object:Gem::Dependency
56
- name: erubis
57
- version_requirement:
58
- version_requirements: !ruby/object:Gem::Version::Requirement
59
- requirements:
60
- - - ">"
61
- - !ruby/object:Gem::Version
62
- version: 0.0.0
63
- version:
54
+ dependencies: []
55
+