nanoc2 2.2.3

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 (100) hide show
  1. data/ChangeLog +3 -0
  2. data/LICENSE +19 -0
  3. data/README +75 -0
  4. data/Rakefile +76 -0
  5. data/bin/nanoc2 +26 -0
  6. data/lib/nanoc2.rb +73 -0
  7. data/lib/nanoc2/base.rb +26 -0
  8. data/lib/nanoc2/base/asset.rb +117 -0
  9. data/lib/nanoc2/base/asset_defaults.rb +21 -0
  10. data/lib/nanoc2/base/asset_rep.rb +282 -0
  11. data/lib/nanoc2/base/binary_filter.rb +44 -0
  12. data/lib/nanoc2/base/code.rb +41 -0
  13. data/lib/nanoc2/base/compiler.rb +67 -0
  14. data/lib/nanoc2/base/core_ext.rb +2 -0
  15. data/lib/nanoc2/base/core_ext/hash.rb +78 -0
  16. data/lib/nanoc2/base/core_ext/string.rb +8 -0
  17. data/lib/nanoc2/base/data_source.rb +286 -0
  18. data/lib/nanoc2/base/defaults.rb +30 -0
  19. data/lib/nanoc2/base/filter.rb +93 -0
  20. data/lib/nanoc2/base/layout.rb +91 -0
  21. data/lib/nanoc2/base/notification_center.rb +66 -0
  22. data/lib/nanoc2/base/page.rb +132 -0
  23. data/lib/nanoc2/base/page_defaults.rb +20 -0
  24. data/lib/nanoc2/base/page_rep.rb +324 -0
  25. data/lib/nanoc2/base/plugin.rb +71 -0
  26. data/lib/nanoc2/base/proxies.rb +5 -0
  27. data/lib/nanoc2/base/proxies/asset_proxy.rb +29 -0
  28. data/lib/nanoc2/base/proxies/asset_rep_proxy.rb +26 -0
  29. data/lib/nanoc2/base/proxies/layout_proxy.rb +25 -0
  30. data/lib/nanoc2/base/proxies/page_proxy.rb +35 -0
  31. data/lib/nanoc2/base/proxies/page_rep_proxy.rb +28 -0
  32. data/lib/nanoc2/base/proxy.rb +37 -0
  33. data/lib/nanoc2/base/router.rb +72 -0
  34. data/lib/nanoc2/base/site.rb +274 -0
  35. data/lib/nanoc2/base/template.rb +64 -0
  36. data/lib/nanoc2/binary_filters.rb +1 -0
  37. data/lib/nanoc2/binary_filters/image_science_thumbnail.rb +28 -0
  38. data/lib/nanoc2/cli.rb +9 -0
  39. data/lib/nanoc2/cli/base.rb +132 -0
  40. data/lib/nanoc2/cli/commands.rb +10 -0
  41. data/lib/nanoc2/cli/commands/autocompile.rb +80 -0
  42. data/lib/nanoc2/cli/commands/compile.rb +312 -0
  43. data/lib/nanoc2/cli/commands/create_layout.rb +85 -0
  44. data/lib/nanoc2/cli/commands/create_page.rb +85 -0
  45. data/lib/nanoc2/cli/commands/create_site.rb +323 -0
  46. data/lib/nanoc2/cli/commands/create_template.rb +76 -0
  47. data/lib/nanoc2/cli/commands/help.rb +69 -0
  48. data/lib/nanoc2/cli/commands/info.rb +125 -0
  49. data/lib/nanoc2/cli/commands/switch.rb +141 -0
  50. data/lib/nanoc2/cli/commands/update.rb +91 -0
  51. data/lib/nanoc2/cli/logger.rb +72 -0
  52. data/lib/nanoc2/data_sources.rb +2 -0
  53. data/lib/nanoc2/data_sources/filesystem.rb +707 -0
  54. data/lib/nanoc2/data_sources/filesystem_combined.rb +495 -0
  55. data/lib/nanoc2/extra.rb +6 -0
  56. data/lib/nanoc2/extra/auto_compiler.rb +285 -0
  57. data/lib/nanoc2/extra/context.rb +22 -0
  58. data/lib/nanoc2/extra/core_ext.rb +2 -0
  59. data/lib/nanoc2/extra/core_ext/hash.rb +54 -0
  60. data/lib/nanoc2/extra/core_ext/time.rb +13 -0
  61. data/lib/nanoc2/extra/file_proxy.rb +29 -0
  62. data/lib/nanoc2/extra/vcs.rb +48 -0
  63. data/lib/nanoc2/extra/vcses.rb +5 -0
  64. data/lib/nanoc2/extra/vcses/bazaar.rb +21 -0
  65. data/lib/nanoc2/extra/vcses/dummy.rb +20 -0
  66. data/lib/nanoc2/extra/vcses/git.rb +21 -0
  67. data/lib/nanoc2/extra/vcses/mercurial.rb +21 -0
  68. data/lib/nanoc2/extra/vcses/subversion.rb +21 -0
  69. data/lib/nanoc2/filters.rb +16 -0
  70. data/lib/nanoc2/filters/bluecloth.rb +13 -0
  71. data/lib/nanoc2/filters/erb.rb +19 -0
  72. data/lib/nanoc2/filters/erubis.rb +14 -0
  73. data/lib/nanoc2/filters/haml.rb +21 -0
  74. data/lib/nanoc2/filters/markaby.rb +14 -0
  75. data/lib/nanoc2/filters/maruku.rb +14 -0
  76. data/lib/nanoc2/filters/old.rb +19 -0
  77. data/lib/nanoc2/filters/rainpress.rb +13 -0
  78. data/lib/nanoc2/filters/rdiscount.rb +13 -0
  79. data/lib/nanoc2/filters/rdoc.rb +23 -0
  80. data/lib/nanoc2/filters/redcloth.rb +14 -0
  81. data/lib/nanoc2/filters/relativize_paths.rb +16 -0
  82. data/lib/nanoc2/filters/relativize_paths_in_css.rb +16 -0
  83. data/lib/nanoc2/filters/relativize_paths_in_html.rb +16 -0
  84. data/lib/nanoc2/filters/rubypants.rb +14 -0
  85. data/lib/nanoc2/filters/sass.rb +18 -0
  86. data/lib/nanoc2/helpers.rb +9 -0
  87. data/lib/nanoc2/helpers/blogging.rb +217 -0
  88. data/lib/nanoc2/helpers/capturing.rb +63 -0
  89. data/lib/nanoc2/helpers/filtering.rb +54 -0
  90. data/lib/nanoc2/helpers/html_escape.rb +25 -0
  91. data/lib/nanoc2/helpers/link_to.rb +113 -0
  92. data/lib/nanoc2/helpers/render.rb +49 -0
  93. data/lib/nanoc2/helpers/tagging.rb +56 -0
  94. data/lib/nanoc2/helpers/text.rb +38 -0
  95. data/lib/nanoc2/helpers/xml_sitemap.rb +63 -0
  96. data/lib/nanoc2/routers.rb +3 -0
  97. data/lib/nanoc2/routers/default.rb +54 -0
  98. data/lib/nanoc2/routers/no_dirs.rb +66 -0
  99. data/lib/nanoc2/routers/versioned.rb +79 -0
  100. metadata +185 -0
@@ -0,0 +1,8 @@
1
+ class String
2
+
3
+ # Transforms string into an actual path
4
+ def cleaned_path
5
+ "/#{self}/".gsub(/^\/+|\/+$/, '/')
6
+ end
7
+
8
+ end
@@ -0,0 +1,286 @@
1
+ module Nanoc2
2
+
3
+ # Nanoc2::DataSource is responsible for loading data. It is the (abstract)
4
+ # superclass for all data sources. Subclasses must at least implement the
5
+ # data reading methods (+pages+, +page_defaults+, +layouts+, +templates+,
6
+ # and +code+); all other methods involving data manipulation are optional.
7
+ #
8
+ # Apart from the methods for loading and storing data, there are the +up+
9
+ # and +down+ methods for bringing up and tearing down the connection to the
10
+ # data source. These should be overridden in subclasses. The +loading+
11
+ # method wraps +up+ and +down+.
12
+ #
13
+ # The +setup+ method is used for setting up a site's data source for the
14
+ # first time. This method should be overridden in subclasses.
15
+ class DataSource < Plugin
16
+
17
+ # Creates a new data source for the given site.
18
+ def initialize(site)
19
+ @site = site
20
+ @references = 0
21
+ end
22
+
23
+ # Loads the data source when necessary (calling +up+), yields, and unloads
24
+ # the data source when it is not being used elsewhere. All data source
25
+ # queries and data manipulations should be wrapped in a +loading+ block;
26
+ # it ensures that the data source is loaded when necessary and makes sure
27
+ # the data source does not get unloaded while it is still being used
28
+ # elsewhere.
29
+ def loading
30
+ # Load if necessary
31
+ up if @references == 0
32
+ @references += 1
33
+
34
+ yield
35
+ ensure
36
+ # Unload if necessary
37
+ @references -= 1
38
+ down if @references == 0
39
+ end
40
+
41
+ ########## Loading and unloading
42
+
43
+ # Brings up the connection to the data. This is an abstract method
44
+ # implemented by the subclass. Depending on the way data is stored, this
45
+ # may not be necessary. This is the ideal place to connect to the
46
+ # database, for example.
47
+ #
48
+ # Subclasses may implement this method.
49
+ def up
50
+ end
51
+
52
+ # Brings down the connection to the data. This is an abstract method
53
+ # implemented by the subclass. This method should undo the effects of
54
+ # +up+.
55
+ #
56
+ # Subclasses may implement this method.
57
+ def down
58
+ end
59
+
60
+ ########## Creating/updating
61
+
62
+ # Creates the bare minimum essentials for this data source to work. This
63
+ # action will likely be destructive. This method should not create sample
64
+ # data such as a default home page, a default layout, etc. For example, if
65
+ # you're using a database, this is where you should create the necessary
66
+ # tables for the data source to function properly.
67
+ #
68
+ # Subclasses must implement this method.
69
+ def setup
70
+ not_implemented('setup')
71
+ end
72
+
73
+ # Removes all data stored by this data source. This method undoes the
74
+ # effects of the +setup+ method.
75
+ #
76
+ # Subclasses must implement this method.
77
+ def destroy
78
+ not_implemented('destroy')
79
+ end
80
+
81
+ # Updated the content stored in this site to a newer version. A newer
82
+ # version of a data source may store content in a different format, and
83
+ # this method will update the stored content to this newer format.
84
+ #
85
+ # Subclasses may implement this method.
86
+ def update
87
+ end
88
+
89
+ ########## Pages
90
+
91
+ # Returns the list of pages (represented by Nanoc2::Page) in this site.
92
+ # This is an abstract method implemented by the subclass.
93
+ #
94
+ # Subclasses must implement this method.
95
+ def pages
96
+ not_implemented('pages')
97
+ end
98
+
99
+ # Saves the given page in the data source, creating it if it doesn't exist
100
+ # yet and updating the existing copy otherwise.
101
+ #
102
+ # Subclasses must implement this method.
103
+ def save_page(page)
104
+ not_implemented('save_page')
105
+ end
106
+
107
+ # Changes the path of the given page to the given new path. When changing
108
+ # a page's path, this method must be used (save_page will not work).
109
+ #
110
+ # Subclasses must implement this method.
111
+ def move_page(page, new_path)
112
+ not_implemented('move_page')
113
+ end
114
+
115
+ # Removes the given page from the data source.
116
+ #
117
+ # Subclasses must implement this method.
118
+ def delete_page(page)
119
+ not_implemented('delete_page')
120
+ end
121
+
122
+ ########## Assets
123
+
124
+ # Returns the list of assets (represented by Nanoc2::Asset) in this site.
125
+ # This is an abstract method implemented by the subclass.
126
+ #
127
+ # Subclasses must implement this method.
128
+ def assets
129
+ not_implemented('assets')
130
+ end
131
+
132
+ # Saves the given asset in the data source, creating it if it doesn't
133
+ # exist yet and updating the existing copy otherwise.
134
+ #
135
+ # Subclasses must implement this method.
136
+ def save_asset(asset)
137
+ not_implemented('save_asset')
138
+ end
139
+
140
+ # Changes the path of the given asset to the given new path. When changing
141
+ # a asset's path, this method must be used (save_asset will not work).
142
+ #
143
+ # Subclasses must implement this method.
144
+ def move_asset(asset, new_path)
145
+ not_implemented('move_asset')
146
+ end
147
+
148
+ # Removes the given asset from the data source.
149
+ #
150
+ # Subclasses must implement this method.
151
+ def delete_asset(asset)
152
+ not_implemented('delete_asset')
153
+ end
154
+
155
+ ########## Page defaults
156
+
157
+ # Returns the page defaults (represented by Nanoc2::PageDefaults) of this
158
+ # site. This is an abstract method implemented by the subclass.
159
+ #
160
+ # Subclasses must implement this method.
161
+ def page_defaults
162
+ not_implemented('page_defaults')
163
+ end
164
+
165
+ # Saves the given page defaults in the data source.
166
+ #
167
+ # Subclasses must implement this method.
168
+ def save_page_defaults(page_defaults)
169
+ not_implemented('save_page_defaults')
170
+ end
171
+
172
+ ########## Asset defaults
173
+
174
+ # Returns the asset defaults (represented by Nanoc2::AssetDefaults) of this
175
+ # site. This is an abstract method implemented by the subclass.
176
+ #
177
+ # Subclasses must implement this method.
178
+ def asset_defaults
179
+ not_implemented('asset_defaults')
180
+ end
181
+
182
+ # Saves the given asset defaults in the data source.
183
+ #
184
+ # Subclasses must implement this method.
185
+ def save_asset_defaults(asset_defaults)
186
+ not_implemented('save_asset_defaults')
187
+ end
188
+
189
+ ########## Layouts
190
+
191
+ # Returns the list of layouts (represented by Nanoc2::Layout) in this site.
192
+ # This is an abstract method implemented by the subclass.
193
+ #
194
+ # Subclasses must implement this method.
195
+ def layouts
196
+ not_implemented('layouts')
197
+ end
198
+
199
+ # Saves the given layout in the data source, creating it if it doesn't
200
+ # exist yet and updating the existing copy otherwise.
201
+ #
202
+ # Subclasses must implement this method.
203
+ def save_layout(layout)
204
+ not_implemented('save_layout')
205
+ end
206
+
207
+ # Changes the path of the given layout to the given new path. When
208
+ # changing a layout's path, this method must be used (save_layout will not
209
+ # work).
210
+ #
211
+ # Subclasses must implement this method.
212
+ def move_layout(layout, new_path)
213
+ not_implemented('move_layout')
214
+ end
215
+
216
+ # Removes the given layout from the data source.
217
+ #
218
+ # Subclasses must implement this method.
219
+ def delete_layout(layout)
220
+ not_implemented('delete_layout')
221
+ end
222
+
223
+ ########## Templates
224
+
225
+ # Returns the list of templates (represented by Nanoc2::Template) in this
226
+ # site. This is an abstract method implemented by the subclass.
227
+ #
228
+ # Subclasses must implement this method.
229
+ def templates
230
+ not_implemented('templates')
231
+ end
232
+
233
+ # Saves the given template in the data source, creating it if it doesn't
234
+ # exist yet and updating the existing copy otherwise.
235
+ #
236
+ # Subclasses must implement this method.
237
+ def save_template(template)
238
+ not_implemented('save_template')
239
+ end
240
+
241
+ # Changes the name of the given template to the given new name. When
242
+ # changing a template's name, this method must be used (save_template will
243
+ # not work).
244
+ #
245
+ # Subclasses must implement this method.
246
+ def move_template(template, new_name)
247
+ not_implemented('move_template')
248
+ end
249
+
250
+ # Removes the given template from the data source.
251
+ #
252
+ # Subclasses must implement this method.
253
+ def delete_template(template)
254
+ not_implemented('delete_template')
255
+ end
256
+
257
+ ########## Code
258
+
259
+ # Returns the custom code (represented by Nanoc2::Code) for this site.
260
+ # This is an abstract method implemented by the subclass. This can be code
261
+ # for custom filters, routers, and more, but pretty much any code can
262
+ # be put in there (global helper functions are very useful).
263
+ #
264
+ # Subclasses must implement this method.
265
+ def code
266
+ not_implemented('code')
267
+ end
268
+
269
+ # Saves the given code in the data source.
270
+ #
271
+ # Subclasses must implement this method.
272
+ def save_code(code)
273
+ not_implemented('save_code')
274
+ end
275
+
276
+ private
277
+
278
+ def not_implemented(name)
279
+ raise NotImplementedError.new(
280
+ "#{self.class} does not override ##{name}, which is required for " +
281
+ "this data source to be used."
282
+ )
283
+ end
284
+
285
+ end
286
+ end
@@ -0,0 +1,30 @@
1
+ module Nanoc2
2
+
3
+ # Nanoc2::Defaults represent the default attributes for a given set of
4
+ # objects in the site. It is basically a hash with an optional modification
5
+ # time.
6
+ class Defaults
7
+
8
+ # Th site where this set of defaults belongs to.
9
+ attr_accessor :site
10
+
11
+ # A hash containing the default attributes.
12
+ attr_reader :attributes
13
+
14
+ # The time when this set of defaults was last modified.
15
+ attr_reader :mtime
16
+
17
+ # Creates a new set of defaults.
18
+ #
19
+ # +attributes+:: The hash containing the metadata that individual objects
20
+ # will override.
21
+ #
22
+ # +mtime+:: The time when the defaults were last modified (optional).
23
+ def initialize(attributes, mtime=nil)
24
+ @attributes = attributes.clean
25
+ @mtime = mtime
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,93 @@
1
+ module Nanoc2
2
+
3
+ # Nanoc2::Filter is responsible for filtering pages and textual assets
4
+ # (binary assets are filtered using Nanoc2::BinaryFilter). It is the
5
+ # (abstract) superclass for all textual filters. Subclasses should override
6
+ # the +run+ method.
7
+ class Filter < Plugin
8
+
9
+ # Deprecated
10
+ EXTENSIONS_MAP = {}
11
+
12
+ # Creates a new filter for the given object (page or asset) and site.
13
+ #
14
+ # +kind+:: The kind of object that is passed. Can be either +:page+ or
15
+ # +:asset+.
16
+ #
17
+ # +obj_rep+:: A proxy for the page or asset representation (Nanoc2::PageRep
18
+ # or Nanoc2::AssetRep) that should be compiled by this filter.
19
+ #
20
+ # +obj+:: A proxy for the page or asset's page (Nanoc2::Page or
21
+ # Nanoc2::Asset).
22
+ #
23
+ # +site+:: The site (Nanoc2::Site) this filter belongs to.
24
+ #
25
+ # +other_assigns+:: A hash containing other variables that should be made
26
+ # available during filtering.
27
+ def initialize(obj_rep, other_assigns={})
28
+ # Determine kind
29
+ @kind = obj_rep.is_a?(Nanoc2::PageRep) ? :page : :asset
30
+
31
+ # Set object
32
+ @obj_rep = obj_rep
33
+ @obj = (@kind == :page ? @obj_rep.page : @obj_rep.asset)
34
+
35
+ # Set page/asset and page/asset reps
36
+ if @kind == :page
37
+ @page = @obj
38
+ @page_rep = @obj_rep
39
+ else
40
+ @asset = @obj
41
+ @asset_rep = @obj_rep
42
+ end
43
+
44
+ # Set site
45
+ @site = @obj.site
46
+
47
+ # Set other assigns
48
+ @other_assigns = other_assigns
49
+ end
50
+
51
+ # Runs the filter. This method returns the filtered content.
52
+ #
53
+ # +content+:: The unprocessed content that should be filtered.
54
+ #
55
+ # Subclasses must implement this method.
56
+ def run(content)
57
+ raise NotImplementedError.new("Nanoc2::Filter subclasses must implement #run")
58
+ end
59
+
60
+ # Returns a hash with data that should be available.
61
+ def assigns
62
+ @assigns ||= @other_assigns.merge({
63
+ :_obj_rep => @obj_rep,
64
+ :_obj => @obj,
65
+ :page_rep => @kind == :page ? @page_rep.to_proxy : nil,
66
+ :page => @kind == :page ? @page.to_proxy : nil,
67
+ :asset_rep => @kind == :asset ? @asset_rep.to_proxy : nil,
68
+ :asset => @kind == :asset ? @asset.to_proxy : nil,
69
+ :pages => @site.pages.map { |obj| obj.to_proxy },
70
+ :assets => @site.assets.map { |obj| obj.to_proxy },
71
+ :layouts => @site.layouts.map { |obj| obj.to_proxy },
72
+ :config => @site.config,
73
+ :site => @site
74
+ })
75
+ end
76
+
77
+ # Returns the filename associated with the item that is being filtered.
78
+ # The returned filename is in the format "page <path> (rep <name>)".
79
+ def filename
80
+ if assigns[:layout]
81
+ "layout #{assigns[:layout].path}"
82
+ elsif assigns[:page]
83
+ "page #{assigns[:_obj].path} (rep #{assigns[:_obj_rep].name})"
84
+ elsif assigns[:asset]
85
+ "asset #{assigns[:_obj].path} (rep #{assigns[:_obj_rep].name})"
86
+ else
87
+ '?'
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,91 @@
1
+ module Nanoc2
2
+
3
+ # A Nanoc2::Layout represents a layout in a nanoc site. It has content,
4
+ # attributes (for determining which filter to use for laying out a page), a
5
+ # path (because layouts are organised hierarchically), and a modification
6
+ # time (to speed up compilation).
7
+ class Layout
8
+
9
+ # Default values for layouts.
10
+ DEFAULTS = {
11
+ :filter => 'erb'
12
+ }
13
+
14
+ # The Nanoc2::Site this layout belongs to.
15
+ attr_accessor :site
16
+
17
+ # The raw content of this layout.
18
+ attr_reader :content
19
+
20
+ # A hash containing this layout's attributes.
21
+ attr_reader :attributes
22
+
23
+ # This layout's path, starting and ending with a slash.
24
+ attr_reader :path
25
+
26
+ # The time when this layout was last modified.
27
+ attr_reader :mtime
28
+
29
+ # Creates a new layout.
30
+ #
31
+ # +content+:: The raw content of this layout.
32
+ #
33
+ # +attributes+:: A hash containing this layout's attributes.
34
+ #
35
+ # +path+:: This layout's path, starting and ending with a slash.
36
+ #
37
+ # +mtime+:: The time when this layout was last modified.
38
+ def initialize(content, attributes, path, mtime=nil)
39
+ @content = content
40
+ @attributes = attributes.clean
41
+ @path = path.cleaned_path
42
+ @mtime = mtime
43
+ end
44
+
45
+ # Returns a proxy (Nanoc2::LayoutProxy) for this layout.
46
+ def to_proxy
47
+ @proxy ||= LayoutProxy.new(self)
48
+ end
49
+
50
+ # Returns the attribute with the given name.
51
+ def attribute_named(name)
52
+ return @attributes[name] if @attributes.has_key?(name)
53
+ return DEFAULTS[name]
54
+ end
55
+
56
+ # Returns the filter class needed for this layout.
57
+ def filter_class
58
+ Nanoc2::Filter.named(attribute_named(:filter))
59
+ end
60
+
61
+ # Saves the layout in the database, creating it if it doesn't exist yet or
62
+ # updating it if it already exists. Tells the site's data source to save
63
+ # the layout.
64
+ def save
65
+ @site.data_source.loading do
66
+ @site.data_source.save_layout(self)
67
+ end
68
+ end
69
+
70
+ # Moves the layout to a new path. Tells the site's data source to move the
71
+ # layout.
72
+ def move_to(new_path)
73
+ @site.data_source.loading do
74
+ @site.data_source.move_layout(self, new_path)
75
+ end
76
+ end
77
+
78
+ # Deletes the layout. Tells the site's data source to delete the layout.
79
+ def delete
80
+ @site.data_source.loading do
81
+ @site.data_source.delete_layout(self)
82
+ end
83
+ end
84
+
85
+ def inspect
86
+ "<#{self.class} path=#{self.path}>"
87
+ end
88
+
89
+ end
90
+
91
+ end