nanoc3 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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