nanoc3 3.0.0

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.
Files changed (116) hide show
  1. data/ChangeLog +3 -0
  2. data/LICENSE +19 -0
  3. data/NEWS.rdoc +262 -0
  4. data/README.rdoc +80 -0
  5. data/Rakefile +11 -0
  6. data/bin/nanoc3 +16 -0
  7. data/lib/nanoc3/base/code_snippet.rb +42 -0
  8. data/lib/nanoc3/base/compiler.rb +225 -0
  9. data/lib/nanoc3/base/compiler_dsl.rb +110 -0
  10. data/lib/nanoc3/base/core_ext/array.rb +21 -0
  11. data/lib/nanoc3/base/core_ext/hash.rb +23 -0
  12. data/lib/nanoc3/base/core_ext/string.rb +14 -0
  13. data/lib/nanoc3/base/core_ext.rb +5 -0
  14. data/lib/nanoc3/base/data_source.rb +197 -0
  15. data/lib/nanoc3/base/dependency_tracker.rb +291 -0
  16. data/lib/nanoc3/base/errors.rb +95 -0
  17. data/lib/nanoc3/base/filter.rb +60 -0
  18. data/lib/nanoc3/base/item.rb +87 -0
  19. data/lib/nanoc3/base/item_rep.rb +236 -0
  20. data/lib/nanoc3/base/layout.rb +53 -0
  21. data/lib/nanoc3/base/notification_center.rb +68 -0
  22. data/lib/nanoc3/base/plugin.rb +88 -0
  23. data/lib/nanoc3/base/preprocessor_context.rb +37 -0
  24. data/lib/nanoc3/base/rule.rb +37 -0
  25. data/lib/nanoc3/base/rule_context.rb +68 -0
  26. data/lib/nanoc3/base/site.rb +334 -0
  27. data/lib/nanoc3/base.rb +25 -0
  28. data/lib/nanoc3/cli/base.rb +151 -0
  29. data/lib/nanoc3/cli/commands/autocompile.rb +89 -0
  30. data/lib/nanoc3/cli/commands/compile.rb +279 -0
  31. data/lib/nanoc3/cli/commands/create_item.rb +79 -0
  32. data/lib/nanoc3/cli/commands/create_layout.rb +94 -0
  33. data/lib/nanoc3/cli/commands/create_site.rb +320 -0
  34. data/lib/nanoc3/cli/commands/help.rb +71 -0
  35. data/lib/nanoc3/cli/commands/info.rb +114 -0
  36. data/lib/nanoc3/cli/commands/update.rb +96 -0
  37. data/lib/nanoc3/cli/commands.rb +13 -0
  38. data/lib/nanoc3/cli/logger.rb +73 -0
  39. data/lib/nanoc3/cli.rb +16 -0
  40. data/lib/nanoc3/data_sources/delicious.rb +66 -0
  41. data/lib/nanoc3/data_sources/filesystem.rb +231 -0
  42. data/lib/nanoc3/data_sources/filesystem_combined.rb +202 -0
  43. data/lib/nanoc3/data_sources/filesystem_common.rb +22 -0
  44. data/lib/nanoc3/data_sources/filesystem_compact.rb +232 -0
  45. data/lib/nanoc3/data_sources/last_fm.rb +103 -0
  46. data/lib/nanoc3/data_sources/twitter.rb +53 -0
  47. data/lib/nanoc3/data_sources.rb +20 -0
  48. data/lib/nanoc3/extra/auto_compiler.rb +97 -0
  49. data/lib/nanoc3/extra/chick.rb +119 -0
  50. data/lib/nanoc3/extra/context.rb +24 -0
  51. data/lib/nanoc3/extra/core_ext/time.rb +19 -0
  52. data/lib/nanoc3/extra/core_ext.rb +3 -0
  53. data/lib/nanoc3/extra/deployers/rsync.rb +64 -0
  54. data/lib/nanoc3/extra/deployers.rb +12 -0
  55. data/lib/nanoc3/extra/file_proxy.rb +31 -0
  56. data/lib/nanoc3/extra/validators/links.rb +0 -0
  57. data/lib/nanoc3/extra/validators/w3c.rb +71 -0
  58. data/lib/nanoc3/extra/validators.rb +12 -0
  59. data/lib/nanoc3/extra/vcs.rb +65 -0
  60. data/lib/nanoc3/extra/vcses/bazaar.rb +21 -0
  61. data/lib/nanoc3/extra/vcses/dummy.rb +20 -0
  62. data/lib/nanoc3/extra/vcses/git.rb +21 -0
  63. data/lib/nanoc3/extra/vcses/mercurial.rb +21 -0
  64. data/lib/nanoc3/extra/vcses/subversion.rb +21 -0
  65. data/lib/nanoc3/extra/vcses.rb +17 -0
  66. data/lib/nanoc3/extra.rb +16 -0
  67. data/lib/nanoc3/filters/bluecloth.rb +13 -0
  68. data/lib/nanoc3/filters/coderay.rb +17 -0
  69. data/lib/nanoc3/filters/erb.rb +19 -0
  70. data/lib/nanoc3/filters/erubis.rb +17 -0
  71. data/lib/nanoc3/filters/haml.rb +20 -0
  72. data/lib/nanoc3/filters/less.rb +13 -0
  73. data/lib/nanoc3/filters/markaby.rb +14 -0
  74. data/lib/nanoc3/filters/maruku.rb +14 -0
  75. data/lib/nanoc3/filters/rainpress.rb +13 -0
  76. data/lib/nanoc3/filters/rdiscount.rb +13 -0
  77. data/lib/nanoc3/filters/rdoc.rb +23 -0
  78. data/lib/nanoc3/filters/redcloth.rb +14 -0
  79. data/lib/nanoc3/filters/relativize_paths.rb +32 -0
  80. data/lib/nanoc3/filters/rubypants.rb +14 -0
  81. data/lib/nanoc3/filters/sass.rb +17 -0
  82. data/lib/nanoc3/filters.rb +37 -0
  83. data/lib/nanoc3/helpers/blogging.rb +226 -0
  84. data/lib/nanoc3/helpers/breadcrumbs.rb +25 -0
  85. data/lib/nanoc3/helpers/capturing.rb +71 -0
  86. data/lib/nanoc3/helpers/filtering.rb +46 -0
  87. data/lib/nanoc3/helpers/html_escape.rb +22 -0
  88. data/lib/nanoc3/helpers/link_to.rb +120 -0
  89. data/lib/nanoc3/helpers/rendering.rb +76 -0
  90. data/lib/nanoc3/helpers/tagging.rb +58 -0
  91. data/lib/nanoc3/helpers/text.rb +40 -0
  92. data/lib/nanoc3/helpers/xml_sitemap.rb +69 -0
  93. data/lib/nanoc3/helpers.rb +16 -0
  94. data/lib/nanoc3/package.rb +106 -0
  95. data/lib/nanoc3/tasks/clean.rake +16 -0
  96. data/lib/nanoc3/tasks/clean.rb +33 -0
  97. data/lib/nanoc3/tasks/deploy/rsync.rake +11 -0
  98. data/lib/nanoc3/tasks/validate.rake +35 -0
  99. data/lib/nanoc3/tasks.rb +9 -0
  100. data/lib/nanoc3.rb +19 -0
  101. data/vendor/cri/ChangeLog +0 -0
  102. data/vendor/cri/LICENSE +19 -0
  103. data/vendor/cri/NEWS +0 -0
  104. data/vendor/cri/README +4 -0
  105. data/vendor/cri/Rakefile +25 -0
  106. data/vendor/cri/lib/cri/base.rb +153 -0
  107. data/vendor/cri/lib/cri/command.rb +105 -0
  108. data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
  109. data/vendor/cri/lib/cri/core_ext.rb +8 -0
  110. data/vendor/cri/lib/cri/option_parser.rb +186 -0
  111. data/vendor/cri/lib/cri.rb +12 -0
  112. data/vendor/cri/test/test_base.rb +6 -0
  113. data/vendor/cri/test/test_command.rb +6 -0
  114. data/vendor/cri/test/test_core_ext.rb +21 -0
  115. data/vendor/cri/test/test_option_parser.rb +279 -0
  116. metadata +225 -0
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3::CLI::Commands
4
+
5
+ class Autocompile < Cri::Command
6
+
7
+ def name
8
+ 'autocompile'
9
+ end
10
+
11
+ def aliases
12
+ [ 'aco' ]
13
+ end
14
+
15
+ def short_desc
16
+ 'start the autocompiler'
17
+ end
18
+
19
+ def long_desc
20
+ 'Start the autocompiler web server. Unless specified, the web ' +
21
+ 'server will run on port 3000 and listen on all IP addresses. ' +
22
+ 'Running the autocompiler requires \'mime/types\' and \'rack\'.'
23
+ end
24
+
25
+ def usage
26
+ "nanoc3 autocompile [options]"
27
+ end
28
+
29
+ def option_definitions
30
+ [
31
+ # --port
32
+ {
33
+ :long => 'port', :short => 'p', :argument => :required,
34
+ :desc => 'specify a port number for the autocompiler'
35
+ },
36
+ # --server
37
+ {
38
+ :long => 'server', :short => 's', :argument => :required,
39
+ :desc => 'specify the server to use (webrick/mongrel)'
40
+ },
41
+ # --host
42
+ {
43
+ :long => 'host', :short => 'o', :argument => :required,
44
+ :desc => 'specify the host to listen on (default: 0.0.0.0)'
45
+ },
46
+ # --port
47
+ {
48
+ :long => 'port', :short => 'p', :argument => :required,
49
+ :desc => 'specify the port to listen on (default: 3000)'
50
+ }
51
+ ]
52
+ end
53
+
54
+ def run(options, arguments)
55
+ require 'rack'
56
+
57
+ # Make sure we are in a nanoc site directory
58
+ @base.require_site
59
+
60
+ # Set options
61
+ options_for_rack = {
62
+ :Port => (options[:port] || 3000).to_i,
63
+ :Host => (options[:host] || '0.0.0.0')
64
+ }
65
+
66
+ # Guess which handler we should use
67
+ unless handler = Rack::Handler.get(options[:server])
68
+ begin
69
+ handler = Rack::Handler::Mongrel
70
+ rescue LoadError => e
71
+ handler = Rack::Handler::WEBrick
72
+ end
73
+ end
74
+
75
+ # Build app
76
+ autocompiler = Nanoc3::Extra::AutoCompiler.new('.')
77
+ app = Rack::Builder.new do
78
+ use Rack::CommonLogger, $stderr
79
+ use Rack::ShowExceptions
80
+ run autocompiler
81
+ end.to_app
82
+
83
+ # Run autocompiler
84
+ handler.run(app, options_for_rack)
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,279 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3::CLI::Commands
4
+
5
+ class Compile < Cri::Command
6
+
7
+ def name
8
+ 'compile'
9
+ end
10
+
11
+ def aliases
12
+ []
13
+ end
14
+
15
+ def short_desc
16
+ 'compile items of this site'
17
+ end
18
+
19
+ def long_desc
20
+ 'Compile all items of the current site. If an identifier is given, ' +
21
+ 'only the item with the given identifier will be compiled. ' +
22
+ "\n\n" +
23
+ 'By default, only item that are outdated will be compiled. This can ' +
24
+ 'speed up the compilation process quite a bit, but items that include ' +
25
+ 'content from other items may have to be recompiled manually. In ' +
26
+ 'order to compile items even when they are outdated, use the --force option.'
27
+ end
28
+
29
+ def usage
30
+ "nanoc3 compile [options] [identifier]"
31
+ end
32
+
33
+ def option_definitions
34
+ [
35
+ # --all
36
+ {
37
+ :long => 'all', :short => 'a', :argument => :forbidden,
38
+ :desc => 'alias for --force (DEPRECATED)'
39
+ },
40
+ # --force
41
+ {
42
+ :long => 'force', :short => 'f', :argument => :forbidden,
43
+ :desc => 'compile items even when they are not outdated'
44
+ }
45
+ ]
46
+ end
47
+
48
+ def run(options, arguments)
49
+ # Make sure we are in a nanoc site directory
50
+ puts "Loading site data..."
51
+ @base.require_site
52
+ @base.site.load_data
53
+
54
+ # Check presence of --all option
55
+ if options.has_key?(:all)
56
+ $stderr.puts "Warning: the --all option is deprecated; please use --force instead."
57
+ end
58
+
59
+ # Find item(s) to compile
60
+ if arguments.size == 0
61
+ item = nil
62
+ elsif arguments.size == 1
63
+ # Find item
64
+ identifier = arguments[0].cleaned_identifier
65
+ item = @base.site.items.find { |item| item.identifier == identifier }
66
+
67
+ # Ensure item
68
+ if item.nil?
69
+ $stderr.puts "Unknown item: #{identifier}"
70
+ exit 1
71
+ end
72
+ end
73
+
74
+ # Give feedback
75
+ puts "Compiling #{item.nil? ? 'site' : 'item'}..."
76
+
77
+ # Initialize profiling stuff
78
+ time_before = Time.now
79
+ @filter_times ||= {}
80
+ @times_stack ||= []
81
+ setup_notifications
82
+
83
+ # Compile
84
+ @base.site.compiler.run(
85
+ item,
86
+ :force => options.has_key?(:all) || options.has_key?(:force)
87
+ )
88
+
89
+ # Find reps
90
+ reps = @base.site.items.map { |i| i.reps }.flatten
91
+
92
+ # Show skipped reps
93
+ reps.select { |r| !r.compiled? }.each do |rep|
94
+ next if rep.raw_path.nil?
95
+ duration = @rep_times[rep.raw_path]
96
+ Nanoc3::CLI::Logger.instance.file(:low, :skip, rep.raw_path, duration)
97
+ end
98
+
99
+ # Give general feedback
100
+ puts
101
+ puts "No items were modified." unless reps.any? { |r| r.modified? }
102
+ puts "#{item.nil? ? 'Site' : 'Item'} compiled in #{format('%.2f', Time.now - time_before)}s."
103
+
104
+ if options.has_key?(:verbose)
105
+ print_state_feedback(reps)
106
+ print_profiling_feedback(reps)
107
+ end
108
+ rescue Interrupt => e
109
+ exit(1)
110
+ rescue StandardError, ScriptError => e
111
+ print_error(e)
112
+ exit(1)
113
+ end
114
+
115
+ private
116
+
117
+ def setup_notifications
118
+ Nanoc3::NotificationCenter.on(:compilation_started) do |rep|
119
+ rep_compilation_started(rep)
120
+ end
121
+ Nanoc3::NotificationCenter.on(:compilation_ended) do |rep|
122
+ rep_compilation_ended(rep)
123
+ end
124
+ Nanoc3::NotificationCenter.on(:filtering_started) do |rep, filter_name|
125
+ rep_filtering_started(rep, filter_name)
126
+ end
127
+ Nanoc3::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
128
+ rep_filtering_ended(rep, filter_name)
129
+ end
130
+ end
131
+
132
+ def print_state_feedback(reps)
133
+ # Categorise reps
134
+ rest = reps
135
+ created, rest = *rest.partition { |r| r.created? }
136
+ modified, rest = *rest.partition { |r| r.modified? }
137
+ skipped, rest = *rest.partition { |r| !r.compiled? }
138
+ not_written, rest = *rest.partition { |r| r.compiled? && !r.written? }
139
+ identical = rest
140
+
141
+ # Print
142
+ puts
143
+ puts format(' %4d created', created.size)
144
+ puts format(' %4d modified', modified.size)
145
+ puts format(' %4d skipped', skipped.size)
146
+ puts format(' %4d not written', not_written.size)
147
+ puts format(' %4d identical', identical.size)
148
+ end
149
+
150
+ def print_profiling_feedback(reps)
151
+ # Get max filter length
152
+ max_filter_name_length = @filter_times.keys.map { |k| k.to_s.size }.max
153
+ return if max_filter_name_length.nil?
154
+
155
+ # Print warning if necessary
156
+ if reps.any? { |r| !r.compiled? }
157
+ $stderr.puts
158
+ $stderr.puts "Warning: profiling information may not be accurate because " +
159
+ "some items were not compiled."
160
+ end
161
+
162
+ # Print header
163
+ puts
164
+ puts ' ' * max_filter_name_length + ' | count min avg max tot'
165
+ puts '-' * max_filter_name_length + '-+-----------------------------------'
166
+
167
+ @filter_times.to_a.sort_by { |r| r[1] }.each do |row|
168
+ # Extract data
169
+ filter_name, samples = *row
170
+
171
+ # Calculate stats
172
+ count = samples.size
173
+ min = samples.min
174
+ tot = samples.inject { |memo, i| memo + i}
175
+ avg = tot/count
176
+ max = samples.max
177
+
178
+ # Format stats
179
+ count = format('%4d', count)
180
+ min = format('%4.2f', min)
181
+ avg = format('%4.2f', avg)
182
+ max = format('%4.2f', max)
183
+ tot = format('%5.2f', tot)
184
+
185
+ # Output stats
186
+ filter_name = format("%#{max_filter_name_length}s", filter_name)
187
+ puts "#{filter_name} | #{count} #{min}s #{avg}s #{max}s #{tot}s"
188
+ end
189
+ end
190
+
191
+ def print_error(error)
192
+ $stderr.puts
193
+
194
+ # Header
195
+ $stderr.puts '+--- /!\ ERROR /!\ -------------------------------------------+'
196
+ $stderr.puts '| An exception occured while compiling the site. If you think |'
197
+ $stderr.puts '| this is a bug in nanoc, please do report it at |'
198
+ $stderr.puts '| <http://projects.stoneship.org/trac/nanoc/newticket> -- |'
199
+ $stderr.puts '| thanks in advance! |'
200
+ $stderr.puts '+-------------------------------------------------------------+'
201
+
202
+ # Exception
203
+ $stderr.puts
204
+ $stderr.puts '=== MESSAGE:'
205
+ $stderr.puts
206
+ $stderr.puts "#{error.class}: #{error.message}"
207
+
208
+ # Compilation stack
209
+ $stderr.puts
210
+ $stderr.puts '=== COMPILATION STACK:'
211
+ $stderr.puts
212
+ if ((@base.site && @base.site.compiler.stack) || []).empty?
213
+ $stderr.puts " (empty)"
214
+ else
215
+ @base.site.compiler.stack.reverse.each do |obj|
216
+ if obj.is_a?(Nanoc3::ItemRep)
217
+ $stderr.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
218
+ else # layout
219
+ $stderr.puts " - [layout] #{obj.identifier}"
220
+ end
221
+ end
222
+ end
223
+
224
+ # Backtrace
225
+ require 'enumerator'
226
+ $stderr.puts
227
+ $stderr.puts '=== BACKTRACE:'
228
+ $stderr.puts
229
+ $stderr.puts error.backtrace.to_enum(:each_with_index).map { |item, index| " #{index}. #{item}" }.join("\n")
230
+ end
231
+
232
+ def rep_compilation_started(rep)
233
+ # Profile compilation
234
+ @rep_times ||= {}
235
+ @rep_times[rep.raw_path] = Time.now
236
+ end
237
+
238
+ def rep_compilation_ended(rep)
239
+ # Profile compilation
240
+ @rep_times ||= {}
241
+ @rep_times[rep.raw_path] = Time.now - @rep_times[rep.raw_path]
242
+
243
+ # Skip if not outputted
244
+ return unless rep.written?
245
+
246
+ # Get action and level
247
+ action, level = *if rep.created?
248
+ [ :create, :high ]
249
+ elsif rep.modified?
250
+ [ :update, :high ]
251
+ elsif !rep.compiled?
252
+ [ nil, nil ]
253
+ else
254
+ [ :identical, :low ]
255
+ end
256
+
257
+ # Log
258
+ unless action.nil?
259
+ duration = @rep_times[rep.raw_path]
260
+ Nanoc3::CLI::Logger.instance.file(level, action, rep.raw_path, duration)
261
+ end
262
+ end
263
+
264
+ def rep_filtering_started(rep, filter_name)
265
+ @times_stack.push(Time.now)
266
+ end
267
+
268
+ def rep_filtering_ended(rep, filter_name)
269
+ # Get last time
270
+ time_start = @times_stack.pop
271
+
272
+ # Update times
273
+ @filter_times[filter_name.to_sym] ||= []
274
+ @filter_times[filter_name.to_sym] << Time.now - time_start
275
+ end
276
+
277
+ end
278
+
279
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3::CLI::Commands
4
+
5
+ class CreateItem < Cri::Command
6
+
7
+ def name
8
+ 'create_item'
9
+ end
10
+
11
+ def aliases
12
+ [ 'ci' ]
13
+ end
14
+
15
+ def short_desc
16
+ 'create a item'
17
+ end
18
+
19
+ def long_desc
20
+ 'Create a new item in the current site. The first data source in the site configuration will be used.'
21
+ end
22
+
23
+ def usage
24
+ "nanoc3 create_item [options] [identifier]"
25
+ end
26
+
27
+ def option_definitions
28
+ [
29
+ # --vcs
30
+ {
31
+ :long => 'vcs', :short => 'c', :argument => :required,
32
+ :desc => 'select the VCS to use'
33
+ }
34
+ ]
35
+ end
36
+
37
+ def run(options, arguments)
38
+ # Check arguments
39
+ if arguments.length != 1
40
+ $stderr.puts "usage: #{usage}"
41
+ exit 1
42
+ end
43
+
44
+ # Extract arguments and options
45
+ identifier = arguments[0].cleaned_identifier
46
+
47
+ # Make sure we are in a nanoc site directory
48
+ @base.require_site
49
+ @base.site.load_data
50
+
51
+ # Set VCS if possible
52
+ @base.set_vcs(options[:vcs])
53
+
54
+ # Check whether item is unique
55
+ if !@base.site.items.find { |i| i.identifier == identifier }.nil?
56
+ $stderr.puts "An item already exists at #{identifier}. Please " +
57
+ "pick a unique name for the item you are creating."
58
+ exit 1
59
+ end
60
+
61
+ # Setup notifications
62
+ Nanoc3::NotificationCenter.on(:file_created) do |file_path|
63
+ Nanoc3::CLI::Logger.instance.file(:high, :create, file_path)
64
+ end
65
+
66
+ # Create item
67
+ data_source = @base.site.data_sources[0]
68
+ data_source.create_item(
69
+ "Hi, I'm a new item!\n",
70
+ { :title => "A New Item" },
71
+ identifier
72
+ )
73
+
74
+ puts "An item has been created at #{identifier}."
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3::CLI::Commands
4
+
5
+ class CreateLayout < Cri::Command
6
+
7
+ def name
8
+ 'create_layout'
9
+ end
10
+
11
+ def aliases
12
+ [ 'cl' ]
13
+ end
14
+
15
+ def short_desc
16
+ 'create a layout'
17
+ end
18
+
19
+ def long_desc
20
+ 'Create a new layout in the current site. The first data source in the site configuration will be used.'
21
+ end
22
+
23
+ def usage
24
+ "nanoc3 create_layout [identifier]"
25
+ end
26
+
27
+ def option_definitions
28
+ [
29
+ # --vcs
30
+ {
31
+ :long => 'vcs', :short => 'c', :argument => :required,
32
+ :desc => 'select the VCS to use'
33
+ }
34
+ ]
35
+ end
36
+
37
+ def run(options, arguments)
38
+ # Check arguments
39
+ if arguments.length != 1
40
+ $stderr.puts "usage: #{usage}"
41
+ exit 1
42
+ end
43
+
44
+ # Extract arguments
45
+ identifier = arguments[0].cleaned_identifier
46
+
47
+ # Make sure we are in a nanoc site directory
48
+ @base.require_site
49
+ @base.site.load_data
50
+
51
+ # Set VCS if possible
52
+ @base.set_vcs(options[:vcs])
53
+
54
+ # Check whether layout is unique
55
+ if !@base.site.layouts.find { |l| l.identifier == identifier }.nil?
56
+ $stderr.puts "A layout already exists at #{identifier}. Please " +
57
+ "pick a unique name for the layout you are creating."
58
+ exit 1
59
+ end
60
+
61
+ # Check whether layout is not at /
62
+ if identifier == '/'
63
+ $stderr.puts "There cannot be a layout with the identifier '/'; " +
64
+ "please pick a different identifier for this layout."
65
+ exit 1
66
+ end
67
+
68
+ # Setup notifications
69
+ Nanoc3::NotificationCenter.on(:file_created) do |file_path|
70
+ Nanoc3::CLI::Logger.instance.file(:high, :create, file_path)
71
+ end
72
+
73
+ # Create layout
74
+ data_source = @base.site.data_sources[0]
75
+ data_source.create_layout(
76
+ "<html>\n" +
77
+ " <head>\n" +
78
+ " <title><%= @item.title %></title>\n" +
79
+ " </head>\n" +
80
+ " <body>\n" +
81
+ " <p>Hi, I'm a new layout. Please customize me!</p>\n" +
82
+ "<%= yield %>\n" +
83
+ " </body>\n" +
84
+ "</html>\n",
85
+ {},
86
+ identifier
87
+ )
88
+
89
+ puts "A layout has been created at #{identifier}."
90
+ end
91
+
92
+ end
93
+
94
+ end