nanoc3 3.1.0a2 → 3.1.0a3

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 (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
  #