nanoc3 3.2.0a2 → 3.2.0a3

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS.md CHANGED
@@ -5,6 +5,30 @@
5
5
  * Sped up nanoc quite a bit
6
6
  * Added AsciiDoc filter
7
7
  * Added progress indicator for long-running filters
8
+ * Made all source data, such as item attributes, frozen during compilation
9
+ * Exposed RedCloth parameters in the filter [Vincent Driessen]
10
+ * Added --color option to force color on
11
+ * Cleaned up internals, deprecating several parts and/or marking them as
12
+ private in the progress
13
+
14
+ ## 3.1.5 (???)
15
+
16
+ * Improved `#render` documentation
17
+ * Improved metadata section check so that e.g. raw diffs are handled properly
18
+ * Deprecated using `Nanoc3::Site#initialize` with a non-`"."` argument
19
+ * Added Ruby engine to version string
20
+ * Allowed the `created_at` and `updated_at` attributes used in the`Blogging`
21
+ helper to be `Date` instances
22
+
23
+ ## 3.1.4 (2010-07-25)
24
+
25
+ * Made INT and TERM signals always quit the CLI
26
+ * Allowed relative imports in LESS
27
+ * Made sure modification times are unchanged for identical recompiled items
28
+ * Improved link validator error handling
29
+ * Made pygmentize not output extra divs and pres
30
+ * Allowed colorizers to be specified using symbols instead of strings
31
+ * Added scss to the default list of text extensions
8
32
 
9
33
  ## 3.1.3 (2010-04-25)
10
34
 
data/README.md CHANGED
@@ -74,9 +74,11 @@ may be interested in the development dependencies:
74
74
  * Dmitry Bilunov
75
75
  * Devon Luke Buchanan
76
76
  * Brian Candler
77
+ * Vincent Driessen
77
78
  * Chris Eppstein
78
79
  * Felix Hanley
79
80
  * Starr Horne
81
+ * Tuomas Kareinen
80
82
  * Ale Muñoz
81
83
  * Nicky Peeters
82
84
  * Christian Plessl
data/lib/nanoc3.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Nanoc3
4
4
 
5
5
  # The current nanoc version.
6
- VERSION = '3.2.0a2'
6
+ VERSION = '3.2.0a3'
7
7
 
8
8
  end
9
9
 
@@ -82,7 +82,7 @@ module Nanoc3
82
82
  #
83
83
  # @return [void]
84
84
  def calculate_all_checksums
85
- @site.objects.each { |obj| new_checksum_for(obj) }
85
+ @site.compiler.objects.each { |obj| new_checksum_for(obj) }
86
86
  end
87
87
 
88
88
  # @param [#reference] obj
@@ -40,6 +40,8 @@ module Nanoc3
40
40
  # the specified object.
41
41
  class Compiler
42
42
 
43
+ # @group Accessors
44
+
43
45
  # @return [Nanoc3::Site] The site this compiler belongs to
44
46
  attr_reader :site
45
47
 
@@ -68,6 +70,8 @@ module Nanoc3
68
70
  # loaded but before the site is compiled
69
71
  attr_accessor :preprocessor
70
72
 
73
+ # @group Public instance methods
74
+
71
75
  # Creates a new compiler fo the given site
72
76
  #
73
77
  # @param [Nanoc3::Site] site The site this compiler belongs to
@@ -96,6 +100,7 @@ module Nanoc3
96
100
 
97
101
  # Compile reps
98
102
  load
103
+ @site.freeze
99
104
  dependency_tracker.start
100
105
  compile_reps(reps)
101
106
  dependency_tracker.stop
@@ -105,6 +110,8 @@ module Nanoc3
105
110
  FileUtils.rm_rf(Nanoc3::Filter::TMP_BINARY_ITEMS_DIR)
106
111
  end
107
112
 
113
+ # @group Private instance methods
114
+
108
115
  # Load the helper data that is used for compiling the site.
109
116
  #
110
117
  # @api private
@@ -114,7 +121,8 @@ module Nanoc3
114
121
  return if @loaded
115
122
  @loaded = true
116
123
 
117
- stores.each { |s| s.load }
124
+ # Load site if necessary
125
+ @site.load
118
126
 
119
127
  # Preprocess
120
128
  load_rules
@@ -123,6 +131,9 @@ module Nanoc3
123
131
  build_reps
124
132
  route_reps
125
133
 
134
+ # Load auxiliary stores
135
+ stores.each { |s| s.load }
136
+
126
137
  # Determine which reps need to be recompiled
127
138
  dependency_tracker.propagate_outdatedness
128
139
  forget_dependencies_if_outdated(items)
@@ -260,7 +271,17 @@ module Nanoc3
260
271
  preprocessor_context.instance_eval(&preprocessor) if preprocessor
261
272
  end
262
273
 
263
- # FIXME get rid of this
274
+ # Returns all objects managed by the site (items, layouts, code snippets,
275
+ # site configuration and the rules).
276
+ #
277
+ # @api private
278
+ def objects
279
+ # FIXME remove reference to rules
280
+ site.items + site.layouts + site.code_snippets + [ site.config, self.rules_with_reference ]
281
+ end
282
+
283
+ # Returns the rules along with an unique reference (`:rules`) so that the
284
+ # outdatedness checker can use them.
264
285
  #
265
286
  # @api private
266
287
  def rules_with_reference
@@ -306,6 +327,9 @@ module Nanoc3
306
327
  # Get basic path by applying matching rule
307
328
  basic_path = rule.apply_to(rep, :compiler => self)
308
329
  next if basic_path.nil?
330
+ if basic_path !~ %r{^/}
331
+ raise RuntimeError, "The path returned for the #{rep.inspect} item representation, “#{basic_path}”, does not start with a slash. Please ensure that all routing rules return a path that starts with a slash.".make_compatible_with_env
332
+ end
309
333
 
310
334
  # Get raw path by prepending output directory
311
335
  rep.raw_paths[snapshot] = @site.config[:output_dir] + basic_path
@@ -328,9 +352,11 @@ module Nanoc3
328
352
  #
329
353
  # @return [Hash] The assigns that should be used in the next filter/layout
330
354
  # operation
355
+ #
356
+ # @api private
331
357
  def assigns_for(rep)
332
358
  if rep.binary?
333
- content_or_filename_assigns = { :filename => rep.filenames[:last] }
359
+ content_or_filename_assigns = { :filename => rep.temporary_filenames[:last] }
334
360
  else
335
361
  content_or_filename_assigns = { :content => rep.content[:last] }
336
362
  end
@@ -218,7 +218,8 @@ module Nanoc3
218
218
  # Load edges
219
219
  new_data[:edges].each do |edge|
220
220
  from_index, to_index = *edge
221
- from, to = @previous_objects[from_index], @previous_objects[to_index]
221
+ from = from_index && @previous_objects[from_index]
222
+ to = to_index && @previous_objects[to_index]
222
223
  @graph.add_edge(from, to)
223
224
  end
224
225
  end
@@ -67,6 +67,9 @@ module Nanoc3
67
67
  #
68
68
  # @return [void]
69
69
  def add_edge(from, to)
70
+ add_vertex(from)
71
+ add_vertex(to)
72
+
70
73
  @from_graph[from] ||= Set.new
71
74
  @from_graph[from] << to
72
75
 
@@ -107,6 +110,8 @@ module Nanoc3
107
110
  return if @vertices.include?(v)
108
111
 
109
112
  @vertices << v
113
+ @vertice_indexes[v] = @vertices.size-1
114
+
110
115
  @roots << v
111
116
  end
112
117
 
@@ -22,20 +22,11 @@ module Nanoc3
22
22
  #
23
23
  # @param [String] filename The filename corresponding to this code snippet
24
24
  #
25
- # @param [Time, Hash] params Extra parameters. For backwards
26
- # compatibility, this can be a Time instance indicating the time when
27
- # this code snippet was last modified (mtime).
28
- #
29
- # @option params [Time, nil] :mtime (nil) The time when this code snippet
30
- # was last modified
25
+ # @param [Time, Hash] params Extra parameters. Ignored by nanoc; it is
26
+ # only included for backwards compatibility.
31
27
  def initialize(data, filename, params=nil)
32
- # Parse params
33
- params ||= {}
34
- params = { :mtime => params } if params.is_a?(Time)
35
-
36
28
  @data = data
37
29
  @filename = filename
38
- @mtime = params[:mtime]
39
30
  end
40
31
 
41
32
  # Loads the code by executing it.
@@ -23,9 +23,6 @@ module Nanoc3
23
23
  # @return [String] This item's identifier
24
24
  attr_accessor :identifier
25
25
 
26
- # @return [Time] The time where this item was last modified
27
- attr_reader :mtime
28
-
29
26
  # @return [Array<Nanoc3::ItemRep>] This item’s list of item reps
30
27
  attr_reader :reps
31
28
 
@@ -60,7 +57,8 @@ module Nanoc3
60
57
  # this item was last modified (mtime).
61
58
  #
62
59
  # @option params [Time, nil] :mtime (nil) The time when this item was last
63
- # modified
60
+ # modified. Deprecated; pass the modification time as the `:mtime`
61
+ # attribute instead.
64
62
  #
65
63
  # @option params [Symbol, nil] :binary (true) Whether or not this item is
66
64
  # binary
@@ -70,9 +68,6 @@ module Nanoc3
70
68
  params = { :mtime => params } if params.is_a?(Time)
71
69
  params[:binary] = false unless params.has_key?(:binary)
72
70
 
73
- # Get mtime
74
- @mtime = params[:mtime]
75
-
76
71
  # Get type and raw content or raw filename
77
72
  @is_binary = params[:binary]
78
73
  if @is_binary
@@ -85,6 +80,9 @@ module Nanoc3
85
80
  @attributes = attributes.symbolize_keys
86
81
  @identifier = identifier.cleaned_identifier
87
82
 
83
+ # Set mtime
84
+ @attributes.merge(:mtime => params[:mtime]) if params[:mtime]
85
+
88
86
  @parent = nil
89
87
  @children = []
90
88
 
@@ -163,6 +161,19 @@ module Nanoc3
163
161
  Nanoc3::NotificationCenter.post(:visit_started, self)
164
162
  Nanoc3::NotificationCenter.post(:visit_ended, self)
165
163
 
164
+ # Get captured content (hax)
165
+ # TODO [in nanoc 4.0] remove me
166
+ if key.to_s =~ /^content_for_(.*)$/
167
+ # Include capturing helper if necessary
168
+ unless @_Nanoc3_Helpers_Capturing_included
169
+ self.class.send(:include, ::Nanoc3::Helpers::Capturing)
170
+ @_Nanoc3_Helpers_Capturing_included = true
171
+ end
172
+
173
+ # Get content
174
+ return content_for(self, $1.to_sym)
175
+ end
176
+
166
177
  @attributes[key]
167
178
  end
168
179
 
@@ -199,10 +210,21 @@ module Nanoc3
199
210
  [ type, self.identifier ]
200
211
  end
201
212
 
213
+ # Prevents all further modifications to itself, its items, its layouts etc.
214
+ #
215
+ # @return [void]
216
+ def freeze
217
+ attributes.freeze
218
+ end
202
219
  def inspect
203
220
  "<#{self.class}:0x#{self.object_id.to_s(16)} identifier=#{self.identifier} binary?=#{self.binary?}>"
204
221
  end
205
222
 
223
+ # @deprecated Access the modification time using `item[:mtime]` instead.
224
+ def mtime
225
+ self[:mtime]
226
+ end
227
+
206
228
  end
207
229
 
208
230
  end
@@ -16,9 +16,6 @@ module Nanoc3
16
16
  # slash
17
17
  attr_accessor :identifier
18
18
 
19
- # @return [Time] The time where this layout was last modified
20
- attr_reader :mtime
21
-
22
19
  # Creates a new layout.
23
20
  #
24
21
  # @param [String] raw_content The raw content of this layout.
@@ -32,18 +29,17 @@ module Nanoc3
32
29
  # this layout was last modified (mtime).
33
30
  #
34
31
  # @option params [Time, nil] :mtime (nil) The time when this layout was
35
- # last modified
32
+ # last modified. Deprecated; pass the modification time as the `:mtime`
33
+ # attribute instead.
36
34
  def initialize(raw_content, attributes, identifier, params=nil)
37
- # Parse params
38
- params ||= {}
39
- params = { :mtime => params } if params.is_a?(Time)
40
-
41
- # Get mtime
42
- @mtime = params[:mtime]
43
-
44
35
  @raw_content = raw_content
45
36
  @attributes = attributes.symbolize_keys
46
37
  @identifier = identifier.cleaned_identifier
38
+
39
+ # Set mtime
40
+ params ||= {}
41
+ params = { :mtime => params } if params.is_a?(Time)
42
+ @attributes.merge(:mtime => params[:mtime]) if params[:mtime]
47
43
  end
48
44
 
49
45
  # Requests the attribute with the given key.
@@ -78,6 +74,11 @@ module Nanoc3
78
74
  "<#{self.class}:0x#{self.object_id.to_s(16)} identifier=#{self.identifier}>"
79
75
  end
80
76
 
77
+ # @deprecated Access the modification time using `layout[:mtime]` instead.
78
+ def mtime
79
+ self[:mtime]
80
+ end
81
+
81
82
  end
82
83
 
83
84
  end
@@ -208,12 +208,16 @@ module Nanoc3
208
208
  end
209
209
  end
210
210
 
211
- # TODO document
211
+ # Prevents all further modifications to itself, its items, its layouts etc.
212
212
  #
213
- # @api private
214
- def objects
215
- # FIXME remove reference to rules
216
- items + layouts + code_snippets + [ config, compiler.rules_with_reference ]
213
+ # @return [void]
214
+ def freeze
215
+ super
216
+
217
+ config.freeze
218
+ items.each { |i| i.freeze }
219
+ layouts.each { |l| l.freeze }
220
+ code_snippets.each { |cs| cs.freeze }
217
221
  end
218
222
 
219
223
  # @deprecated It is no longer necessary to explicitly load site data. It
@@ -222,10 +226,12 @@ module Nanoc3
222
226
  warn 'It is no longer necessary to call Nanoc3::Site#load_data. This method no longer has any effect. All calls to this method can be safely removed.'
223
227
  end
224
228
 
225
- private
226
-
227
229
  # Loads the site data. It is not necessary to call this method explicitly;
228
230
  # it will be called when it is necessary.
231
+ #
232
+ # @api private
233
+ #
234
+ # @return [void]
229
235
  def load
230
236
  return if @data_loaded
231
237
  @data_loaded = true
@@ -243,6 +249,8 @@ module Nanoc3
243
249
  compiler.load
244
250
  end
245
251
 
252
+ private
253
+
246
254
  # Loads this site’s code and executes it.
247
255
  def load_code_snippets
248
256
  @code_snippets_loaded ||= false
@@ -296,6 +304,11 @@ module Nanoc3
296
304
  # {#initialize} for details.
297
305
  def build_config(dir_or_config_hash)
298
306
  if dir_or_config_hash.is_a? String
307
+ # Check whether it is supported
308
+ if dir_or_config_hash != '.'
309
+ warn 'WARNING: Calling Nanoc3::Site.new with a directory that is not the current working directory is not supported. It is recommended to change the directory before calling Nanoc3::Site.new. For example, instead of Nanoc3::Site.new(\'abc\'), use Dir.chdir(\'abc\') { Nanoc3::Site.new(\'.\') }.'
310
+ end
311
+
299
312
  # Read config from config.yaml in given dir
300
313
  config_path = File.join(dir_or_config_hash, 'config.yaml')
301
314
  @config = DEFAULT_CONFIG.merge(YAML.load_file(config_path).symbolize_keys)
@@ -55,6 +55,11 @@ module Nanoc3::CLI
55
55
  add_command(Nanoc3::CLI::Commands::Watch.new)
56
56
  end
57
57
 
58
+ # Returns a fully initialised base instance. It is recommended to use this
59
+ # shared instance than to create new ones, as this will be the instance
60
+ # that will be used when reading all code from the `lib/` directory.
61
+ #
62
+ # @return [Nanoc3::CLI::Base]
58
63
  def self.shared_base
59
64
  @shared_base ||= Nanoc3::CLI::Base.new
60
65
  end
@@ -64,8 +69,11 @@ module Nanoc3::CLI
64
69
  @debug
65
70
  end
66
71
 
67
- # Helper function which can be called when a command is executed that
68
- # requires a site, such as the compile command.
72
+ # Asserts that the current working directory contains a site
73
+ # ({Nanoc3::Site} instance). If no site is present, prints an error
74
+ # message and exits.
75
+ #
76
+ # @return [void]
69
77
  def require_site
70
78
  if site.nil?
71
79
  $stderr.puts 'The current working directory does not seem to be a ' +
@@ -74,7 +82,10 @@ module Nanoc3::CLI
74
82
  end
75
83
  end
76
84
 
77
- # Gets the site (Nanoc3::Site) in the current directory and loads its data.
85
+ # Gets the site ({Nanoc3::Site} instance) in the current directory and
86
+ # loads its data.
87
+ #
88
+ # @return [Nanoc3::Site] The site in the current working directory
78
89
  def site
79
90
  # Load site if possible
80
91
  if File.file?('config.yaml') && (!self.instance_variable_defined?(:@site) || @site.nil?)
@@ -89,8 +100,16 @@ module Nanoc3::CLI
89
100
  @site
90
101
  end
91
102
 
92
- # Inherited from ::Cri::Base
103
+ # @see ::Cri::Base#run
93
104
  def run(args)
105
+ # Set exit handler
106
+ [ 'INT', 'TERM' ].each do |signal|
107
+ Signal.trap(signal) do
108
+ puts
109
+ exit!(0)
110
+ end
111
+ end
112
+
94
113
  super(args)
95
114
  rescue Interrupt => e
96
115
  exit(1)
@@ -99,8 +118,12 @@ module Nanoc3::CLI
99
118
  exit(1)
100
119
  end
101
120
 
102
- # Prints the given error to stderr. Includes message, possible resolution,
103
- # compilation stack, backtrace, etc.
121
+ # Prints the given error to stderr. Includes message, possible resolution
122
+ # (see {#resolution_for}), compilation stack, backtrace, etc.
123
+ #
124
+ # @param [Error] error The error that should be described
125
+ #
126
+ # @return [void]
104
127
  def print_error(error)
105
128
  $stderr.puts
106
129
 
@@ -144,8 +167,12 @@ module Nanoc3::CLI
144
167
  $stderr.puts error.backtrace.to_enum(:each_with_index).map { |item, index| " #{index}. #{item}" }.join("\n")
145
168
  end
146
169
 
147
- # Returns a string containing hints for resolving the given error, or nil
148
- # if no resolution can be automatically obtained.
170
+ # Attempts to find a resolution for the given error, or nil if no
171
+ # resolution can be automatically obtained.
172
+ #
173
+ # @param [Error] error The error to find a resolution for
174
+ #
175
+ # @return [String] The resolution for the given error
149
176
  def resolution_for(error)
150
177
  case error
151
178
  when LoadError
@@ -157,12 +184,22 @@ module Nanoc3::CLI
157
184
  if gem_name
158
185
  "Try installing the '#{gem_name}' gem (`gem install #{gem_name}`) and then re-running the command."
159
186
  end
187
+ when RuntimeError
188
+ if error.message =~ /^can't modify frozen/
189
+ "You attempted to modify immutable data. Some data, such as " \
190
+ "item/layout attributes and raw item/layout content, can no " \
191
+ "longer be modified once compilation has started."
192
+ end
160
193
  end
161
194
  end
162
195
 
163
196
  # Sets the data source's VCS to the VCS with the given name. Does nothing
164
197
  # when the site's data source does not support VCSes (i.e. does not
165
198
  # implement #vcs=).
199
+ #
200
+ # @param [String] vcs_name The name of the VCS that should be used
201
+ #
202
+ # @return [void]
166
203
  def set_vcs(vcs_name)
167
204
  # Skip if not possible
168
205
  return if vcs_name.nil? || site.nil?
@@ -183,13 +220,17 @@ module Nanoc3::CLI
183
220
  end
184
221
  end
185
222
 
186
- # Returns the list of global option definitionss.
223
+ # @return [Array] The list of global option definitions
187
224
  def global_option_definitions
188
225
  [
189
226
  {
190
227
  :long => 'help', :short => 'h', :argument => :forbidden,
191
228
  :desc => 'show this help message and quit'
192
229
  },
230
+ {
231
+ :long => 'color', :short => 'l', :argument => :forbidden,
232
+ :desc => 'enable color'
233
+ },
193
234
  {
194
235
  :long => 'no-color', :short => 'C', :argument => :forbidden,
195
236
  :desc => 'disable color'
@@ -213,13 +254,15 @@ module Nanoc3::CLI
213
254
  ]
214
255
  end
215
256
 
257
+ # @see Cri::Base#handle_option
216
258
  def handle_option(option)
217
259
  case option
218
260
  when :version
219
261
  gem_info = defined?(Gem) ? "with RubyGems #{Gem::VERSION}" : "without RubyGems"
262
+ engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
220
263
 
221
264
  puts "nanoc #{Nanoc3::VERSION} (c) 2007-2010 Denis Defreyne."
222
- puts "Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) running on #{RUBY_PLATFORM} #{gem_info}"
265
+ puts "Running #{engine} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) on #{RUBY_PLATFORM} #{gem_info}"
223
266
  exit 0
224
267
  when :verbose
225
268
  Nanoc3::CLI::Logger.instance.level = :low
@@ -227,6 +270,8 @@ module Nanoc3::CLI
227
270
  @debug = true
228
271
  when :warn
229
272
  $-w = true
273
+ when :color
274
+ Nanoc3::CLI::Logger.instance.color = true
230
275
  when :'no-color'
231
276
  Nanoc3::CLI::Logger.instance.color = false
232
277
  when :help
@@ -53,7 +53,7 @@ module Nanoc3::CLI::Commands
53
53
  puts "item #{item.identifier} depends on:"
54
54
  predecessors = dependency_tracker.direct_predecessors_of(item).sort_by { |i| i.identifier }
55
55
  predecessors.each do |pred|
56
- puts " #{pred.identifier}"
56
+ puts " [ #{format '%6s', pred.type} ] #{pred.identifier}"
57
57
  end
58
58
  puts " (nothing)" if predecessors.empty?
59
59
  puts
@@ -31,11 +31,7 @@ module Nanoc3::CLI::Commands
31
31
 
32
32
  def run(options, arguments)
33
33
  require 'fssm'
34
-
35
- Signal.trap("INT") do
36
- puts
37
- exit
38
- end
34
+ require 'pathname'
39
35
 
40
36
  @notifier = Notifier.new
41
37
 
@@ -119,7 +115,7 @@ module Nanoc3::CLI::Commands
119
115
  # @param [String] message The message to include in the notification
120
116
  def notify(message)
121
117
  return if tool.nil?
122
- send(tool.tr('-', '_'), message, params)
118
+ send(tool.tr('-', '_'), message)
123
119
  end
124
120
 
125
121
  private
@@ -128,11 +124,11 @@ module Nanoc3::CLI::Commands
128
124
  @tool ||= TOOLS.find { |t| !`which #{t}`.empty? }
129
125
  end
130
126
 
131
- def growlnotify(message, params={})
127
+ def growlnotify(message)
132
128
  system('growlnotify', '-m', message)
133
129
  end
134
130
 
135
- def notify_send(message, params={})
131
+ def notify_send(message)
136
132
  system('notify-send', message)
137
133
  end
138
134
 
@@ -8,6 +8,8 @@ module Nanoc3::CLI
8
8
  # feedback in the terminal.
9
9
  class Logger
10
10
 
11
+ # Maps actions (`:create`, `:update`, `:identical` and `:skip`) onto their
12
+ # ANSI color codes.
11
13
  ACTION_COLORS = {
12
14
  :create => "\e[1m" + "\e[32m", # bold + green
13
15
  :update => "\e[1m" + "\e[33m", # bold + yellow
@@ -17,35 +19,43 @@ module Nanoc3::CLI
17
19
 
18
20
  include Singleton
19
21
 
20
- # The log level, which can be :high, :low or :off (which will log all
21
- # messages, only high-priority messages, or no messages at all,
22
+ # Returns the log level, which can be :high, :low or :off (which will log
23
+ # all messages, only high-priority messages, or no messages at all,
22
24
  # respectively).
25
+ #
26
+ # @return [Symbol] The log level
23
27
  attr_accessor :level
24
28
 
25
- # Whether to use color in log messages or not
26
- attr_accessor :color
27
- alias_method :color?, :color
29
+ # @return [Boolean] True if color should be used, false otherwise
30
+ attr_writer :color
28
31
 
29
32
  def initialize
30
33
  @level = :high
31
- @color = $stdout.tty?
34
+ end
32
35
 
33
- # Try enabling color support on Windows
34
- begin
35
- require 'Win32/Console/ANSI' if RUBY_PLATFORM =~/mswin|mingw/
36
- rescue LoadError
37
- @color = false
36
+ # @return [Boolean] true if colors are enabled, false otherwise
37
+ def color?
38
+ if @color.nil?
39
+ @color = true
40
+ begin
41
+ require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /mswin|mingw/
42
+ rescue LoadError
43
+ @color = false
44
+ end
38
45
  end
46
+
47
+ @color
39
48
  end
40
49
 
41
50
  # Logs a file-related action.
42
51
  #
43
- # +level+:: The importance of this action. Can be :high or :low.
52
+ # @param [:high, :low] level The importance of this action
44
53
  #
45
- # +action+:: The kind of file action. Can be :create, :update or
46
- # :identical.
54
+ # @param [:create, :update, :identical] action The kind of file action
47
55
  #
48
- # +identifier+:: The identifier of the item the action was performed on.
56
+ # @param [String] name The name of the file the action was performed on
57
+ #
58
+ # @return [void]
49
59
  def file(level, action, identifier, duration=nil)
50
60
  log(
51
61
  level,
@@ -61,18 +71,19 @@ module Nanoc3::CLI
61
71
 
62
72
  # Logs a message.
63
73
  #
64
- # +level+:: The importance of this message. Can be :high or :low.
74
+ # @param [:high, :low] level The importance of this message
75
+ #
76
+ # @param [String] message The message to be logged
65
77
  #
66
- # +s+:: The message to be logged.
78
+ # @param [#puts] io The stream to which the message should be written
67
79
  #
68
- # +io+:: The IO instance to which the message will be written. Defaults to
69
- # standard output.
70
- def log(level, s, io=$stdout)
80
+ # @return [void]
81
+ def log(level, message, io=$stdout)
71
82
  # Don't log when logging is disabled
72
83
  return if @level == :off
73
84
 
74
85
  # Log when level permits it
75
- io.puts(s) if (@level == :low or @level == level)
86
+ io.puts(message) if (@level == :low or @level == level)
76
87
  end
77
88
 
78
89
  end
@@ -238,7 +238,7 @@ module Nanoc3::DataSources
238
238
  data = File.read(content_filename)
239
239
 
240
240
  # Check presence of metadata section
241
- if data[0, 3] != '-'*3 && data[0, 5] != '-'*5
241
+ if data !~ /\A-{3,5}\s*$/
242
242
  return [ {}, data ]
243
243
  end
244
244
 
@@ -107,8 +107,23 @@ module Nanoc3::Filters
107
107
  code
108
108
  end
109
109
 
110
+ # Runs the content through [pygmentize](http://pygments.org/docs/cmdline/),
111
+ # the commandline frontend for [Pygments](http://pygments.org/).
112
+ #
113
+ # @api private
114
+ #
115
+ # @param [String] code The code to colorize
116
+ #
117
+ # @param [String] language The language the code is written in
118
+ #
119
+ # @option params [String, Symbol] :encoding The encoding of the code block
120
+ #
121
+ # @return [String] The colorized output
110
122
  def pygmentize(code, language, params={})
111
- IO.popen("pygmentize -l #{language} -f html", "r+") do |io|
123
+ enc = ""
124
+ enc = "-O encoding=" + params[:encoding] if params[:encoding]
125
+
126
+ IO.popen("pygmentize -l #{language} -f html #{enc}", "r+") do |io|
112
127
  io.write(code)
113
128
  io.close_write
114
129
  highlighted_code = io.read
@@ -3,8 +3,22 @@
3
3
  module Nanoc3::Filters
4
4
  class RedCloth < Nanoc3::Filter
5
5
 
6
- # Runs the content through [RedCloth](http://redcloth.org/).
7
- # This method takes no options.
6
+ # Runs the content through [RedCloth](http://redcloth.org/). This method
7
+ # takes the following options:
8
+ #
9
+ # * `:filter_class`
10
+ # * `:filter_html`
11
+ # * `:filter_ids`
12
+ # * `:filter_style`
13
+ # * `:hard_breaks`
14
+ # * `:lite_mode`
15
+ # * `:no_span_caps`
16
+ # * `:sanitize_htm`
17
+ #
18
+ # Each of these options sets the corresponding attribute on the `RedCloth`
19
+ # instance. For example, when the `:hard_breaks => false` option is passed
20
+ # to this filter, the filter will call `r.hard_breaks = false` (with `r`
21
+ # being the `RedCloth` instance).
8
22
  #
9
23
  # @param [String] content The content to filter
10
24
  #
@@ -12,8 +26,21 @@ module Nanoc3::Filters
12
26
  def run(content, params={})
13
27
  require 'redcloth'
14
28
 
29
+ # Create formatter
30
+ r = ::RedCloth.new(content)
31
+
32
+ # Set options
33
+ r.filter_classes = params[:filter_classes] if params.has_key?(:filter_classes)
34
+ r.filter_html = params[:filter_html] if params.has_key?(:filter_html)
35
+ r.filter_ids = params[:filter_ids] if params.has_key?(:filter_ids)
36
+ r.filter_styles = params[:filter_styles] if params.has_key?(:filter_styles)
37
+ r.hard_breaks = params[:hard_breaks] if params.has_key?(:hard_breaks)
38
+ r.lite_mode = params[:lite_mode] if params.has_key?(:lite_mode)
39
+ r.no_span_caps = params[:no_span_caps] if params.has_key?(:no_span_caps)
40
+ r.sanitize_html = params[:sanitize_html] if params.has_key?(:sanitize_html)
41
+
15
42
  # Get result
16
- ::RedCloth.new(content).to_html
43
+ r.to_html
17
44
  end
18
45
 
19
46
  end
@@ -39,8 +39,7 @@ module Nanoc3::Helpers
39
39
  def sorted_articles
40
40
  require 'time'
41
41
  articles.sort_by do |a|
42
- time = a[:created_at]
43
- time.is_a?(String) ? Time.parse(time) : time
42
+ attribute_to_time(a[:created_at])
44
43
  end.reverse
45
44
  end
46
45
 
@@ -183,8 +182,7 @@ module Nanoc3::Helpers
183
182
 
184
183
  # Get sorted relevant articles
185
184
  sorted_relevant_articles = relevant_articles.sort_by do |a|
186
- time = a[:created_at]
187
- time.is_a?(String) ? Time.parse(time) : time
185
+ attribute_to_time(a[:created_at])
188
186
  end.reverse.first(limit)
189
187
 
190
188
  # Get most recent article
@@ -204,8 +202,7 @@ module Nanoc3::Helpers
204
202
  xml.title title
205
203
 
206
204
  # Add date
207
- time = last_article[:created_at]
208
- xml.updated((time.is_a?(String) ? Time.parse(time) : time).to_iso8601_time)
205
+ xml.updated(attribute_to_time(last_article[:created_at]).to_iso8601_time)
209
206
 
210
207
  # Add links
211
208
  xml.link(:rel => 'alternate', :href => root_url)
@@ -229,10 +226,8 @@ module Nanoc3::Helpers
229
226
  xml.title a[:title], :type => 'html'
230
227
 
231
228
  # Add dates
232
- create_time = a[:created_at]
233
- update_time = a[:updated_at] || a[:created_at]
234
- xml.published((create_time.is_a?(String) ? Time.parse(create_time) : create_time).to_iso8601_time)
235
- xml.updated( (update_time.is_a?(String) ? Time.parse(update_time) : update_time).to_iso8601_time)
229
+ xml.published attribute_to_time(a[:created_at]).to_iso8601_time
230
+ xml.updated attribute_to_time(a[:updated_at] || a[:created_at]).to_iso8601_time
236
231
 
237
232
  # Add specific author information
238
233
  if a[:author_name] || a[:author_uri]
@@ -305,12 +300,24 @@ module Nanoc3::Helpers
305
300
 
306
301
  hostname, base_dir = %r{^.+?://([^/]+)(.*)$}.match(@site.config[:base_url])[1..2]
307
302
 
308
- time = item[:created_at]
309
- formatted_date = (time.is_a?(String) ? Time.parse(time) : time).to_iso8601_date
303
+ formatted_date = attribute_to_time(item[:created_at]).to_iso8601_date
310
304
 
311
305
  'tag:' + hostname + ',' + formatted_date + ':' + base_dir + (item.path || item.identifier)
312
306
  end
313
307
 
308
+ # Converts the given attribute (which can be a string, a Time or a Date)
309
+ # into a Time.
310
+ #
311
+ # @param [String, Time, Date] time Something that contains time
312
+ # information but is not necessarily a Time instance yet
313
+ #
314
+ # @return [Time] The Time instance corresponding to the given input
315
+ def attribute_to_time(time)
316
+ time = Time.local(time.year, time.month, time.day) if time.is_a?(Date)
317
+ time = Time.parse(time) if time.is_a?(String)
318
+ time
319
+ end
320
+
314
321
  end
315
322
 
316
323
  end
@@ -12,7 +12,10 @@ module Nanoc3::Helpers
12
12
  # you write the summary on the item itself, but capture it, and print it in
13
13
  # the sidebar layout.
14
14
  #
15
- # @example Capturing content into a `content_for_summary` attribute
15
+ # This helper has been tested with ERB and Haml. Other filters may not work
16
+ # correctly.
17
+ #
18
+ # @example Capturing content for a summary
16
19
  #
17
20
  # <% content_for :summary do %>
18
21
  # <p>On this item, nanoc is introduced, blah blah.</p>
@@ -22,28 +25,95 @@ module Nanoc3::Helpers
22
25
  #
23
26
  # <div id="sidebar">
24
27
  # <h3>Summary</h3>
28
+ # <%= content_for(@item, :summary) || '(no summary)' %>
29
+ # </div>
30
+ #
31
+ # @example Showing captured content in a sidebar the old, deprecated way (do not use or I will become very angry)
32
+ #
33
+ # <div id="sidebar">
34
+ # <h3>Summary</h3>
25
35
  # <%= @item[:content_for_summary] || '(no summary)' %>
26
36
  # </div>
27
37
  module Capturing
28
38
 
29
- # Captures the content inside the block and stores it in an item
30
- # attribute named `content_for_` followed by the given name. The
31
- # content of the block itself will not be outputted.
39
+ # @api private
40
+ class CapturesStore
41
+
42
+ require 'singleton'
43
+ include Singleton
44
+
45
+ def initialize
46
+ @store = {}
47
+ end
48
+
49
+ def []=(item, name, content)
50
+ @store[item.identifier] ||= {}
51
+ @store[item.identifier][name] = content
52
+ end
53
+
54
+ def [](item, name)
55
+ @store[item.identifier] ||= {}
56
+ @store[item.identifier][name]
57
+ end
58
+
59
+ end
60
+
61
+ # @overload content_for(name, &block)
62
+ #
63
+ # Captures the content inside the block and stores it so that it can be
64
+ # referenced later on. The same method, {#content_for}, is used for
65
+ # getting the captured content as well as setting it. When capturing,
66
+ # the content of the block itself will not be outputted.
67
+ #
68
+ # For backwards compatibility, it is also possible to fetch the captured
69
+ # content by getting the contents of the attribute named `content_for_`
70
+ # followed by the given name. This way of accessing captures is
71
+ # deprecated.
72
+ #
73
+ # @param [Symbol, String] name The base name of the attribute into which
74
+ # the content should be stored
75
+ #
76
+ # @return [void]
77
+ #
78
+ # @overload content_for(item, name)
32
79
  #
33
- # @param [Symbol, String] The base name of the attribute into which the
34
- # content should be stored
80
+ # Fetches the capture with the given name from the given item and
81
+ # returns it.
35
82
  #
36
- # @return [void]
37
- def content_for(name, &block)
38
- eval("@item[:content_for_#{name.to_s}] = capture(&block)")
83
+ # @param [Nanoc3::Item] item The item for which to get the capture
84
+ #
85
+ # @param [Symbol, String] name The name of the capture to fetch
86
+ #
87
+ # @return [String] The stored captured content
88
+ def content_for(*args, &block)
89
+ if block_given? # Set content
90
+ # Get args
91
+ if args.size != 1
92
+ raise ArgumentError, "expected 1 argument (the name " +
93
+ "of the capture) but got #{args.size} instead"
94
+ end
95
+ name = args[0]
96
+
97
+ # Capture and store
98
+ content = capture(&block)
99
+ CapturesStore.instance[@item, name.to_sym] = content
100
+ else # Get content
101
+ # Get args
102
+ if args.size != 2
103
+ raise ArgumentError, "expected 2 arguments (the item " +
104
+ "and the name of the capture) but got #{args.size} instead"
105
+ end
106
+ item = args[0]
107
+ name = args[1]
108
+
109
+ # Get content
110
+ CapturesStore.instance[item, name.to_sym]
111
+ end
39
112
  end
40
113
 
41
- # Evaluates the given block and returns the result. The contents of the
114
+ # Evaluates the given block and returns its contents. The contents of the
42
115
  # block is not outputted.
43
116
  #
44
- # This function has been tested with ERB and Haml. Other filters may not
45
- # work correctly.
46
- #
47
117
  # @return [String] The captured result
48
118
  def capture(&block)
49
119
  # Get erbout so far
@@ -7,7 +7,18 @@ module Nanoc3::Helpers
7
7
 
8
8
  include Nanoc3::Helpers::Capturing
9
9
 
10
- # Returns a string containing the rendered given layout.
10
+ # Returns a string containing the rendered given layout. The given layout
11
+ # will first be run through the matching layout rule.
12
+ #
13
+ # The assigns (`@item`, `@config`, …) will not be available in the
14
+ # partial, but it is possible to pass custom assigns to the method. These
15
+ # assigns will be made available as instance variables inside the partial.
16
+ #
17
+ # The method can also take a block. In this case, the content of the block
18
+ # will be captured (using the {Nanoc3::Helpers::Capturing} helper) and
19
+ # this content will be made available with `yield`. In other words, a
20
+ # `yield` inside the partial will output the content of the block passed
21
+ # to the method.
11
22
  #
12
23
  # @param [String] identifier The identifier of the layout that should be
13
24
  # rendered
@@ -29,6 +40,18 @@ module Nanoc3::Helpers
29
40
  # <%= render 'head', :title => 'Foo' %>
30
41
  # # => "<h1>Foo</h1>"
31
42
  #
43
+ # @example Yielding inside a partial
44
+ #
45
+ # # The 'box' partial
46
+ # <div class="box">
47
+ # <%= yield %>
48
+ # </div>
49
+ #
50
+ # # The item/layout where the partial is rendered
51
+ # <% render 'box' do %>
52
+ # I'm boxy! Luvz!
53
+ # <% end %>
54
+ #
32
55
  # @raise [Nanoc3::Errors::UnknownLayout] if the given layout does not
33
56
  # exist
34
57
  #
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc3
3
3
  version: !ruby/object:Gem::Version
4
- hash: -142061300
4
+ hash: -794993270
5
5
  prerelease: true
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
- - 0a2
10
- version: 3.2.0a2
9
+ - 0a3
10
+ version: 3.2.0a3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Denis Defreyne
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-09 00:00:00 +02:00
18
+ date: 2010-08-24 00:00:00 +02:00
19
19
  default_executable: nanoc3
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency