nanoc3 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +3 -0
- data/LICENSE +19 -0
- data/NEWS.rdoc +262 -0
- data/README.rdoc +80 -0
- data/Rakefile +11 -0
- data/bin/nanoc3 +16 -0
- data/lib/nanoc3/base/code_snippet.rb +42 -0
- data/lib/nanoc3/base/compiler.rb +225 -0
- data/lib/nanoc3/base/compiler_dsl.rb +110 -0
- data/lib/nanoc3/base/core_ext/array.rb +21 -0
- data/lib/nanoc3/base/core_ext/hash.rb +23 -0
- data/lib/nanoc3/base/core_ext/string.rb +14 -0
- data/lib/nanoc3/base/core_ext.rb +5 -0
- data/lib/nanoc3/base/data_source.rb +197 -0
- data/lib/nanoc3/base/dependency_tracker.rb +291 -0
- data/lib/nanoc3/base/errors.rb +95 -0
- data/lib/nanoc3/base/filter.rb +60 -0
- data/lib/nanoc3/base/item.rb +87 -0
- data/lib/nanoc3/base/item_rep.rb +236 -0
- data/lib/nanoc3/base/layout.rb +53 -0
- data/lib/nanoc3/base/notification_center.rb +68 -0
- data/lib/nanoc3/base/plugin.rb +88 -0
- data/lib/nanoc3/base/preprocessor_context.rb +37 -0
- data/lib/nanoc3/base/rule.rb +37 -0
- data/lib/nanoc3/base/rule_context.rb +68 -0
- data/lib/nanoc3/base/site.rb +334 -0
- data/lib/nanoc3/base.rb +25 -0
- data/lib/nanoc3/cli/base.rb +151 -0
- data/lib/nanoc3/cli/commands/autocompile.rb +89 -0
- data/lib/nanoc3/cli/commands/compile.rb +279 -0
- data/lib/nanoc3/cli/commands/create_item.rb +79 -0
- data/lib/nanoc3/cli/commands/create_layout.rb +94 -0
- data/lib/nanoc3/cli/commands/create_site.rb +320 -0
- data/lib/nanoc3/cli/commands/help.rb +71 -0
- data/lib/nanoc3/cli/commands/info.rb +114 -0
- data/lib/nanoc3/cli/commands/update.rb +96 -0
- data/lib/nanoc3/cli/commands.rb +13 -0
- data/lib/nanoc3/cli/logger.rb +73 -0
- data/lib/nanoc3/cli.rb +16 -0
- data/lib/nanoc3/data_sources/delicious.rb +66 -0
- data/lib/nanoc3/data_sources/filesystem.rb +231 -0
- data/lib/nanoc3/data_sources/filesystem_combined.rb +202 -0
- data/lib/nanoc3/data_sources/filesystem_common.rb +22 -0
- data/lib/nanoc3/data_sources/filesystem_compact.rb +232 -0
- data/lib/nanoc3/data_sources/last_fm.rb +103 -0
- data/lib/nanoc3/data_sources/twitter.rb +53 -0
- data/lib/nanoc3/data_sources.rb +20 -0
- data/lib/nanoc3/extra/auto_compiler.rb +97 -0
- data/lib/nanoc3/extra/chick.rb +119 -0
- data/lib/nanoc3/extra/context.rb +24 -0
- data/lib/nanoc3/extra/core_ext/time.rb +19 -0
- data/lib/nanoc3/extra/core_ext.rb +3 -0
- data/lib/nanoc3/extra/deployers/rsync.rb +64 -0
- data/lib/nanoc3/extra/deployers.rb +12 -0
- data/lib/nanoc3/extra/file_proxy.rb +31 -0
- data/lib/nanoc3/extra/validators/links.rb +0 -0
- data/lib/nanoc3/extra/validators/w3c.rb +71 -0
- data/lib/nanoc3/extra/validators.rb +12 -0
- data/lib/nanoc3/extra/vcs.rb +65 -0
- data/lib/nanoc3/extra/vcses/bazaar.rb +21 -0
- data/lib/nanoc3/extra/vcses/dummy.rb +20 -0
- data/lib/nanoc3/extra/vcses/git.rb +21 -0
- data/lib/nanoc3/extra/vcses/mercurial.rb +21 -0
- data/lib/nanoc3/extra/vcses/subversion.rb +21 -0
- data/lib/nanoc3/extra/vcses.rb +17 -0
- data/lib/nanoc3/extra.rb +16 -0
- data/lib/nanoc3/filters/bluecloth.rb +13 -0
- data/lib/nanoc3/filters/coderay.rb +17 -0
- data/lib/nanoc3/filters/erb.rb +19 -0
- data/lib/nanoc3/filters/erubis.rb +17 -0
- data/lib/nanoc3/filters/haml.rb +20 -0
- data/lib/nanoc3/filters/less.rb +13 -0
- data/lib/nanoc3/filters/markaby.rb +14 -0
- data/lib/nanoc3/filters/maruku.rb +14 -0
- data/lib/nanoc3/filters/rainpress.rb +13 -0
- data/lib/nanoc3/filters/rdiscount.rb +13 -0
- data/lib/nanoc3/filters/rdoc.rb +23 -0
- data/lib/nanoc3/filters/redcloth.rb +14 -0
- data/lib/nanoc3/filters/relativize_paths.rb +32 -0
- data/lib/nanoc3/filters/rubypants.rb +14 -0
- data/lib/nanoc3/filters/sass.rb +17 -0
- data/lib/nanoc3/filters.rb +37 -0
- data/lib/nanoc3/helpers/blogging.rb +226 -0
- data/lib/nanoc3/helpers/breadcrumbs.rb +25 -0
- data/lib/nanoc3/helpers/capturing.rb +71 -0
- data/lib/nanoc3/helpers/filtering.rb +46 -0
- data/lib/nanoc3/helpers/html_escape.rb +22 -0
- data/lib/nanoc3/helpers/link_to.rb +120 -0
- data/lib/nanoc3/helpers/rendering.rb +76 -0
- data/lib/nanoc3/helpers/tagging.rb +58 -0
- data/lib/nanoc3/helpers/text.rb +40 -0
- data/lib/nanoc3/helpers/xml_sitemap.rb +69 -0
- data/lib/nanoc3/helpers.rb +16 -0
- data/lib/nanoc3/package.rb +106 -0
- data/lib/nanoc3/tasks/clean.rake +16 -0
- data/lib/nanoc3/tasks/clean.rb +33 -0
- data/lib/nanoc3/tasks/deploy/rsync.rake +11 -0
- data/lib/nanoc3/tasks/validate.rake +35 -0
- data/lib/nanoc3/tasks.rb +9 -0
- data/lib/nanoc3.rb +19 -0
- data/vendor/cri/ChangeLog +0 -0
- data/vendor/cri/LICENSE +19 -0
- data/vendor/cri/NEWS +0 -0
- data/vendor/cri/README +4 -0
- data/vendor/cri/Rakefile +25 -0
- data/vendor/cri/lib/cri/base.rb +153 -0
- data/vendor/cri/lib/cri/command.rb +105 -0
- data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
- data/vendor/cri/lib/cri/core_ext.rb +8 -0
- data/vendor/cri/lib/cri/option_parser.rb +186 -0
- data/vendor/cri/lib/cri.rb +12 -0
- data/vendor/cri/test/test_base.rb +6 -0
- data/vendor/cri/test/test_command.rb +6 -0
- data/vendor/cri/test/test_core_ext.rb +21 -0
- data/vendor/cri/test/test_option_parser.rb +279 -0
- metadata +225 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Filters
|
|
4
|
+
|
|
5
|
+
autoload 'BlueCloth', 'nanoc3/filters/bluecloth'
|
|
6
|
+
autoload 'CodeRay', 'nanoc3/filters/coderay'
|
|
7
|
+
autoload 'ERB', 'nanoc3/filters/erb'
|
|
8
|
+
autoload 'Erubis', 'nanoc3/filters/erubis'
|
|
9
|
+
autoload 'Haml', 'nanoc3/filters/haml'
|
|
10
|
+
autoload 'Less', 'nanoc3/filters/less'
|
|
11
|
+
autoload 'Markaby', 'nanoc3/filters/markaby'
|
|
12
|
+
autoload 'Maruku', 'nanoc3/filters/maruku'
|
|
13
|
+
autoload 'Rainpress', 'nanoc3/filters/rainpress'
|
|
14
|
+
autoload 'RDiscount', 'nanoc3/filters/rdiscount'
|
|
15
|
+
autoload 'RDoc', 'nanoc3/filters/rdoc'
|
|
16
|
+
autoload 'RedCloth', 'nanoc3/filters/redcloth'
|
|
17
|
+
autoload 'RelativizePaths', 'nanoc3/filters/relativize_paths'
|
|
18
|
+
autoload 'RubyPants', 'nanoc3/filters/rubypants'
|
|
19
|
+
autoload 'Sass', 'nanoc3/filters/sass'
|
|
20
|
+
|
|
21
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::BlueCloth', :bluecloth
|
|
22
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::CodeRay', :coderay
|
|
23
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::ERB', :erb
|
|
24
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Erubis', :erubis
|
|
25
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Haml', :haml
|
|
26
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Less', :less
|
|
27
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Markaby', :markaby
|
|
28
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Maruku', :maruku
|
|
29
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Rainpress', :rainpress
|
|
30
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::RDiscount', :rdiscount
|
|
31
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::RDoc', :rdoc
|
|
32
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::RedCloth', :redcloth
|
|
33
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::RelativizePaths', :relativize_paths
|
|
34
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::RubyPants', :rubypants
|
|
35
|
+
Nanoc3::Filter.register '::Nanoc3::Filters::Sass', :sass
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Blogging provides some functionality for building blogs,
|
|
6
|
+
# such as finding articles and constructing feeds.
|
|
7
|
+
#
|
|
8
|
+
# This helper has a few requirements. First, all blog articles should have
|
|
9
|
+
# the following attributes:
|
|
10
|
+
#
|
|
11
|
+
# * 'kind', set to 'article'.
|
|
12
|
+
#
|
|
13
|
+
# * 'created_at', set to the creation timestamp.
|
|
14
|
+
#
|
|
15
|
+
# Some functions in this blogging helper, such as the +atom_feed+ function,
|
|
16
|
+
# require additional attributes to be set; these attributes are described in
|
|
17
|
+
# the documentation for these functions.
|
|
18
|
+
#
|
|
19
|
+
# The two main functions are sorted_articles and atom_feed.
|
|
20
|
+
#
|
|
21
|
+
# To activate this helper, +include+ it, like this:
|
|
22
|
+
#
|
|
23
|
+
# include Nanoc3::Helpers::Blogging
|
|
24
|
+
module Blogging
|
|
25
|
+
|
|
26
|
+
# Returns an unsorted list of articles.
|
|
27
|
+
def articles
|
|
28
|
+
@items.select { |item| item[:kind] == 'article' }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns a list of articles, sorted by descending creation date (so newer
|
|
32
|
+
# articles appear first).
|
|
33
|
+
def sorted_articles
|
|
34
|
+
require 'time'
|
|
35
|
+
articles.sort_by { |a| Time.parse(a[:created_at]) }.reverse
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns a string representing the atom feed containing recent articles,
|
|
39
|
+
# sorted by descending creation date. +params+ is a hash where the
|
|
40
|
+
# following keys can be set:
|
|
41
|
+
#
|
|
42
|
+
# +limit+:: The maximum number of articles to show. Defaults to 5.
|
|
43
|
+
#
|
|
44
|
+
# +articles+:: A list of articles to include in the feed. Defaults to the
|
|
45
|
+
# list of articles returned by the articles function.
|
|
46
|
+
#
|
|
47
|
+
# +content_proc+:: A proc that returns the content of the given article,
|
|
48
|
+
# passed as a parameter. By default, given the argument
|
|
49
|
+
# +article+, this proc will return
|
|
50
|
+
# +article.reps[0].content+. This function may not return
|
|
51
|
+
# nil.
|
|
52
|
+
#
|
|
53
|
+
# +excerpt_proc+:: A proc that returns the excerpt of the given article,
|
|
54
|
+
# passed as a parameter. By default, given the argument
|
|
55
|
+
# +article+, this proc will return +article.excerpt+.
|
|
56
|
+
# This function may return nil.
|
|
57
|
+
#
|
|
58
|
+
# The following attributes must be set on blog articles:
|
|
59
|
+
#
|
|
60
|
+
# * 'title', containing the title of the blog post.
|
|
61
|
+
#
|
|
62
|
+
# * all other attributes mentioned above.
|
|
63
|
+
#
|
|
64
|
+
# The following attributes can optionally be set on blog articles to
|
|
65
|
+
# change the behaviour of the Atom feed:
|
|
66
|
+
#
|
|
67
|
+
# * 'excerpt', containing an excerpt of the article, usually only a few
|
|
68
|
+
# lines long.
|
|
69
|
+
#
|
|
70
|
+
# * 'custom_path_in_feed', containing the path that will be used instead
|
|
71
|
+
# of the normal path in the feed. This can be useful when including
|
|
72
|
+
# non-outputted items in a feed; such items could have their custom feed
|
|
73
|
+
# path set to the blog path instead, for example.
|
|
74
|
+
#
|
|
75
|
+
# The feed will also include dates on which the articles were updated.
|
|
76
|
+
# These are generated automatically; the way this happens depends on the
|
|
77
|
+
# used data source (the filesystem data source checks the file mtimes, for
|
|
78
|
+
# instance).
|
|
79
|
+
#
|
|
80
|
+
# The site configuration will need to have the following attributes:
|
|
81
|
+
#
|
|
82
|
+
# * 'base_url', containing the URL to the site, without trailing slash.
|
|
83
|
+
# For example, if the site is at "http://example.com/", the base_url
|
|
84
|
+
# would be "http://example.com".
|
|
85
|
+
#
|
|
86
|
+
# The feed item will need to have the following attributes:
|
|
87
|
+
#
|
|
88
|
+
# * 'title', containing the title of the feed, which is usually also the
|
|
89
|
+
# title of the blog.
|
|
90
|
+
#
|
|
91
|
+
# * 'author_name', containing the name of the item's author. This will
|
|
92
|
+
# likely be a global attribute, unless the site is managed by several
|
|
93
|
+
# people/
|
|
94
|
+
#
|
|
95
|
+
# * 'author_uri', containing the URI for the item's author, such as the
|
|
96
|
+
# author's web site URL. This will also likely be a global attribute.
|
|
97
|
+
#
|
|
98
|
+
# The feed item can have the following optional attributes:
|
|
99
|
+
#
|
|
100
|
+
# * 'feed_url', containing the custom URL of the feed. This can be useful
|
|
101
|
+
# when the private feed URL shouldn't be exposed; for example, when
|
|
102
|
+
# using FeedBurner this would be set to the public FeedBurner URL.
|
|
103
|
+
#
|
|
104
|
+
# To construct a feed, create a blank item with no layout, only the 'erb'
|
|
105
|
+
# (or 'erubis') filter, and an 'xml' extension. It may also be useful to
|
|
106
|
+
# set 'is_hidden' to true, so that helpers such as the sitemap helper will
|
|
107
|
+
# ignore the item. The content of the feed item should be:
|
|
108
|
+
#
|
|
109
|
+
# <%= atom_feed %>
|
|
110
|
+
def atom_feed(params={})
|
|
111
|
+
require 'builder'
|
|
112
|
+
require 'time'
|
|
113
|
+
|
|
114
|
+
# Extract parameters
|
|
115
|
+
limit = params[:limit] || 5
|
|
116
|
+
relevant_articles = params[:articles] || articles || []
|
|
117
|
+
content_proc = params[:content_proc] || lambda { |a| a.reps[0].content_at_snapshot(:pre) }
|
|
118
|
+
excerpt_proc = params[:excerpt_proc] || lambda { |a| a[:excerpt] }
|
|
119
|
+
|
|
120
|
+
# Check config attributes
|
|
121
|
+
if @site.config[:base_url].nil?
|
|
122
|
+
raise RuntimeError.new('Cannot build Atom feed: site configuration has no base_url')
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Check feed item attributes
|
|
126
|
+
if @item[:title].nil?
|
|
127
|
+
raise RuntimeError.new('Cannot build Atom feed: feed item has no title')
|
|
128
|
+
end
|
|
129
|
+
if @item[:author_name].nil?
|
|
130
|
+
raise RuntimeError.new('Cannot build Atom feed: feed item has no author_name')
|
|
131
|
+
end
|
|
132
|
+
if @item[:author_uri].nil?
|
|
133
|
+
raise RuntimeError.new('Cannot build Atom feed: feed item has no author_uri')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Check article attributes
|
|
137
|
+
if relevant_articles.empty?
|
|
138
|
+
raise RuntimeError.new('Cannot build Atom feed: no articles')
|
|
139
|
+
end
|
|
140
|
+
if relevant_articles.any? { |a| a[:created_at].nil? }
|
|
141
|
+
raise RuntimeError.new('Cannot build Atom feed: one or more articles lack created_at')
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Get sorted relevant articles
|
|
145
|
+
sorted_relevant_articles = relevant_articles.sort_by { |a| Time.parse(a[:created_at]) }.reverse.first(limit)
|
|
146
|
+
|
|
147
|
+
# Get most recent article
|
|
148
|
+
last_article = sorted_relevant_articles.first
|
|
149
|
+
|
|
150
|
+
# Create builder
|
|
151
|
+
buffer = ''
|
|
152
|
+
xml = Builder::XmlMarkup.new(:target => buffer, :indent => 2)
|
|
153
|
+
|
|
154
|
+
# Build feed
|
|
155
|
+
xml.instruct!
|
|
156
|
+
xml.feed(:xmlns => 'http://www.w3.org/2005/Atom') do
|
|
157
|
+
# Add primary attributes
|
|
158
|
+
xml.id @site.config[:base_url] + '/'
|
|
159
|
+
xml.title @item[:title]
|
|
160
|
+
|
|
161
|
+
# Add date
|
|
162
|
+
xml.updated Time.parse(last_article[:created_at]).to_iso8601_time
|
|
163
|
+
|
|
164
|
+
# Add links
|
|
165
|
+
xml.link(:rel => 'alternate', :href => @site.config[:base_url])
|
|
166
|
+
xml.link(:rel => 'self', :href => feed_url)
|
|
167
|
+
|
|
168
|
+
# Add author information
|
|
169
|
+
xml.author do
|
|
170
|
+
xml.name @item[:author_name]
|
|
171
|
+
xml.uri @item[:author_uri]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Add articles
|
|
175
|
+
sorted_relevant_articles.each do |a|
|
|
176
|
+
xml.entry do
|
|
177
|
+
# Add primary attributes
|
|
178
|
+
xml.id atom_tag_for(a)
|
|
179
|
+
xml.title a[:title], :type => 'html'
|
|
180
|
+
|
|
181
|
+
# Add dates
|
|
182
|
+
xml.published Time.parse(a[:created_at]).to_iso8601_time
|
|
183
|
+
xml.updated a.mtime.to_iso8601_time
|
|
184
|
+
|
|
185
|
+
# Add link
|
|
186
|
+
xml.link(:rel => 'alternate', :href => url_for(a))
|
|
187
|
+
|
|
188
|
+
# Add content
|
|
189
|
+
summary = excerpt_proc.call(a)
|
|
190
|
+
xml.content content_proc.call(a), :type => 'html'
|
|
191
|
+
xml.summary summary, :type => 'html' unless summary.nil?
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
buffer
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Returns the URL for the given item. It will return the URL containing
|
|
200
|
+
# the custom path in the feed if possible, otherwise the normal path.
|
|
201
|
+
def url_for(item)
|
|
202
|
+
@site.config[:base_url] + (item[:custom_path_in_feed] || item.reps[0].path)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Returns the URL of the feed. It will return the custom feed URL if set,
|
|
206
|
+
# or otherwise the normal feed URL.
|
|
207
|
+
def feed_url
|
|
208
|
+
@item[:feed_url] || @site.config[:base_url] + @item.reps[0].path
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Returns an URI containing an unique ID for the given item. This will be
|
|
212
|
+
# used in the Atom feed to uniquely identify articles. These IDs are
|
|
213
|
+
# created using a procedure suggested by Mark Pilgrim in this blog post:
|
|
214
|
+
# http://diveintomark.org/archives/2004/05/28/howto-atom-id.
|
|
215
|
+
def atom_tag_for(item)
|
|
216
|
+
require 'time'
|
|
217
|
+
|
|
218
|
+
hostname = @site.config[:base_url].sub(/.*:\/\/(.+?)\/?$/, '\1')
|
|
219
|
+
formatted_date = Time.parse(item[:created_at]).to_iso8601_date
|
|
220
|
+
|
|
221
|
+
'tag:' + hostname + ',' + formatted_date + ':' + (item.reps[0].path || item.identifier)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Breadcrumbs provides support for breadcrumbs, which allow
|
|
6
|
+
# the user to go up in the page hierarchy.
|
|
7
|
+
module Breadcrumbs
|
|
8
|
+
|
|
9
|
+
# Returns the breadcrumbs trail as an array. Higher items (items that are
|
|
10
|
+
# closer to the root) come before lower items.
|
|
11
|
+
def breadcrumbs_trail
|
|
12
|
+
trail = []
|
|
13
|
+
item = @item
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
trail.unshift(item)
|
|
17
|
+
item = item.parent
|
|
18
|
+
end until item.nil?
|
|
19
|
+
|
|
20
|
+
trail
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Capturing provides a content_for method, which allows
|
|
6
|
+
# content to be "captured" on one item and reused elsewhere.
|
|
7
|
+
#
|
|
8
|
+
# = Example
|
|
9
|
+
#
|
|
10
|
+
# For example, suppose you want the sidebar of your site to contain a short
|
|
11
|
+
# summary of the item. You could put the summary in the meta file, but
|
|
12
|
+
# that’s not possible when the summary contains eRuby. You could also put
|
|
13
|
+
# the sidebar inside the actual item, but that’s not very pretty. Instead,
|
|
14
|
+
# you write the summary on the item itself, but capture it, and print it in
|
|
15
|
+
# the sidebar layout.
|
|
16
|
+
#
|
|
17
|
+
# Captured content becomes part of the item. For example, a sidebar layout
|
|
18
|
+
# could look like this:
|
|
19
|
+
#
|
|
20
|
+
# <div id="sidebar">
|
|
21
|
+
# <h3>Summary</h3>
|
|
22
|
+
# <%= @item[:content_for_summary] || '(no summary)' %>
|
|
23
|
+
# </div>
|
|
24
|
+
#
|
|
25
|
+
# To put something inside that content_for_summary variable, capture it
|
|
26
|
+
# using the content_for function. In the about item, for example:
|
|
27
|
+
#
|
|
28
|
+
# <% content_for :summary do %>
|
|
29
|
+
# <p>On this item, nanoc is introduced, blah blah.</p>
|
|
30
|
+
# <% end %>
|
|
31
|
+
#
|
|
32
|
+
# When the site is compiled, the sidebar of the about item will say “On
|
|
33
|
+
# this item, the purpose of nanoc is described, blah blah blah,” as
|
|
34
|
+
# expected.
|
|
35
|
+
#
|
|
36
|
+
# This helper likely only works with ERB (and perhaps Erubis).
|
|
37
|
+
#
|
|
38
|
+
# To activate this helper, +include+ it, like this:
|
|
39
|
+
#
|
|
40
|
+
# include Nanoc3::Helpers::Capturing
|
|
41
|
+
module Capturing
|
|
42
|
+
|
|
43
|
+
# Captures the content inside the block into a item attribute named
|
|
44
|
+
# "content_for_" followed by the given name. The content of the block
|
|
45
|
+
# itself will not be outputted.
|
|
46
|
+
def content_for(name, &block)
|
|
47
|
+
eval("@item[:content_for_#{name.to_s}] = capture(&block)")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Evaluates the given block and returns the result. The block is not outputted.
|
|
51
|
+
def capture(*args, &block)
|
|
52
|
+
# Get erbout so far
|
|
53
|
+
erbout = eval('_erbout', block.binding)
|
|
54
|
+
erbout_length = erbout.length
|
|
55
|
+
|
|
56
|
+
# Execute block
|
|
57
|
+
block.call(*args)
|
|
58
|
+
|
|
59
|
+
# Get new piece of erbout
|
|
60
|
+
erbout_addition = erbout[erbout_length..-1]
|
|
61
|
+
|
|
62
|
+
# Remove addition
|
|
63
|
+
erbout[erbout_length..-1] = ''
|
|
64
|
+
|
|
65
|
+
# Done
|
|
66
|
+
erbout_addition
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Filtering provides a filter method, which allows parts of
|
|
6
|
+
# an item to be filtered.
|
|
7
|
+
#
|
|
8
|
+
# For example, the following piece of code only runs the "rubypants" filter
|
|
9
|
+
# on the second paragraph:
|
|
10
|
+
#
|
|
11
|
+
# <p>Lorem ipsum dolor sit amet...</p>
|
|
12
|
+
# <% filter :rubypants do %>
|
|
13
|
+
# <p>Consectetur adipisicing elit...</p>
|
|
14
|
+
# <% end %>
|
|
15
|
+
#
|
|
16
|
+
# This helper likely only works with ERB (and perhaps Erubis).
|
|
17
|
+
#
|
|
18
|
+
# To activate this helper, +include+ it, like this:
|
|
19
|
+
#
|
|
20
|
+
# include Nanoc3::Helpers::Filtering
|
|
21
|
+
module Filtering
|
|
22
|
+
|
|
23
|
+
require 'nanoc3/helpers/capturing'
|
|
24
|
+
include Nanoc3::Helpers::Capturing
|
|
25
|
+
|
|
26
|
+
# Filters the content in the given block and outputs it.
|
|
27
|
+
def filter(filter_name, arguments={}, &block)
|
|
28
|
+
# Capture block
|
|
29
|
+
data = capture(&block)
|
|
30
|
+
|
|
31
|
+
# Find filter
|
|
32
|
+
klass = Nanoc3::Filter.named(filter_name)
|
|
33
|
+
raise Nanoc3::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
|
34
|
+
filter = klass.new(@item_rep.assigns)
|
|
35
|
+
|
|
36
|
+
# Filter captured data
|
|
37
|
+
filtered_data = filter.run(data, arguments)
|
|
38
|
+
|
|
39
|
+
# Append filtered data to buffer
|
|
40
|
+
buffer = eval('_erbout', block.binding)
|
|
41
|
+
buffer << filtered_data
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::HTMLEscape contains functionality for HTML-escaping
|
|
6
|
+
# strings.
|
|
7
|
+
module HTMLEscape
|
|
8
|
+
|
|
9
|
+
# Returns the HTML-escaped representation of the given string. Only &, <,
|
|
10
|
+
# > and " are escaped.
|
|
11
|
+
def html_escape(string)
|
|
12
|
+
string.gsub('&', '&').
|
|
13
|
+
gsub('<', '<').
|
|
14
|
+
gsub('>', '>').
|
|
15
|
+
gsub('"', '"')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias h html_escape
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::LinkTo contains functions for linking to items.
|
|
6
|
+
#
|
|
7
|
+
# To activate this helper, +include+ it, like this:
|
|
8
|
+
#
|
|
9
|
+
# include Nanoc3::Helpers::LinkTo
|
|
10
|
+
module LinkTo
|
|
11
|
+
|
|
12
|
+
require 'nanoc3/helpers/html_escape'
|
|
13
|
+
include Nanoc3::Helpers::HTMLEscape
|
|
14
|
+
|
|
15
|
+
# Creates a HTML link to the given path or item representation, and with
|
|
16
|
+
# the given text.
|
|
17
|
+
#
|
|
18
|
+
# +path_or_rep+:: the URL or path (a String) that should be linked to, or
|
|
19
|
+
# the item representation that should be linked to.
|
|
20
|
+
#
|
|
21
|
+
# +text+:: the visible link text.
|
|
22
|
+
#
|
|
23
|
+
# +attributes+:: a hash containing HTML attributes that will be added to
|
|
24
|
+
# the link.
|
|
25
|
+
#
|
|
26
|
+
# Examples:
|
|
27
|
+
#
|
|
28
|
+
# link_to('Blog', '/blog/')
|
|
29
|
+
# # => '<a href="/blog/">Blog</a>'
|
|
30
|
+
#
|
|
31
|
+
# item_rep = @items.find { |i| i.item_id == 'special' }.reps[0]
|
|
32
|
+
# link_to('Special Item', item_rep)
|
|
33
|
+
# # => '<a href="/special_item/">Special Item</a>'
|
|
34
|
+
#
|
|
35
|
+
# link_to('Blog', '/blog/', :title => 'My super cool blog')
|
|
36
|
+
# # => '<a href="/blog/" title="My super cool blog">Blog</a>
|
|
37
|
+
def link_to(text, path_or_rep, attributes={})
|
|
38
|
+
# Find path
|
|
39
|
+
path = path_or_rep.is_a?(String) ? path_or_rep : path_or_rep.path
|
|
40
|
+
|
|
41
|
+
# Join attributes
|
|
42
|
+
attributes = attributes.inject('') do |memo, (key, value)|
|
|
43
|
+
memo + key.to_s + '="' + h(value) + '" '
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Create link
|
|
47
|
+
"<a #{attributes}href=\"#{path}\">#{text}</a>"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Creates a HTML link using link_to, except when the linked item is the
|
|
51
|
+
# current one. In this case, a span element with class "active" and with
|
|
52
|
+
# the given text will be returned.
|
|
53
|
+
#
|
|
54
|
+
# Examples:
|
|
55
|
+
#
|
|
56
|
+
# link_to_unless_current('Blog', '/blog/')
|
|
57
|
+
# # => '<a href="/blog/">Blog</a>'
|
|
58
|
+
#
|
|
59
|
+
# link_to_unless_current('This Item', @item_rep)
|
|
60
|
+
# # => '<span class="active">This Item</span>'
|
|
61
|
+
def link_to_unless_current(text, path_or_rep, attributes={})
|
|
62
|
+
# Find path
|
|
63
|
+
path = path_or_rep.is_a?(String) ? path_or_rep : path_or_rep.path
|
|
64
|
+
|
|
65
|
+
if @item_rep and @item_rep.path == path
|
|
66
|
+
# Create message
|
|
67
|
+
"<span class=\"active\" title=\"You're here.\">#{text}</span>"
|
|
68
|
+
else
|
|
69
|
+
link_to(text, path_or_rep, attributes)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns the relative path from the current item to the given path or
|
|
74
|
+
# item representation.
|
|
75
|
+
#
|
|
76
|
+
# +path_or_rep+:: the URL or path (a String) to where the relative should
|
|
77
|
+
# point, or the item representation to which the relative
|
|
78
|
+
# should point.
|
|
79
|
+
#
|
|
80
|
+
# Example:
|
|
81
|
+
#
|
|
82
|
+
# # if the current item's path is /foo/bar/
|
|
83
|
+
# relative_path('/foo/qux/')
|
|
84
|
+
# # => '../qux/'
|
|
85
|
+
def relative_path_to(target)
|
|
86
|
+
require 'pathname'
|
|
87
|
+
|
|
88
|
+
# Find path
|
|
89
|
+
if target.is_a?(String)
|
|
90
|
+
path = target
|
|
91
|
+
elsif target.respond_to?(:reps)
|
|
92
|
+
path = target.reps.find { |r| r.name == :default }.path
|
|
93
|
+
else
|
|
94
|
+
path = target.path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Get source and destination paths
|
|
98
|
+
dst_path = Pathname.new(path)
|
|
99
|
+
src_path = Pathname.new(@item_rep.path)
|
|
100
|
+
|
|
101
|
+
# Calculate elative path (method depends on whether destination is a
|
|
102
|
+
# directory or not).
|
|
103
|
+
if src_path.to_s[-1,1] != '/'
|
|
104
|
+
relative_path = dst_path.relative_path_from(src_path.dirname).to_s
|
|
105
|
+
else
|
|
106
|
+
relative_path = dst_path.relative_path_from(src_path).to_s
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Add trailing slash if necessary
|
|
110
|
+
if dst_path.to_s[-1,1] == '/'
|
|
111
|
+
relative_path += '/'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Done
|
|
115
|
+
relative_path
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Rendering provides functionality for rendering layouts as
|
|
6
|
+
# partials.
|
|
7
|
+
module Rendering
|
|
8
|
+
|
|
9
|
+
include Nanoc3::Helpers::Capturing
|
|
10
|
+
|
|
11
|
+
# Returns a string containing the rendered given layout.
|
|
12
|
+
#
|
|
13
|
+
# +identifier+:: the identifier of the layout that should be rendered.
|
|
14
|
+
#
|
|
15
|
+
# +other_assigns+:: a hash containing assigns that will be made available
|
|
16
|
+
# as instance variables.
|
|
17
|
+
#
|
|
18
|
+
# Example 1: a layout 'head' with content "HEAD" and a layout 'foot' with
|
|
19
|
+
# content "FOOT":
|
|
20
|
+
#
|
|
21
|
+
# <%= render 'head' %> - MIDDLE - <%= render 'foot' %>
|
|
22
|
+
# # => "HEAD - MIDDLE - FOOT"
|
|
23
|
+
#
|
|
24
|
+
# Example 2: a layout named 'head' with content "<h1><%= @title %></h1>":
|
|
25
|
+
#
|
|
26
|
+
# <%= render 'head', :title => 'Foo' %>
|
|
27
|
+
# # => "<h1>Foo</h1>"
|
|
28
|
+
def render(identifier, other_assigns={}, &block)
|
|
29
|
+
# Find layout
|
|
30
|
+
layout = @site.layouts.find { |l| l.identifier == identifier.cleaned_identifier }
|
|
31
|
+
raise Nanoc3::Errors::UnknownLayout.new(identifier.cleaned_identifier) if layout.nil?
|
|
32
|
+
|
|
33
|
+
# Capture content, if any
|
|
34
|
+
captured_content = block_given? ? capture(&block) : nil
|
|
35
|
+
|
|
36
|
+
# Get assigns
|
|
37
|
+
assigns = {
|
|
38
|
+
:content => captured_content,
|
|
39
|
+
:item => @item,
|
|
40
|
+
:item_rep => @item_rep,
|
|
41
|
+
:items => @items,
|
|
42
|
+
:layout => layout,
|
|
43
|
+
:layouts => @layouts,
|
|
44
|
+
:config => @config,
|
|
45
|
+
:site => @site
|
|
46
|
+
}.merge(other_assigns)
|
|
47
|
+
|
|
48
|
+
# Get filter name
|
|
49
|
+
filter_name, filter_args = @site.compiler.filter_for_layout(layout)
|
|
50
|
+
raise Nanoc3::Errors::CannotDetermineFilter.new(layout.identifier) if filter_name.nil?
|
|
51
|
+
|
|
52
|
+
# Get filter class
|
|
53
|
+
filter_class = Nanoc3::Filter.named(filter_name)
|
|
54
|
+
raise Nanoc3::Errors::UnknownFilter.new(filter_name) if filter_class.nil?
|
|
55
|
+
|
|
56
|
+
# Create filter
|
|
57
|
+
filter = filter_class.new(assigns)
|
|
58
|
+
|
|
59
|
+
# Layout
|
|
60
|
+
@site.compiler.stack.push(layout)
|
|
61
|
+
result = filter.run(layout.raw_content, filter_args)
|
|
62
|
+
@site.compiler.stack.pop
|
|
63
|
+
|
|
64
|
+
# Append to erbout if we have a block
|
|
65
|
+
if block_given?
|
|
66
|
+
erbout = eval('_erbout', block.binding)
|
|
67
|
+
erbout << result
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Done
|
|
71
|
+
result
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc3::Helpers
|
|
4
|
+
|
|
5
|
+
# Nanoc3::Helpers::Tagging provides some support for managing tags added to
|
|
6
|
+
# items. To add tags to items, set the +tags+ attribute to an array of
|
|
7
|
+
# tags that should be applied to the item. For example:
|
|
8
|
+
#
|
|
9
|
+
# tags: [ 'foo', 'bar', 'baz' ]
|
|
10
|
+
#
|
|
11
|
+
# To activate this helper, +include+ it, like this:
|
|
12
|
+
#
|
|
13
|
+
# include Nanoc3::Helpers::Tagging
|
|
14
|
+
module Tagging
|
|
15
|
+
|
|
16
|
+
# Returns a formatted list of tags for the given item as a string. Several
|
|
17
|
+
# parameters allow customization:
|
|
18
|
+
#
|
|
19
|
+
# :base_url:: The URL to which the tag will be appended to construct the
|
|
20
|
+
# link URL. This URL must have a trailing slash. Defaults to
|
|
21
|
+
# "http://technorati.com/tag/".
|
|
22
|
+
#
|
|
23
|
+
# :none_text:: The text to display when the item has no tags. Defaults to
|
|
24
|
+
# "(none)".
|
|
25
|
+
#
|
|
26
|
+
# :separator:: The separator to put between tags. Defaults to ", ".
|
|
27
|
+
def tags_for(item, params={})
|
|
28
|
+
base_url = params[:base_url] || 'http://technorati.com/tag/'
|
|
29
|
+
none_text = params[:none_text] || '(none)'
|
|
30
|
+
separator = params[:separator] || ', '
|
|
31
|
+
|
|
32
|
+
if item[:tags].nil? or item[:tags].empty?
|
|
33
|
+
none_text
|
|
34
|
+
else
|
|
35
|
+
item[:tags].map { |tag| link_for_tag(tag, base_url) }.join(separator)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns all items with the given tag.
|
|
40
|
+
def items_with_tag(tag)
|
|
41
|
+
@items.select { |i| (i[:tags] || []).include?(tag) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns a link to to the specified tag. The link is marked up using the
|
|
45
|
+
# rel-tag microformat.
|
|
46
|
+
#
|
|
47
|
+
# +tag+:: The name of the tag, which should consist of letters and numbers
|
|
48
|
+
# (no spaces, slashes, or other special characters).
|
|
49
|
+
#
|
|
50
|
+
# +base_url+:: The URL to which the tag will be appended to construct the
|
|
51
|
+
# link URL. This URL must have a trailing slash.
|
|
52
|
+
def link_for_tag(tag, base_url)
|
|
53
|
+
%[<a href="#{base_url}#{tag}" rel="tag">#{tag}</a>]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|