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.
Files changed (116) hide show
  1. data/ChangeLog +3 -0
  2. data/LICENSE +19 -0
  3. data/NEWS.rdoc +262 -0
  4. data/README.rdoc +80 -0
  5. data/Rakefile +11 -0
  6. data/bin/nanoc3 +16 -0
  7. data/lib/nanoc3/base/code_snippet.rb +42 -0
  8. data/lib/nanoc3/base/compiler.rb +225 -0
  9. data/lib/nanoc3/base/compiler_dsl.rb +110 -0
  10. data/lib/nanoc3/base/core_ext/array.rb +21 -0
  11. data/lib/nanoc3/base/core_ext/hash.rb +23 -0
  12. data/lib/nanoc3/base/core_ext/string.rb +14 -0
  13. data/lib/nanoc3/base/core_ext.rb +5 -0
  14. data/lib/nanoc3/base/data_source.rb +197 -0
  15. data/lib/nanoc3/base/dependency_tracker.rb +291 -0
  16. data/lib/nanoc3/base/errors.rb +95 -0
  17. data/lib/nanoc3/base/filter.rb +60 -0
  18. data/lib/nanoc3/base/item.rb +87 -0
  19. data/lib/nanoc3/base/item_rep.rb +236 -0
  20. data/lib/nanoc3/base/layout.rb +53 -0
  21. data/lib/nanoc3/base/notification_center.rb +68 -0
  22. data/lib/nanoc3/base/plugin.rb +88 -0
  23. data/lib/nanoc3/base/preprocessor_context.rb +37 -0
  24. data/lib/nanoc3/base/rule.rb +37 -0
  25. data/lib/nanoc3/base/rule_context.rb +68 -0
  26. data/lib/nanoc3/base/site.rb +334 -0
  27. data/lib/nanoc3/base.rb +25 -0
  28. data/lib/nanoc3/cli/base.rb +151 -0
  29. data/lib/nanoc3/cli/commands/autocompile.rb +89 -0
  30. data/lib/nanoc3/cli/commands/compile.rb +279 -0
  31. data/lib/nanoc3/cli/commands/create_item.rb +79 -0
  32. data/lib/nanoc3/cli/commands/create_layout.rb +94 -0
  33. data/lib/nanoc3/cli/commands/create_site.rb +320 -0
  34. data/lib/nanoc3/cli/commands/help.rb +71 -0
  35. data/lib/nanoc3/cli/commands/info.rb +114 -0
  36. data/lib/nanoc3/cli/commands/update.rb +96 -0
  37. data/lib/nanoc3/cli/commands.rb +13 -0
  38. data/lib/nanoc3/cli/logger.rb +73 -0
  39. data/lib/nanoc3/cli.rb +16 -0
  40. data/lib/nanoc3/data_sources/delicious.rb +66 -0
  41. data/lib/nanoc3/data_sources/filesystem.rb +231 -0
  42. data/lib/nanoc3/data_sources/filesystem_combined.rb +202 -0
  43. data/lib/nanoc3/data_sources/filesystem_common.rb +22 -0
  44. data/lib/nanoc3/data_sources/filesystem_compact.rb +232 -0
  45. data/lib/nanoc3/data_sources/last_fm.rb +103 -0
  46. data/lib/nanoc3/data_sources/twitter.rb +53 -0
  47. data/lib/nanoc3/data_sources.rb +20 -0
  48. data/lib/nanoc3/extra/auto_compiler.rb +97 -0
  49. data/lib/nanoc3/extra/chick.rb +119 -0
  50. data/lib/nanoc3/extra/context.rb +24 -0
  51. data/lib/nanoc3/extra/core_ext/time.rb +19 -0
  52. data/lib/nanoc3/extra/core_ext.rb +3 -0
  53. data/lib/nanoc3/extra/deployers/rsync.rb +64 -0
  54. data/lib/nanoc3/extra/deployers.rb +12 -0
  55. data/lib/nanoc3/extra/file_proxy.rb +31 -0
  56. data/lib/nanoc3/extra/validators/links.rb +0 -0
  57. data/lib/nanoc3/extra/validators/w3c.rb +71 -0
  58. data/lib/nanoc3/extra/validators.rb +12 -0
  59. data/lib/nanoc3/extra/vcs.rb +65 -0
  60. data/lib/nanoc3/extra/vcses/bazaar.rb +21 -0
  61. data/lib/nanoc3/extra/vcses/dummy.rb +20 -0
  62. data/lib/nanoc3/extra/vcses/git.rb +21 -0
  63. data/lib/nanoc3/extra/vcses/mercurial.rb +21 -0
  64. data/lib/nanoc3/extra/vcses/subversion.rb +21 -0
  65. data/lib/nanoc3/extra/vcses.rb +17 -0
  66. data/lib/nanoc3/extra.rb +16 -0
  67. data/lib/nanoc3/filters/bluecloth.rb +13 -0
  68. data/lib/nanoc3/filters/coderay.rb +17 -0
  69. data/lib/nanoc3/filters/erb.rb +19 -0
  70. data/lib/nanoc3/filters/erubis.rb +17 -0
  71. data/lib/nanoc3/filters/haml.rb +20 -0
  72. data/lib/nanoc3/filters/less.rb +13 -0
  73. data/lib/nanoc3/filters/markaby.rb +14 -0
  74. data/lib/nanoc3/filters/maruku.rb +14 -0
  75. data/lib/nanoc3/filters/rainpress.rb +13 -0
  76. data/lib/nanoc3/filters/rdiscount.rb +13 -0
  77. data/lib/nanoc3/filters/rdoc.rb +23 -0
  78. data/lib/nanoc3/filters/redcloth.rb +14 -0
  79. data/lib/nanoc3/filters/relativize_paths.rb +32 -0
  80. data/lib/nanoc3/filters/rubypants.rb +14 -0
  81. data/lib/nanoc3/filters/sass.rb +17 -0
  82. data/lib/nanoc3/filters.rb +37 -0
  83. data/lib/nanoc3/helpers/blogging.rb +226 -0
  84. data/lib/nanoc3/helpers/breadcrumbs.rb +25 -0
  85. data/lib/nanoc3/helpers/capturing.rb +71 -0
  86. data/lib/nanoc3/helpers/filtering.rb +46 -0
  87. data/lib/nanoc3/helpers/html_escape.rb +22 -0
  88. data/lib/nanoc3/helpers/link_to.rb +120 -0
  89. data/lib/nanoc3/helpers/rendering.rb +76 -0
  90. data/lib/nanoc3/helpers/tagging.rb +58 -0
  91. data/lib/nanoc3/helpers/text.rb +40 -0
  92. data/lib/nanoc3/helpers/xml_sitemap.rb +69 -0
  93. data/lib/nanoc3/helpers.rb +16 -0
  94. data/lib/nanoc3/package.rb +106 -0
  95. data/lib/nanoc3/tasks/clean.rake +16 -0
  96. data/lib/nanoc3/tasks/clean.rb +33 -0
  97. data/lib/nanoc3/tasks/deploy/rsync.rake +11 -0
  98. data/lib/nanoc3/tasks/validate.rake +35 -0
  99. data/lib/nanoc3/tasks.rb +9 -0
  100. data/lib/nanoc3.rb +19 -0
  101. data/vendor/cri/ChangeLog +0 -0
  102. data/vendor/cri/LICENSE +19 -0
  103. data/vendor/cri/NEWS +0 -0
  104. data/vendor/cri/README +4 -0
  105. data/vendor/cri/Rakefile +25 -0
  106. data/vendor/cri/lib/cri/base.rb +153 -0
  107. data/vendor/cri/lib/cri/command.rb +105 -0
  108. data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
  109. data/vendor/cri/lib/cri/core_ext.rb +8 -0
  110. data/vendor/cri/lib/cri/option_parser.rb +186 -0
  111. data/vendor/cri/lib/cri.rb +12 -0
  112. data/vendor/cri/test/test_base.rb +6 -0
  113. data/vendor/cri/test/test_command.rb +6 -0
  114. data/vendor/cri/test/test_core_ext.rb +21 -0
  115. data/vendor/cri/test/test_option_parser.rb +279 -0
  116. 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('&', '&amp;').
13
+ gsub('<', '&lt;').
14
+ gsub('>', '&gt;').
15
+ gsub('"', '&quot;')
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