nanoc3 3.1.0a2 → 3.1.0a3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/LICENSE +1 -1
  2. data/NEWS.md +12 -2
  3. data/README.md +2 -0
  4. data/lib/nanoc3/base/code_snippet.rb +6 -2
  5. data/lib/nanoc3/base/compiler.rb +9 -6
  6. data/lib/nanoc3/base/compiler_dsl.rb +15 -9
  7. data/lib/nanoc3/base/data_source.rb +14 -14
  8. data/lib/nanoc3/base/dependency_tracker.rb +9 -9
  9. data/lib/nanoc3/base/directed_graph.rb +6 -7
  10. data/lib/nanoc3/base/errors.rb +48 -13
  11. data/lib/nanoc3/base/filter.rb +62 -16
  12. data/lib/nanoc3/base/item.rb +63 -20
  13. data/lib/nanoc3/base/item_rep.rb +117 -48
  14. data/lib/nanoc3/base/layout.rb +18 -5
  15. data/lib/nanoc3/base/notification_center.rb +8 -8
  16. data/lib/nanoc3/base/plugin_registry.rb +9 -9
  17. data/lib/nanoc3/base/rule.rb +8 -8
  18. data/lib/nanoc3/base/rule_context.rb +5 -5
  19. data/lib/nanoc3/base/site.rb +33 -29
  20. data/lib/nanoc3/cli/base.rb +1 -1
  21. data/lib/nanoc3/cli/commands/create_site.rb +12 -14
  22. data/lib/nanoc3/cli.rb +0 -1
  23. data/lib/nanoc3/data_sources/filesystem.rb +12 -2
  24. data/lib/nanoc3/data_sources/filesystem_unified.rb +22 -19
  25. data/lib/nanoc3/extra/auto_compiler.rb +12 -3
  26. data/lib/nanoc3/extra/chick.rb +12 -6
  27. data/lib/nanoc3/extra/deployers/rsync.rb +30 -27
  28. data/lib/nanoc3/extra/deployers.rb +0 -1
  29. data/lib/nanoc3/extra/file_proxy.rb +2 -15
  30. data/lib/nanoc3/extra/validators/links.rb +242 -0
  31. data/lib/nanoc3/extra/validators/w3c.rb +49 -25
  32. data/lib/nanoc3/extra/validators.rb +2 -2
  33. data/lib/nanoc3/extra/vcs.rb +1 -1
  34. data/lib/nanoc3/extra.rb +4 -1
  35. data/lib/nanoc3/helpers/blogging.rb +57 -29
  36. data/lib/nanoc3/helpers/breadcrumbs.rb +1 -1
  37. data/lib/nanoc3/helpers/capturing.rb +4 -2
  38. data/lib/nanoc3/helpers/filtering.rb +2 -1
  39. data/lib/nanoc3/helpers/link_to.rb +13 -6
  40. data/lib/nanoc3/helpers/rendering.rb +4 -3
  41. data/lib/nanoc3/helpers/tagging.rb +7 -6
  42. data/lib/nanoc3/helpers/text.rb +2 -2
  43. data/lib/nanoc3/tasks/validate.rake +62 -5
  44. data/lib/nanoc3.rb +2 -2
  45. metadata +23 -11
  46. data/lib/nanoc3/base/core_ext/enumerable.rb +0 -41
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007-2009 Denis Defreyne and contributors
1
+ Copyright (c) 2007-2010 Denis Defreyne and contributors
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/NEWS.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  ## 3.1
4
4
 
5
- New:
6
-
7
5
  * An `Item#rep(name)` function for quickly getting a certain rep
8
6
  * An `Item#compiled_content` function for quickly getting compiled content
9
7
  * An `Item#path` function for quickly getting the path of an item rep
@@ -42,6 +40,18 @@ Deprecated:
42
40
  * The `last_fm`, `delicious` and `twitter` data sources; fetch online content
43
41
  into a cache by a rake task and load data from this cache instead
44
42
 
43
+ ## 3.0.9
44
+
45
+ * Fixed 1.8.x parsing bug due to lack of parens which could cause “undefined
46
+ method `to_iso8601_time` for #<String:0x…>” errors
47
+
48
+ ## 3.0.8
49
+
50
+ * `#atom_tag_for` now works with base_urls that contain a path [Eric Sunshine]
51
+ * Generated root URLs in `#atom_feed` now end with a slash [Eric Sunshine]
52
+ * Autocompiler now recognises requests to index files
53
+ * `Blogging` helper now allows created_at to be a Time instance
54
+
45
55
  ## 3.0.7
46
56
 
47
57
  * Fixed a bug which could cause layout rules not be matched in order
data/README.md CHANGED
@@ -5,6 +5,8 @@ It operates on local files, and therefore does not run on the server. nanoc
5
5
  “compiles” the local source files into HTML (usually), by evaluating eRuby,
6
6
  Markdown, etc.
7
7
 
8
+ Note: This documentation looks best with Yardoc, not RDoc.
9
+
8
10
  ## Resources
9
11
 
10
12
  The [nanoc web site](http://nanoc.stoneship.org) contains a few useful
@@ -29,9 +29,13 @@ module Nanoc3
29
29
 
30
30
  # Creates a new code snippet.
31
31
  #
32
- # @param [String] data The raw source code which will be executed before compilation
32
+ # @param [String] data The raw source code which will be executed before
33
+ # compilation
34
+ #
33
35
  # @param [String] filename The filename corresponding to this code snippet
34
- # @param [Time] mtime The time when the code was last modified (can be nil)
36
+ #
37
+ # @param [Time] mtime The time when the code was last modified (can be
38
+ # nil)
35
39
  def initialize(data, filename, mtime=nil)
36
40
  @data = data
37
41
  @filename = filename
@@ -47,10 +47,10 @@ module Nanoc3
47
47
  # representations.
48
48
  #
49
49
  # @param [Nanoc3::Item] item The item that should be compiled, along with
50
- # its dependencies. Pass `nil` if the entire site should be compiled.
50
+ # its dependencies. Pass `nil` if the entire site should be compiled.
51
51
  #
52
52
  # @option params [Boolean] :force (false) true if the rep should be
53
- # compiled even if it is not outdated, false if not
53
+ # compiled even if it is not outdated, false if not
54
54
  #
55
55
  # @return [void]
56
56
  def run(item=nil, params={})
@@ -83,6 +83,9 @@ module Nanoc3
83
83
  compile_reps(reps)
84
84
  dependency_tracker.stop
85
85
 
86
+ # Cleanup
87
+ FileUtils.rm_rf(Nanoc3::Filter::TMP_BINARY_ITEMS_DIR)
88
+
86
89
  # Store dependencies
87
90
  dependency_tracker.store_graph
88
91
  end
@@ -93,7 +96,7 @@ module Nanoc3
93
96
  # @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
94
97
  #
95
98
  # @return [Nanoc3::Rule, nil] The compilation rule for the given item rep,
96
- # or nil if no rules have been found
99
+ # or nil if no rules have been found
97
100
  def compilation_rule_for(rep)
98
101
  @item_compilation_rules.find do |rule|
99
102
  rule.applicable_to?(rep.item) && rule.rep_name == rep.name
@@ -105,7 +108,7 @@ module Nanoc3
105
108
  # @param [Nanoc3::ItemRep] rep The item rep for which to fetch the rule
106
109
  #
107
110
  # @return [Nanoc3::Rule, nil] The routing rule for the given item rep, or
108
- # nil if no rules have been found
111
+ # nil if no rules have been found
109
112
  def routing_rule_for(rep)
110
113
  @item_routing_rules.find do |rule|
111
114
  rule.applicable_to?(rep.item) && rule.rep_name == rep.name
@@ -117,7 +120,7 @@ module Nanoc3
117
120
  # @param [Nanoc3::Layout] layout The layout for which to fetch the filter.
118
121
  #
119
122
  # @return [Array, nil] A tuple containing the filter name and the filter
120
- # arguments for the given layout.
123
+ # arguments for the given layout.
121
124
  def filter_for_layout(layout)
122
125
  @layout_filter_mapping.each_pair do |layout_identifier, filter_name_and_args|
123
126
  return filter_name_and_args if layout.identifier =~ layout_identifier
@@ -228,7 +231,7 @@ module Nanoc3
228
231
  # Clears the list of dependencies for items that will be recompiled.
229
232
  #
230
233
  # @param [Array<Nanoc3::Item>] items The list of items for which to forget
231
- # the dependencies
234
+ # the dependencies
232
235
  #
233
236
  # @return [void]
234
237
  def forget_dependencies_if_outdated(items)
@@ -33,22 +33,24 @@ module Nanoc3
33
33
  # rep as a block argument.
34
34
  #
35
35
  # @param [String] identifier A pattern matching identifiers of items that
36
- # should be compiled using this rule
36
+ # should be compiled using this rule
37
37
  #
38
38
  # @option params [Symbol] :rep (:default) The name of the representation
39
- # that should be compiled using this rule
39
+ # that should be compiled using this rule
40
40
  #
41
41
  # @yield The block that will be executed when an item matching this
42
- # compilation rule needs to be compiled
42
+ # compilation rule needs to be compiled
43
43
  #
44
44
  # @return [void]
45
45
  #
46
46
  # @example Compiling the default rep of the `/foo/` item
47
+ #
47
48
  # compile '/foo/' do
48
49
  # rep.filter :erb
49
50
  # end
50
51
  #
51
52
  # @example Compiling the `:raw` rep of the `/bar/` item
53
+ #
52
54
  # compile '/bar/', :rep => :raw do
53
55
  # # do nothing
54
56
  # end
@@ -75,22 +77,24 @@ module Nanoc3
75
77
  # and passing the rep as a block argument.
76
78
  #
77
79
  # @param [String] identifier A pattern matching identifiers of items that
78
- # should be routed using this rule
80
+ # should be routed using this rule
79
81
  #
80
82
  # @option params [Symbol] :rep (:default) The name of the representation
81
- # that should be routed using this rule
83
+ # that should be routed using this rule
82
84
  #
83
85
  # @yield The block that will be executed when an item matching this
84
- # compilation rule needs to be routed
86
+ # compilation rule needs to be routed
85
87
  #
86
88
  # @return [void]
87
89
  #
88
90
  # @example Routing the default rep of the `/foo/` item
91
+ #
89
92
  # route '/foo/' do
90
93
  # item.identifier + 'index.html'
91
94
  # end
92
95
  #
93
96
  # @example Routing the `:raw` rep of the `/bar/` item
97
+ #
94
98
  # route '/bar/', :rep => :raw do
95
99
  # '/raw' + item.identifier + 'index.txt'
96
100
  # end
@@ -113,20 +117,22 @@ module Nanoc3
113
117
  # contains filter arguments that will be passed to the filter.
114
118
  #
115
119
  # @param [String] identifier A pattern matching identifiers of layouts
116
- # that should be filtered using this rule
120
+ # that should be filtered using this rule
117
121
  #
118
122
  # @param [Symbol] filter_name The name of the filter that should be run
119
- # when processing the layout
123
+ # when processing the layout
120
124
  #
121
125
  # @param [Hash] params Extra filter arguments that should be passed to the
122
- # filter when processing the layout (see {Nanoc3::Filter#run})
126
+ # filter when processing the layout (see {Nanoc3::Filter#run})
123
127
  #
124
128
  # @return [void]
125
129
  #
126
130
  # @example Specifying the filter to use for a layout
131
+ #
127
132
  # layout '/default/', :erb
128
133
  #
129
134
  # @example Using custom filter arguments for a layout
135
+ #
130
136
  # layout '/custom/', :haml, :format => :html5
131
137
  def layout(identifier, filter_name, params={})
132
138
  @site.compiler.layout_filter_mapping[identifier_to_regex(identifier)] = [ filter_name, params ]
@@ -27,15 +27,15 @@ module Nanoc3
27
27
  class DataSource
28
28
 
29
29
  # @return [String] The root path where items returned by this data source
30
- # should be mounted.
30
+ # should be mounted.
31
31
  attr_reader :items_root
32
32
 
33
33
  # @return [String] The root path where layouts returned by this data
34
- # source should be mounted.
34
+ # source should be mounted.
35
35
  attr_reader :layouts_root
36
36
 
37
37
  # @return [Hash] The configuration for this data source. For example,
38
- # online data sources could contain authentication details.
38
+ # online data sources could contain authentication details.
39
39
  attr_reader :config
40
40
 
41
41
  extend Nanoc3::PluginRegistry::PluginMethods
@@ -45,12 +45,12 @@ module Nanoc3
45
45
  # @param [Nanoc3::Site] site The site this data source belongs to.
46
46
  #
47
47
  # @param [String] items_root The prefix that should be given to all items
48
- # returned by the #items method (comparable to mount points for
49
- # filesystems in Unix-ish OSes).
48
+ # returned by the #items method (comparable to mount points for
49
+ # filesystems in Unix-ish OSes).
50
50
  #
51
51
  # @param [String] layouts_root The prefix that should be given to all
52
- # layouts returned by the #layouts method (comparable to mount points
53
- # for filesystems in Unix-ish OSes).
52
+ # layouts returned by the #layouts method (comparable to mount points
53
+ # for filesystems in Unix-ish OSes).
54
54
  #
55
55
  # @param [Hash] config The configuration for this data source.
56
56
  def initialize(site, items_root, layouts_root, config)
@@ -93,7 +93,7 @@ module Nanoc3
93
93
  #
94
94
  # Calling this method decreases the internal reference count. When the
95
95
  # reference count reaches zero, i.e. when the data source is not used any
96
- # more, the data soruce will be unloaded ({#down} will be called).
96
+ # more, the data source will be unloaded ({#down} will be called).
97
97
  #
98
98
  # @return [void]
99
99
  def unuse
@@ -189,9 +189,9 @@ module Nanoc3
189
189
  # @param [String] identifier
190
190
  #
191
191
  # @param [Hash] params Extra parameters to give to the data source. This
192
- # can be used to influence the way items are stored. For example,
193
- # filesystem data sources could use this to pass the extension of the
194
- # files that should be generated.
192
+ # can be used to influence the way items are stored. For example,
193
+ # filesystem data sources could use this to pass the extension of the
194
+ # files that should be generated.
195
195
  #
196
196
  # @return [void]
197
197
  def create_item(content, attributes, identifier, params={})
@@ -212,9 +212,9 @@ module Nanoc3
212
212
  # @param [String] identifier
213
213
  #
214
214
  # @param [Hash] params Extra parameters to give to the data source. This
215
- # can be used to influence the way items are stored. For example,
216
- # filesystem data sources could use this to pass the extension of the
217
- # files that should be generated.
215
+ # can be used to influence the way items are stored. For example,
216
+ # filesystem data sources could use this to pass the extension of the
217
+ # files that should be generated.
218
218
  #
219
219
  # @return [void]
220
220
  def create_layout(content, attributes, identifier, params={})
@@ -24,7 +24,7 @@ module Nanoc3
24
24
  class DependencyTracker
25
25
 
26
26
  # @return [String] The name of the file in which dependency information is
27
- # stored
27
+ # stored
28
28
  attr_accessor :filename
29
29
 
30
30
  # The version of the file format used to store dependencies.
@@ -33,7 +33,7 @@ module Nanoc3
33
33
  # Creates a new dependency tracker for the given items.
34
34
  #
35
35
  # @param [Array<Nanoc3::Item>] item The list of items whose dependencies
36
- # should be managed
36
+ # should be managed
37
37
  def initialize(items)
38
38
  @items = items
39
39
  @filename = 'tmp/dependencies'
@@ -89,7 +89,7 @@ module Nanoc3
89
89
  # direct dependencies of A do not include C).
90
90
  #
91
91
  # @param [Nanoc3::Item] item The item for which to fetch the direct
92
- # predecessors
92
+ # predecessors
93
93
  #
94
94
  # @return [Array<Nanoc3::Item>] The direct predecessors of the given item
95
95
  def direct_predecessors_of(item)
@@ -102,7 +102,7 @@ module Nanoc3
102
102
  # cause `item` to be marked as outdated.
103
103
  #
104
104
  # @param [Nanoc3::Item] item The item for which to fetch all direct and
105
- # indirect predecessors
105
+ # indirect predecessors
106
106
  #
107
107
  # @return [Array<Nanoc3::Item>] The predecessors of the given item
108
108
  def predecessors_of(item)
@@ -117,7 +117,7 @@ module Nanoc3
117
117
  # direct inverse dependencies of C do not include A).
118
118
  #
119
119
  # @param [Nanoc3::Item] item The item for which to fetch the direct
120
- # successors
120
+ # successors
121
121
  #
122
122
  # @return [Array<Nanoc3::Item>] The direct successors of the given item
123
123
  def direct_successors_of(item)
@@ -130,7 +130,7 @@ module Nanoc3
130
130
  # as outdated when `item` is outdated.
131
131
  #
132
132
  # @param [Nanoc3::Item] item The item for which to fetch all direct and
133
- # indirect successors
133
+ # indirect successors
134
134
  #
135
135
  # @return [Array<Nanoc3::Item>] The successors of the given item
136
136
  def successors_of(item)
@@ -141,11 +141,11 @@ module Nanoc3
141
141
  # `dst` is oudated, `src` will also become outdated.
142
142
  #
143
143
  # @param [Nanoc3::Item] src The source of the dependency, i.e. the item
144
- # that will become outdated if dst is outdated
144
+ # that will become outdated if dst is outdated
145
145
  #
146
146
  # @param [Nanoc3::Item] dst The destination of the dependency, i.e. the
147
- # item that will cause the source to become outdated if the destination
148
- # is outdated
147
+ # item that will cause the source to become outdated if the destination
148
+ # is outdated
149
149
  #
150
150
  # @return [void]
151
151
  def record_dependency(src, dst)
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Nanoc3
4
4
 
5
- # Nanoc3::DirectedGraph represents a directed graph. It is used by the
6
- # dependency tracker for storing and querying dependencies between items.
7
- # Internally, the graph will be stored as an adjacency matrix. For this,
8
- # the {Nanoc3::DirectedGraph::SquareBooleanMatrix} class is used.
5
+ # Represents a directed graph. It is used by the dependency tracker for
6
+ # storing and querying dependencies between items. Internally, the graph
7
+ # will be stored as an adjacency matrix. For this, the
8
+ # {Nanoc3::DirectedGraph::SquareBooleanMatrix} class is used.
9
9
  #
10
10
  # @example Creating and using a directed graph
11
11
  #
@@ -33,15 +33,14 @@ module Nanoc3
33
33
  # # => %w( b c )
34
34
  class DirectedGraph
35
35
 
36
- # Nanoc3::DirectedGraph::SquareBooleanMatrix is, as the name says, a
37
- # square matrix that contains boolean values. It is used as an adjacency
36
+ # A square matrix that contains boolean values. It is used as an adjacency
38
37
  # matrix by the {Nanoc3::DirectedGraph} class.
39
38
  class SquareBooleanMatrix
40
39
 
41
40
  # Creates a new matrix with the given number of rows/columns.
42
41
  #
43
42
  # @param [Number] size The number of elements along both sides of the
44
- # matrix (in other words, the square root of the number of elements)
43
+ # matrix (in other words, the square root of the number of elements)
45
44
  def initialize(size)
46
45
  @size = size
47
46
  end
@@ -14,7 +14,7 @@ module Nanoc3
14
14
  class UnknownDataSource < Generic
15
15
 
16
16
  # @param [String] data_source_name The data source name for which no
17
- # data source could be found
17
+ # data source could be found
18
18
  def initialize(data_source_name)
19
19
  super("The data source specified in the site's configuration file, #{data_source_name}, does not exist.")
20
20
  end
@@ -26,7 +26,7 @@ module Nanoc3
26
26
  class UnknownLayout < Generic
27
27
 
28
28
  # @param [String] layout_identifier The layout identifier for which no
29
- # layout could be found
29
+ # layout could be found
30
30
  def initialize(layout_identifier)
31
31
  super("The site does not have a layout with identifier '#{layout_identifier}'.")
32
32
  end
@@ -38,7 +38,7 @@ module Nanoc3
38
38
  class UnknownFilter < Generic
39
39
 
40
40
  # @param [Symbol] filter_name The filter name for which no filter could
41
- # be found
41
+ # be found
42
42
  def initialize(filter_name)
43
43
  super("The requested filter, #{filter_name}, does not exist.")
44
44
  end
@@ -51,7 +51,7 @@ module Nanoc3
51
51
  class CannotDetermineFilter < Generic
52
52
 
53
53
  # @param [String] layout_identifier The identifier of the layout for
54
- # which the filter could not be determined
54
+ # which the filter could not be determined
55
55
  def initialize(layout_identifier)
56
56
  super("The filter to be used for the '#{layout_identifier}' could not be determined. Make sure the layout does have a filter.")
57
57
  end
@@ -63,12 +63,12 @@ module Nanoc3
63
63
  class DataNotYetAvailable < Generic
64
64
 
65
65
  # @param [String] type The name of the data type that is not yet
66
- # available. For example: `"site"`, `"items"`.
66
+ # available. For example: `"site"`, `"items"`.
67
67
  #
68
68
  # @param [Boolean] plural True if the given type is plural, false
69
- # otherwise. This only has an effect on the exception message. For
70
- # example, if the given type is `"site"`, plural would be `false`; if
71
- # the given type is `"items"`, plural would be `true`.
69
+ # otherwise. This only has an effect on the exception message. For
70
+ # example, if the given type is `"site"`, plural would be `false`; if
71
+ # the given type is `"items"`, plural would be `true`.
72
72
  def initialize(type, plural)
73
73
  super("#{type} #{plural ? 'are' : 'is'} not available yet. You may be missing a Nanoc3::Site#load_data call.")
74
74
  end
@@ -80,7 +80,7 @@ module Nanoc3
80
80
  class RecursiveCompilation < Generic
81
81
 
82
82
  # @param [Array<Nanoc3::ItemRep>] reps A list of item representations
83
- # that mutually depend on each other
83
+ # that mutually depend on each other
84
84
  def initialize(reps)
85
85
  super("The site cannot be compiled because the following items mutually depend on each other: #{reps.inspect}.")
86
86
  end
@@ -102,7 +102,7 @@ module Nanoc3
102
102
  class NoMatchingCompilationRuleFound < Generic
103
103
 
104
104
  # @param [Nanoc3::Item] item The item for which no compilation rule
105
- # could be found
105
+ # could be found
106
106
  def initialize(item)
107
107
  super("No compilation rules were found for the '#{item.identifier}' item.")
108
108
  end
@@ -114,7 +114,7 @@ module Nanoc3
114
114
  class NoMatchingRoutingRuleFound < Generic
115
115
 
116
116
  # @param [Nanoc3::Item] item The item for which no routing rule could be
117
- # found
117
+ # found
118
118
  def initialize(rep)
119
119
  super("No routing rules were found for the '#{rep.item.identifier}' item (rep '#{rep.name}').")
120
120
  end
@@ -126,11 +126,11 @@ module Nanoc3
126
126
  class UnmetDependency < Generic
127
127
 
128
128
  # @return [Nanoc3::ItemRep] The item representation that cannot yet be
129
- # compiled
129
+ # compiled
130
130
  attr_reader :rep
131
131
 
132
132
  # @param [Nanoc3::ItemRep] The item representation that cannot yet be
133
- # compiled
133
+ # compiled
134
134
  def initialize(rep)
135
135
  @rep = rep
136
136
  super("The '#{rep.item.identifier}' item (rep '#{rep.name}') cannot currently be compiled yet due to an unmet dependency.")
@@ -138,6 +138,41 @@ module Nanoc3
138
138
 
139
139
  end
140
140
 
141
+ # Error that is raised when a binary item is attempted to be laid out.
142
+ class CannotLayoutBinaryItem < Generic
143
+
144
+ # @param [Nanoc3::ItemRep] The item representation that was attempted to
145
+ # be laid out
146
+ def initialize(rep)
147
+ super("The '#{rep.item.identifier}' item (rep '#{rep.name}') cannot be laid out because it is a binary item.")
148
+ end
149
+
150
+ end
151
+
152
+ class CannotUseTextualFilter < Generic
153
+
154
+ # @param [Nanoc3::ItemRep] rep The item representation that was
155
+ # attempted to be filtered
156
+ #
157
+ # @param [Class] filter_class The filter class that was used
158
+ def initialize(rep, filter_class)
159
+ super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because textual filters cannot be used on binary items.")
160
+ end
161
+
162
+ end
163
+
164
+ class CannotUseBinaryFilter < Generic
165
+
166
+ # @param [Nanoc3::ItemRep] rep The item representation that was
167
+ # attempted to be filtered
168
+ #
169
+ # @param [Class] filter_class The filter class that was used
170
+ def initialize(rep, filter_class)
171
+ super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because binary filters cannot be used on textual items.")
172
+ end
173
+
174
+ end
175
+
141
176
  end
142
177
 
143
178
  end
@@ -5,6 +5,9 @@ module Nanoc3
5
5
  # Nanoc3::Filter is responsible for filtering items. It is the superclass
6
6
  # for all textual filters.
7
7
  #
8
+ # A filter instance should only be used once. Filters should not be reused
9
+ # since they store state.
10
+ #
8
11
  # When creating a filter with a hash containing assigned variables, those
9
12
  # variables will be made available in the `@assigns` instance variable and
10
13
  # the {#assigns} method. The assigns itself will also be available as
@@ -12,19 +15,22 @@ module Nanoc3
12
15
  #
13
16
  # @example Accessing assigns in different ways
14
17
  #
15
- # filter = SomeFilter.new({ :foo => 'bar' })
16
- # filter.instance_eval { @assigns[:foo] }
17
- # # => 'bar'
18
- # filter.instance_eval { assigns[:foo] }
19
- # # => 'bar'
20
- # filter.instance_eval { @foo }
21
- # # => 'bar'
22
- # filter.instance_eval { foo }
23
- # # => 'bar'
18
+ # filter = SomeFilter.new({ :foo => 'bar' })
19
+ # filter.instance_eval { @assigns[:foo] }
20
+ # # => 'bar'
21
+ # filter.instance_eval { assigns[:foo] }
22
+ # # => 'bar'
23
+ # filter.instance_eval { @foo }
24
+ # # => 'bar'
25
+ # filter.instance_eval { foo }
26
+ # # => 'bar'
24
27
  #
25
28
  # @abstract Subclass and override {#run} to implement a custom filter.
26
29
  class Filter < Context
27
30
 
31
+ # The path to the directory where temporary binary items are stored
32
+ TMP_BINARY_ITEMS_DIR = 'tmp/binary_items'
33
+
28
34
  # A hash containing variables that will be made available during
29
35
  # filtering.
30
36
  #
@@ -33,29 +39,69 @@ module Nanoc3
33
39
 
34
40
  extend Nanoc3::PluginRegistry::PluginMethods
35
41
 
42
+ class << self
43
+
44
+ # Sets the new type for the filter (`:binary` or `:text`).
45
+ #
46
+ # @param [Symbol] arg The new type of this filter
47
+ #
48
+ # @return [void]
49
+ def type(arg)
50
+ @type = arg
51
+ end
52
+
53
+ # @return [Boolean] True if this is a binary filter, false otherwise
54
+ def binary?
55
+ (@type || :text) == :binary
56
+ end
57
+
58
+ end
59
+
36
60
  # Creates a new filter that has access to the given assigns.
37
61
  #
38
- # @param [Hash] a_assigns A hash containing variables that should be made
39
- # available during filtering.
62
+ # @param [Hash] hash A hash containing variables that should be made
63
+ # available during filtering.
40
64
  def initialize(hash={})
41
65
  @assigns = hash
42
66
  super
43
67
  end
44
68
 
45
- # Runs the filter on the given content.
69
+ # Runs the filter on the given content or filename.
46
70
  #
47
71
  # @abstract
48
72
  #
49
- # @param [String] content The unprocessed content that should be filtered.
73
+ # @param [String] content_or_filename The unprocessed content that should
74
+ # be filtered (if the item is a textual item) or the path to the file that
75
+ # should be fitlered (if the item is a binar item)
50
76
  #
51
77
  # @param [Hash] params A hash containing parameters. Filter subclasses can
52
- # use these parameters to allow modifying the filter's behaviour.
78
+ # use these parameters to allow modifying the filter's behaviour.
53
79
  #
54
- # @return [String] The filtered content
55
- def run(content, params={})
80
+ # @return [String] The filtered content (if the item is a textual item) or
81
+ # a path to a newly generated file containing the filtered content (if the
82
+ # item is a binary item)
83
+ def run(content_or_filename, params={})
56
84
  raise NotImplementedError.new("Nanoc3::Filter subclasses must implement #run")
57
85
  end
58
86
 
87
+ # Returns a filename that is used to write data to. This method is only
88
+ # used on binary items. When running a binary filter on a file, the
89
+ # resulting file must end up in the location returned by this method.
90
+ #
91
+ # @return [String] The output filename
92
+ def output_filename
93
+ @output_filename ||= begin
94
+ require 'tempfile'
95
+
96
+ FileUtils.mkdir_p(TMP_BINARY_ITEMS_DIR)
97
+ tempfile = Tempfile.new(filename.gsub(/[^a-z]/, '-'), TMP_BINARY_ITEMS_DIR)
98
+ new_filename = tempfile.path
99
+ tempfile.close!
100
+
101
+ new_filename
102
+ end
103
+ end
104
+
59
105
  # Returns the filename associated with the item that is being filtered.
60
106
  # It is in the format `item <identifier> (rep <name>)`.
61
107
  #