nanoc 3.2.4 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/ChangeLog +3 -0
- data/Gemfile +32 -0
- data/LICENSE +19 -0
- data/NEWS.md +470 -0
- data/README.md +114 -0
- data/Rakefile +14 -0
- data/bin/nanoc +7 -27
- data/bin/nanoc3 +3 -0
- data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
- data/lib/nanoc.rb +41 -0
- data/lib/nanoc/base.rb +49 -0
- data/lib/nanoc/base/compilation/checksum_store.rb +57 -0
- data/lib/nanoc/base/compilation/compiled_content_cache.rb +62 -0
- data/lib/nanoc/base/compilation/compiler.rb +458 -0
- data/lib/nanoc/base/compilation/compiler_dsl.rb +214 -0
- data/lib/nanoc/base/compilation/dependency_tracker.rb +200 -0
- data/lib/nanoc/base/compilation/filter.rb +165 -0
- data/lib/nanoc/base/compilation/item_rep_proxy.rb +103 -0
- data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +102 -0
- data/lib/nanoc/base/compilation/outdatedness_checker.rb +223 -0
- data/lib/nanoc/base/compilation/outdatedness_reasons.rb +46 -0
- data/lib/nanoc/base/compilation/rule.rb +73 -0
- data/lib/nanoc/base/compilation/rule_context.rb +84 -0
- data/lib/nanoc/base/compilation/rule_memory_calculator.rb +40 -0
- data/lib/nanoc/base/compilation/rule_memory_store.rb +53 -0
- data/lib/nanoc/base/compilation/rules_collection.rb +243 -0
- data/lib/nanoc/base/context.rb +47 -0
- data/lib/nanoc/base/core_ext.rb +6 -0
- data/lib/nanoc/base/core_ext/array.rb +62 -0
- data/lib/nanoc/base/core_ext/hash.rb +63 -0
- data/lib/nanoc/base/core_ext/pathname.rb +26 -0
- data/lib/nanoc/base/core_ext/string.rb +46 -0
- data/lib/nanoc/base/directed_graph.rb +275 -0
- data/lib/nanoc/base/errors.rb +211 -0
- data/lib/nanoc/base/memoization.rb +67 -0
- data/lib/nanoc/base/notification_center.rb +84 -0
- data/lib/nanoc/base/ordered_hash.rb +200 -0
- data/lib/nanoc/base/plugin_registry.rb +181 -0
- data/lib/nanoc/base/result_data/item_rep.rb +492 -0
- data/lib/nanoc/base/source_data/code_snippet.rb +58 -0
- data/lib/nanoc/base/source_data/configuration.rb +24 -0
- data/lib/nanoc/base/source_data/data_source.rb +234 -0
- data/lib/nanoc/base/source_data/item.rb +301 -0
- data/lib/nanoc/base/source_data/layout.rb +130 -0
- data/lib/nanoc/base/source_data/site.rb +361 -0
- data/lib/nanoc/base/store.rb +135 -0
- data/lib/nanoc/cli.rb +137 -0
- data/lib/nanoc/cli/command_runner.rb +104 -0
- data/lib/nanoc/cli/commands/autocompile.rb +58 -0
- data/lib/nanoc/cli/commands/compile.rb +297 -0
- data/lib/nanoc/cli/commands/create_item.rb +60 -0
- data/lib/nanoc/cli/commands/create_layout.rb +73 -0
- data/lib/nanoc/cli/commands/create_site.rb +411 -0
- data/lib/nanoc/cli/commands/debug.rb +117 -0
- data/lib/nanoc/cli/commands/deploy.rb +79 -0
- data/lib/nanoc/cli/commands/info.rb +98 -0
- data/lib/nanoc/cli/commands/nanoc.rb +38 -0
- data/lib/nanoc/cli/commands/prune.rb +50 -0
- data/lib/nanoc/cli/commands/update.rb +70 -0
- data/lib/nanoc/cli/commands/view.rb +82 -0
- data/lib/nanoc/cli/commands/watch.rb +124 -0
- data/lib/nanoc/cli/error_handler.rb +199 -0
- data/lib/nanoc/cli/logger.rb +92 -0
- data/lib/nanoc/data_sources.rb +29 -0
- data/lib/nanoc/data_sources/deprecated/delicious.rb +42 -0
- data/lib/nanoc/data_sources/deprecated/last_fm.rb +87 -0
- data/lib/nanoc/data_sources/deprecated/twitter.rb +38 -0
- data/lib/nanoc/data_sources/filesystem.rb +299 -0
- data/lib/nanoc/data_sources/filesystem_unified.rb +121 -0
- data/lib/nanoc/data_sources/filesystem_verbose.rb +91 -0
- data/lib/nanoc/extra.rb +24 -0
- data/lib/nanoc/extra/auto_compiler.rb +103 -0
- data/lib/nanoc/extra/chick.rb +125 -0
- data/lib/nanoc/extra/core_ext.rb +6 -0
- data/lib/nanoc/extra/core_ext/enumerable.rb +33 -0
- data/lib/nanoc/extra/core_ext/pathname.rb +30 -0
- data/lib/nanoc/extra/core_ext/time.rb +19 -0
- data/lib/nanoc/extra/deployer.rb +47 -0
- data/lib/nanoc/extra/deployers.rb +15 -0
- data/lib/nanoc/extra/deployers/fog.rb +98 -0
- data/lib/nanoc/extra/deployers/rsync.rb +70 -0
- data/lib/nanoc/extra/file_proxy.rb +40 -0
- data/lib/nanoc/extra/pruner.rb +86 -0
- data/lib/nanoc/extra/validators.rb +12 -0
- data/lib/nanoc/extra/validators/links.rb +268 -0
- data/lib/nanoc/extra/validators/w3c.rb +95 -0
- data/lib/nanoc/extra/vcs.rb +66 -0
- data/lib/nanoc/extra/vcses.rb +17 -0
- data/lib/nanoc/extra/vcses/bazaar.rb +25 -0
- data/lib/nanoc/extra/vcses/dummy.rb +24 -0
- data/lib/nanoc/extra/vcses/git.rb +25 -0
- data/lib/nanoc/extra/vcses/mercurial.rb +25 -0
- data/lib/nanoc/extra/vcses/subversion.rb +25 -0
- data/lib/nanoc/filters.rb +59 -0
- data/lib/nanoc/filters/asciidoc.rb +38 -0
- data/lib/nanoc/filters/bluecloth.rb +19 -0
- data/lib/nanoc/filters/coderay.rb +21 -0
- data/lib/nanoc/filters/coffeescript.rb +20 -0
- data/lib/nanoc/filters/colorize_syntax.rb +298 -0
- data/lib/nanoc/filters/erb.rb +38 -0
- data/lib/nanoc/filters/erubis.rb +34 -0
- data/lib/nanoc/filters/haml.rb +27 -0
- data/lib/nanoc/filters/kramdown.rb +20 -0
- data/lib/nanoc/filters/less.rb +53 -0
- data/lib/nanoc/filters/markaby.rb +20 -0
- data/lib/nanoc/filters/maruku.rb +20 -0
- data/lib/nanoc/filters/mustache.rb +24 -0
- data/lib/nanoc/filters/rainpress.rb +19 -0
- data/lib/nanoc/filters/rdiscount.rb +22 -0
- data/lib/nanoc/filters/rdoc.rb +33 -0
- data/lib/nanoc/filters/redcarpet.rb +62 -0
- data/lib/nanoc/filters/redcloth.rb +47 -0
- data/lib/nanoc/filters/relativize_paths.rb +94 -0
- data/lib/nanoc/filters/rubypants.rb +20 -0
- data/lib/nanoc/filters/sass.rb +74 -0
- data/lib/nanoc/filters/slim.rb +25 -0
- data/lib/nanoc/filters/typogruby.rb +23 -0
- data/lib/nanoc/filters/uglify_js.rb +42 -0
- data/lib/nanoc/filters/xsl.rb +46 -0
- data/lib/nanoc/filters/yui_compressor.rb +23 -0
- data/lib/nanoc/helpers.rb +16 -0
- data/lib/nanoc/helpers/blogging.rb +319 -0
- data/lib/nanoc/helpers/breadcrumbs.rb +40 -0
- data/lib/nanoc/helpers/capturing.rb +138 -0
- data/lib/nanoc/helpers/filtering.rb +50 -0
- data/lib/nanoc/helpers/html_escape.rb +55 -0
- data/lib/nanoc/helpers/link_to.rb +151 -0
- data/lib/nanoc/helpers/rendering.rb +140 -0
- data/lib/nanoc/helpers/tagging.rb +71 -0
- data/lib/nanoc/helpers/text.rb +44 -0
- data/lib/nanoc/helpers/xml_sitemap.rb +76 -0
- data/lib/nanoc/tasks.rb +10 -0
- data/lib/nanoc/tasks/clean.rake +16 -0
- data/lib/nanoc/tasks/clean.rb +29 -0
- data/lib/nanoc/tasks/deploy/rsync.rake +16 -0
- data/lib/nanoc/tasks/validate.rake +92 -0
- data/nanoc.gemspec +49 -0
- data/tasks/doc.rake +16 -0
- data/tasks/test.rake +46 -0
- data/test/base/core_ext/array_spec.rb +73 -0
- data/test/base/core_ext/hash_spec.rb +98 -0
- data/test/base/core_ext/pathname_spec.rb +27 -0
- data/test/base/core_ext/string_spec.rb +37 -0
- data/test/base/test_checksum_store.rb +35 -0
- data/test/base/test_code_snippet.rb +31 -0
- data/test/base/test_compiler.rb +403 -0
- data/test/base/test_compiler_dsl.rb +161 -0
- data/test/base/test_context.rb +31 -0
- data/test/base/test_data_source.rb +46 -0
- data/test/base/test_dependency_tracker.rb +262 -0
- data/test/base/test_directed_graph.rb +288 -0
- data/test/base/test_filter.rb +83 -0
- data/test/base/test_item.rb +179 -0
- data/test/base/test_item_rep.rb +579 -0
- data/test/base/test_layout.rb +59 -0
- data/test/base/test_memoization.rb +90 -0
- data/test/base/test_notification_center.rb +34 -0
- data/test/base/test_outdatedness_checker.rb +394 -0
- data/test/base/test_plugin.rb +30 -0
- data/test/base/test_rule.rb +19 -0
- data/test/base/test_rule_context.rb +65 -0
- data/test/base/test_site.rb +190 -0
- data/test/cli/commands/test_compile.rb +33 -0
- data/test/cli/commands/test_create_item.rb +14 -0
- data/test/cli/commands/test_create_layout.rb +28 -0
- data/test/cli/commands/test_create_site.rb +24 -0
- data/test/cli/commands/test_deploy.rb +74 -0
- data/test/cli/commands/test_help.rb +12 -0
- data/test/cli/commands/test_info.rb +11 -0
- data/test/cli/commands/test_prune.rb +98 -0
- data/test/cli/commands/test_update.rb +10 -0
- data/test/cli/test_cli.rb +102 -0
- data/test/cli/test_error_handler.rb +29 -0
- data/test/cli/test_logger.rb +10 -0
- data/test/data_sources/test_filesystem.rb +433 -0
- data/test/data_sources/test_filesystem_unified.rb +536 -0
- data/test/data_sources/test_filesystem_verbose.rb +357 -0
- data/test/extra/core_ext/test_enumerable.rb +30 -0
- data/test/extra/core_ext/test_pathname.rb +17 -0
- data/test/extra/core_ext/test_time.rb +15 -0
- data/test/extra/deployers/test_fog.rb +67 -0
- data/test/extra/deployers/test_rsync.rb +100 -0
- data/test/extra/test_auto_compiler.rb +417 -0
- data/test/extra/test_file_proxy.rb +19 -0
- data/test/extra/test_vcs.rb +22 -0
- data/test/extra/validators/test_links.rb +62 -0
- data/test/extra/validators/test_w3c.rb +47 -0
- data/test/filters/test_asciidoc.rb +22 -0
- data/test/filters/test_bluecloth.rb +18 -0
- data/test/filters/test_coderay.rb +44 -0
- data/test/filters/test_coffeescript.rb +18 -0
- data/test/filters/test_colorize_syntax.rb +379 -0
- data/test/filters/test_erb.rb +105 -0
- data/test/filters/test_erubis.rb +78 -0
- data/test/filters/test_haml.rb +96 -0
- data/test/filters/test_kramdown.rb +18 -0
- data/test/filters/test_less.rb +113 -0
- data/test/filters/test_markaby.rb +24 -0
- data/test/filters/test_maruku.rb +18 -0
- data/test/filters/test_mustache.rb +25 -0
- data/test/filters/test_rainpress.rb +29 -0
- data/test/filters/test_rdiscount.rb +31 -0
- data/test/filters/test_rdoc.rb +18 -0
- data/test/filters/test_redcarpet.rb +73 -0
- data/test/filters/test_redcloth.rb +33 -0
- data/test/filters/test_relativize_paths.rb +533 -0
- data/test/filters/test_rubypants.rb +18 -0
- data/test/filters/test_sass.rb +229 -0
- data/test/filters/test_slim.rb +35 -0
- data/test/filters/test_typogruby.rb +21 -0
- data/test/filters/test_uglify_js.rb +30 -0
- data/test/filters/test_xsl.rb +105 -0
- data/test/filters/test_yui_compressor.rb +44 -0
- data/test/gem_loader.rb +11 -0
- data/test/helper.rb +207 -0
- data/test/helpers/test_blogging.rb +754 -0
- data/test/helpers/test_breadcrumbs.rb +81 -0
- data/test/helpers/test_capturing.rb +41 -0
- data/test/helpers/test_filtering.rb +106 -0
- data/test/helpers/test_html_escape.rb +32 -0
- data/test/helpers/test_link_to.rb +249 -0
- data/test/helpers/test_rendering.rb +89 -0
- data/test/helpers/test_tagging.rb +87 -0
- data/test/helpers/test_text.rb +24 -0
- data/test/helpers/test_xml_sitemap.rb +103 -0
- data/test/tasks/test_clean.rb +67 -0
- metadata +327 -15
- data/bin/nanoc-select +0 -86
- data/lib/nanoc-select.rb +0 -11
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Provides support for breadcrumbs, which allow the user to go up in the
|
6
|
+
# page hierarchy.
|
7
|
+
module Breadcrumbs
|
8
|
+
|
9
|
+
# Creates a breadcrumb trail leading from the current item to its parent,
|
10
|
+
# to its parent’s parent, etc, until the root item is reached. This
|
11
|
+
# function does not require that each intermediate item exist; for
|
12
|
+
# example, if there is no `/foo/` item, breadcrumbs for a `/foo/bar/` item
|
13
|
+
# will contain a `nil` element.
|
14
|
+
#
|
15
|
+
# @return [Array] The breadcrumbs, starting with the root item and ending
|
16
|
+
# with the item itself
|
17
|
+
def breadcrumbs_trail
|
18
|
+
breadcrumbs_for_identifier(@item.identifier)
|
19
|
+
end
|
20
|
+
|
21
|
+
def item_with_identifier(identifier)
|
22
|
+
@identifier_cache ||= {}
|
23
|
+
@identifier_cache[identifier] ||= begin
|
24
|
+
@items.find { |i| i.identifier == identifier }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def breadcrumbs_for_identifier(identifier)
|
29
|
+
@breadcrumbs_cache ||= {}
|
30
|
+
@breadcrumbs_cache[identifier] ||= begin
|
31
|
+
head = (identifier == '/' ? [] : breadcrumbs_for_identifier(identifier.sub(/[^\/]+\/$/, '')) )
|
32
|
+
tail = [ item_with_identifier(identifier) ]
|
33
|
+
|
34
|
+
head + tail
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Provides functionality for “capturing” content in one place and reusing
|
6
|
+
# this content elsewhere.
|
7
|
+
#
|
8
|
+
# For example, suppose you want the sidebar of your site to contain a short
|
9
|
+
# summary of the item. You could put the summary in the meta file, but
|
10
|
+
# that’s not possible when the summary contains eRuby. You could also put
|
11
|
+
# the sidebar inside the actual item, but that’s not very pretty. Instead,
|
12
|
+
# you write the summary on the item itself, but capture it, and print it in
|
13
|
+
# the sidebar layout.
|
14
|
+
#
|
15
|
+
# This helper has been tested with ERB and Haml. Other filters may not work
|
16
|
+
# correctly.
|
17
|
+
#
|
18
|
+
# @example Capturing content for a summary
|
19
|
+
#
|
20
|
+
# <% content_for :summary do %>
|
21
|
+
# <p>On this item, nanoc is introduced, blah blah.</p>
|
22
|
+
# <% end %>
|
23
|
+
#
|
24
|
+
# @example Showing captured content in a sidebar
|
25
|
+
#
|
26
|
+
# <div id="sidebar">
|
27
|
+
# <h3>Summary</h3>
|
28
|
+
# <%= content_for(@item, :summary) || '(no summary)' %>
|
29
|
+
# </div>
|
30
|
+
#
|
31
|
+
# @example Showing captured content in a sidebar the old, deprecated way (do not use or I will become very angry)
|
32
|
+
#
|
33
|
+
# <div id="sidebar">
|
34
|
+
# <h3>Summary</h3>
|
35
|
+
# <%= @item[:content_for_summary] || '(no summary)' %>
|
36
|
+
# </div>
|
37
|
+
module Capturing
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
class CapturesStore
|
41
|
+
|
42
|
+
require 'singleton'
|
43
|
+
include Singleton
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
@store = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def []=(item, name, content)
|
50
|
+
@store[item.identifier] ||= {}
|
51
|
+
@store[item.identifier][name] = content
|
52
|
+
end
|
53
|
+
|
54
|
+
def [](item, name)
|
55
|
+
@store[item.identifier] ||= {}
|
56
|
+
@store[item.identifier][name]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# @overload content_for(name, &block)
|
62
|
+
#
|
63
|
+
# Captures the content inside the block and stores it so that it can be
|
64
|
+
# referenced later on. The same method, {#content_for}, is used for
|
65
|
+
# getting the captured content as well as setting it. When capturing,
|
66
|
+
# the content of the block itself will not be outputted.
|
67
|
+
#
|
68
|
+
# For backwards compatibility, it is also possible to fetch the captured
|
69
|
+
# content by getting the contents of the attribute named `content_for_`
|
70
|
+
# followed by the given name. This way of accessing captures is
|
71
|
+
# deprecated.
|
72
|
+
#
|
73
|
+
# @param [Symbol, String] name The base name of the attribute into which
|
74
|
+
# the content should be stored
|
75
|
+
#
|
76
|
+
# @return [void]
|
77
|
+
#
|
78
|
+
# @overload content_for(item, name)
|
79
|
+
#
|
80
|
+
# Fetches the capture with the given name from the given item and
|
81
|
+
# returns it.
|
82
|
+
#
|
83
|
+
# @param [Nanoc::Item] item The item for which to get the capture
|
84
|
+
#
|
85
|
+
# @param [Symbol, String] name The name of the capture to fetch
|
86
|
+
#
|
87
|
+
# @return [String] The stored captured content
|
88
|
+
def content_for(*args, &block)
|
89
|
+
if block_given? # Set content
|
90
|
+
# Get args
|
91
|
+
if args.size != 1
|
92
|
+
raise ArgumentError, "expected 1 argument (the name " +
|
93
|
+
"of the capture) but got #{args.size} instead"
|
94
|
+
end
|
95
|
+
name = args[0]
|
96
|
+
|
97
|
+
# Capture and store
|
98
|
+
content = capture(&block)
|
99
|
+
CapturesStore.instance[@item, name.to_sym] = content
|
100
|
+
else # Get content
|
101
|
+
# Get args
|
102
|
+
if args.size != 2
|
103
|
+
raise ArgumentError, "expected 2 arguments (the item " +
|
104
|
+
"and the name of the capture) but got #{args.size} instead"
|
105
|
+
end
|
106
|
+
item = args[0]
|
107
|
+
name = args[1]
|
108
|
+
|
109
|
+
# Get content
|
110
|
+
CapturesStore.instance[item, name.to_sym]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Evaluates the given block and returns its contents. The contents of the
|
115
|
+
# block is not outputted.
|
116
|
+
#
|
117
|
+
# @return [String] The captured result
|
118
|
+
def capture(&block)
|
119
|
+
# Get erbout so far
|
120
|
+
erbout = eval('_erbout', block.binding)
|
121
|
+
erbout_length = erbout.length
|
122
|
+
|
123
|
+
# Execute block
|
124
|
+
block.call
|
125
|
+
|
126
|
+
# Get new piece of erbout
|
127
|
+
erbout_addition = erbout[erbout_length..-1]
|
128
|
+
|
129
|
+
# Remove addition
|
130
|
+
erbout[erbout_length..-1] = ''
|
131
|
+
|
132
|
+
# Done
|
133
|
+
erbout_addition
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Provides functionality for filtering parts of an item or a layout.
|
6
|
+
module Filtering
|
7
|
+
|
8
|
+
require 'nanoc/helpers/capturing'
|
9
|
+
include Nanoc::Helpers::Capturing
|
10
|
+
|
11
|
+
# Filters the content in the given block and outputs it. This function
|
12
|
+
# does not return anything; instead, the filtered contents is directly
|
13
|
+
# appended to the output buffer (`_erbout`).
|
14
|
+
#
|
15
|
+
# This function has been tested with ERB and Haml. Other filters may not
|
16
|
+
# work correctly.
|
17
|
+
#
|
18
|
+
# @example Running a filter on a part of an item or layout
|
19
|
+
#
|
20
|
+
# <p>Lorem ipsum dolor sit amet...</p>
|
21
|
+
# <% filter :rubypants do %>
|
22
|
+
# <p>Consectetur adipisicing elit...</p>
|
23
|
+
# <% end %>
|
24
|
+
#
|
25
|
+
# @param [Symbol] filter_name The name of the filter to run on the
|
26
|
+
# contents of the block
|
27
|
+
#
|
28
|
+
# @param [Hash] argument Arguments to pass to the filter
|
29
|
+
#
|
30
|
+
# @return [void]
|
31
|
+
def filter(filter_name, arguments={}, &block)
|
32
|
+
# Capture block
|
33
|
+
data = capture(&block)
|
34
|
+
|
35
|
+
# Find filter
|
36
|
+
klass = Nanoc::Filter.named(filter_name)
|
37
|
+
raise Nanoc::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
38
|
+
filter = klass.new(@item_rep.assigns)
|
39
|
+
|
40
|
+
# Filter captured data
|
41
|
+
filtered_data = filter.run(data, arguments)
|
42
|
+
|
43
|
+
# Append filtered data to buffer
|
44
|
+
buffer = eval('_erbout', block.binding)
|
45
|
+
buffer << filtered_data
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Contains functionality for HTML-escaping strings.
|
6
|
+
module HTMLEscape
|
7
|
+
|
8
|
+
require 'nanoc/helpers/capturing'
|
9
|
+
include Nanoc::Helpers::Capturing
|
10
|
+
|
11
|
+
# Returns the HTML-escaped representation of the given string or the given
|
12
|
+
# block. Only `&`, `<`, `>` and `"` are escaped. When given a block, the
|
13
|
+
# contents of the block will be escaped and appended to the output buffer,
|
14
|
+
# `_erbout`.
|
15
|
+
#
|
16
|
+
# @example Escaping a string
|
17
|
+
#
|
18
|
+
# h('<br>')
|
19
|
+
# # => '<br>'
|
20
|
+
#
|
21
|
+
# @example Escaping with a block
|
22
|
+
#
|
23
|
+
# <% h do %>
|
24
|
+
# <h1>Hello <em>world</em>!</h1>
|
25
|
+
# <% end %>
|
26
|
+
# # The buffer will now contain “<h1>Hello <em>world</em>!</h1>”
|
27
|
+
#
|
28
|
+
# @param [String] string The string to escape
|
29
|
+
#
|
30
|
+
# @return [String] The escaped string
|
31
|
+
def html_escape(string=nil, &block)
|
32
|
+
if block_given?
|
33
|
+
# Capture and escape block
|
34
|
+
data = capture(&block)
|
35
|
+
escaped_data = html_escape(data)
|
36
|
+
|
37
|
+
# Append filtered data to buffer
|
38
|
+
buffer = eval('_erbout', block.binding)
|
39
|
+
buffer << escaped_data
|
40
|
+
elsif string
|
41
|
+
string.gsub('&', '&').
|
42
|
+
gsub('<', '<').
|
43
|
+
gsub('>', '>').
|
44
|
+
gsub('"', '"')
|
45
|
+
else
|
46
|
+
raise RuntimeError, "The #html_escape or #h function needs either a " \
|
47
|
+
"string or a block to HTML-escape, but neither a string nor a block was given"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
alias h html_escape
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Contains functions for linking to items and item representations.
|
6
|
+
module LinkTo
|
7
|
+
|
8
|
+
require 'nanoc/helpers/html_escape'
|
9
|
+
include Nanoc::Helpers::HTMLEscape
|
10
|
+
|
11
|
+
# Creates a HTML link to the given path or item representation, and with
|
12
|
+
# the given text. All attributes of the `a` element, including the `href`
|
13
|
+
# attribute, will be HTML-escaped; the contents of the `a` element, which
|
14
|
+
# can contain markup, will not be HTML-escaped. The HTML-escaping is done
|
15
|
+
# using {Nanoc::Helpers::HTMLEscape#html_escape}.
|
16
|
+
#
|
17
|
+
# @param [String] text The visible link text
|
18
|
+
#
|
19
|
+
# @param [String, Nanoc::Item, Nanoc::ItemRep] target The path/URL,
|
20
|
+
# item or item representation that should be linked to
|
21
|
+
#
|
22
|
+
# @param [Hash] attributes A hash containing HTML attributes (e.g.
|
23
|
+
# `rel`, `title`, …) that will be added to the link.
|
24
|
+
#
|
25
|
+
# @return [String] The link text
|
26
|
+
#
|
27
|
+
# @example Linking to a path
|
28
|
+
#
|
29
|
+
# link_to('Blog', '/blog/')
|
30
|
+
# # => '<a href="/blog/">Blog</a>'
|
31
|
+
#
|
32
|
+
# @example Linking to an item
|
33
|
+
#
|
34
|
+
# about = @items.find { |i| i.identifier == '/about/' }
|
35
|
+
# link_to('About Me', about)
|
36
|
+
# # => '<a href="/about.html">About Me</a>'
|
37
|
+
#
|
38
|
+
# @example Linking to an item representation
|
39
|
+
#
|
40
|
+
# about = @items.find { |i| i.identifier == '/about/' }
|
41
|
+
# link_to('My vCard', about.rep(:vcard))
|
42
|
+
# # => '<a href="/about.vcf">My vCard</a>'
|
43
|
+
#
|
44
|
+
# @example Linking with custom attributes
|
45
|
+
#
|
46
|
+
# link_to('Blog', '/blog/', :title => 'My super cool blog')
|
47
|
+
# # => '<a title="My super cool blog" href="/blog/">Blog</a>'
|
48
|
+
def link_to(text, target, attributes={})
|
49
|
+
# Find path
|
50
|
+
if target.is_a?(String)
|
51
|
+
path = target
|
52
|
+
else
|
53
|
+
path = target.path
|
54
|
+
raise RuntimeError, "Cannot create a link to #{target.inspect} because this target is not outputted (its routing rule returns nil)" if path.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Join attributes
|
58
|
+
attributes = attributes.inject('') do |memo, (key, value)|
|
59
|
+
memo + key.to_s + '="' + h(value) + '" '
|
60
|
+
end
|
61
|
+
|
62
|
+
# Create link
|
63
|
+
"<a #{attributes}href=\"#{h path}\">#{text}</a>"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Creates a HTML link using {#link_to}, except when the linked item is
|
67
|
+
# the current one. In this case, a span element with class “active” and
|
68
|
+
# with the given text will be returned. The HTML-escaping rules for
|
69
|
+
# {#link_to} apply here as well.
|
70
|
+
#
|
71
|
+
# @param [String] text The visible link text
|
72
|
+
#
|
73
|
+
# @param [String, Nanoc::Item, Nanoc::ItemRep] target The path/URL,
|
74
|
+
# item or item representation that should be linked to
|
75
|
+
#
|
76
|
+
# @param [Hash] attributes A hash containing HTML attributes (e.g.
|
77
|
+
# `rel`, `title`, …) that will be added to the link.
|
78
|
+
#
|
79
|
+
# @return [String] The link text
|
80
|
+
#
|
81
|
+
# @example Linking to a different page
|
82
|
+
#
|
83
|
+
# link_to_unless_current('Blog', '/blog/')
|
84
|
+
# # => '<a href="/blog/">Blog</a>'
|
85
|
+
#
|
86
|
+
# @example Linking to the same page
|
87
|
+
#
|
88
|
+
# link_to_unless_current('This Item', @item)
|
89
|
+
# # => '<span class="active" title="You\'re here.">This Item</span>'
|
90
|
+
def link_to_unless_current(text, target, attributes={})
|
91
|
+
# Find path
|
92
|
+
path = target.is_a?(String) ? target : target.path
|
93
|
+
|
94
|
+
if @item_rep && @item_rep.path == path
|
95
|
+
# Create message
|
96
|
+
"<span class=\"active\" title=\"You're here.\">#{text}</span>"
|
97
|
+
else
|
98
|
+
link_to(text, target, attributes)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns the relative path from the current item to the given path or
|
103
|
+
# item representation. The returned path will not be HTML-escaped.
|
104
|
+
#
|
105
|
+
# @param [String, Nanoc::Item, Nanoc::ItemRep] target The path/URL,
|
106
|
+
# item or item representation to which the relative path should be
|
107
|
+
# generated
|
108
|
+
#
|
109
|
+
# @return [String] The relative path to the target
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
#
|
113
|
+
# # if the current item's path is /foo/bar/
|
114
|
+
# relative_path_to('/foo/qux/')
|
115
|
+
# # => '../qux/'
|
116
|
+
def relative_path_to(target)
|
117
|
+
require 'pathname'
|
118
|
+
|
119
|
+
# Find path
|
120
|
+
if target.is_a?(String)
|
121
|
+
path = target
|
122
|
+
else
|
123
|
+
path = target.path
|
124
|
+
raise RuntimeError, "Cannot get the relative path to #{target.inspect} because this target is not outputted (its routing rule returns nil)" if path.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Get source and destination paths
|
128
|
+
dst_path = Pathname.new(path)
|
129
|
+
raise RuntimeError, "Cannot get the relative path to #{path} because the current item representation, #{@item_rep.inspect}, is not outputted (its routing rule returns nil)" if @item_rep.path.nil?
|
130
|
+
src_path = Pathname.new(@item_rep.path)
|
131
|
+
|
132
|
+
# Calculate the relative path (method depends on whether destination is
|
133
|
+
# a directory or not).
|
134
|
+
if src_path.to_s[-1,1] != '/'
|
135
|
+
relative_path = dst_path.relative_path_from(src_path.dirname).to_s
|
136
|
+
else
|
137
|
+
relative_path = dst_path.relative_path_from(src_path).to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
# Add trailing slash if necessary
|
141
|
+
if dst_path.to_s[-1,1] == '/'
|
142
|
+
relative_path << '/'
|
143
|
+
end
|
144
|
+
|
145
|
+
# Done
|
146
|
+
relative_path
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Helpers
|
4
|
+
|
5
|
+
# Provides functionality for rendering layouts as partials.
|
6
|
+
module Rendering
|
7
|
+
|
8
|
+
include Nanoc::Helpers::Capturing
|
9
|
+
|
10
|
+
# Renders the given layout. The given layout will be run through the first
|
11
|
+
# matching layout rule.
|
12
|
+
#
|
13
|
+
# When this method is invoked _without_ a block, the return value will be
|
14
|
+
# the rendered layout (a string) and `_erbout` will not be modified.
|
15
|
+
#
|
16
|
+
# When this method is invoked _with_ a block, an empty string will be
|
17
|
+
# returned and the rendered content will be appended to `_erbout`. In this
|
18
|
+
# case, the content of the block will be captured (using the
|
19
|
+
# {Nanoc::Helpers::Capturing} helper) and this content will be made
|
20
|
+
# available with `yield`. In other words, a `yield` inside the partial
|
21
|
+
# will output the content of the block passed to the method.
|
22
|
+
#
|
23
|
+
# (For the curious: the reason why {#render} with a block has this
|
24
|
+
# behaviour of returning an empty string and modifying `_erbout` is
|
25
|
+
# because ERB does not support combining the `<%= ... %>` form with a
|
26
|
+
# method call that takes a block.)
|
27
|
+
#
|
28
|
+
# The assigns (`@item`, `@config`, …) will be available in the partial. It
|
29
|
+
# is also possible to pass custom assigns to the method; these assigns
|
30
|
+
# will be made available as instance variables inside the partial.
|
31
|
+
#
|
32
|
+
# @param [String] identifier The identifier of the layout that should be
|
33
|
+
# rendered
|
34
|
+
#
|
35
|
+
# @param [Hash] other_assigns A hash containing extra assigns that will be
|
36
|
+
# made available as instance variables in the partial
|
37
|
+
#
|
38
|
+
# @example Rendering a head and a foot partial around some text
|
39
|
+
#
|
40
|
+
# <%= render 'head' %> - MIDDLE - <%= render 'foot' %>
|
41
|
+
# # => "HEAD - MIDDLE - FOOT"
|
42
|
+
#
|
43
|
+
# @example Rendering a head partial with a custom title
|
44
|
+
#
|
45
|
+
# # The 'head' layout
|
46
|
+
# <h1><%= @title %></h1>
|
47
|
+
#
|
48
|
+
# # The item/layout where the partial is rendered
|
49
|
+
# <%= render 'head', :title => 'Foo' %>
|
50
|
+
# # => "<h1>Foo</h1>"
|
51
|
+
#
|
52
|
+
# @example Yielding inside a partial
|
53
|
+
#
|
54
|
+
# # The 'box' partial
|
55
|
+
# <div class="box">
|
56
|
+
# <%= yield %>
|
57
|
+
# </div>
|
58
|
+
#
|
59
|
+
# # The item/layout where the partial is rendered
|
60
|
+
# <% render 'box' do %>
|
61
|
+
# I'm boxy! Luvz!
|
62
|
+
# <% end %>
|
63
|
+
#
|
64
|
+
# # Result
|
65
|
+
# <div class="box">
|
66
|
+
# I'm boxy! Luvz!
|
67
|
+
# </div>
|
68
|
+
#
|
69
|
+
# @raise [Nanoc::Errors::UnknownLayout] if the given layout does not
|
70
|
+
# exist
|
71
|
+
#
|
72
|
+
# @raise [Nanoc::Errors::CannotDetermineFilter] if there is no layout
|
73
|
+
# rule for the given layout
|
74
|
+
#
|
75
|
+
# @raise [Nanoc::Errors::UnknownFilter] if the layout rule for the given
|
76
|
+
# layout specifies an unknown filter
|
77
|
+
#
|
78
|
+
# @return [String, nil] The rendered partial, or nil if this method was
|
79
|
+
# invoked with a block
|
80
|
+
def render(identifier, other_assigns={}, &block)
|
81
|
+
# Find layout
|
82
|
+
layout = @site.layouts.find { |l| l.identifier == identifier.cleaned_identifier }
|
83
|
+
raise Nanoc::Errors::UnknownLayout.new(identifier.cleaned_identifier) if layout.nil?
|
84
|
+
|
85
|
+
# Visit
|
86
|
+
Nanoc::NotificationCenter.post(:visit_started, layout)
|
87
|
+
Nanoc::NotificationCenter.post(:visit_ended, layout)
|
88
|
+
|
89
|
+
# Capture content, if any
|
90
|
+
captured_content = block_given? ? capture(&block) : nil
|
91
|
+
|
92
|
+
# Get assigns
|
93
|
+
assigns = {
|
94
|
+
:content => captured_content,
|
95
|
+
:item => @item,
|
96
|
+
:item_rep => @item_rep,
|
97
|
+
:items => @items,
|
98
|
+
:layout => layout,
|
99
|
+
:layouts => @layouts,
|
100
|
+
:config => @config,
|
101
|
+
:site => @site
|
102
|
+
}.merge(other_assigns)
|
103
|
+
|
104
|
+
# Get filter name
|
105
|
+
filter_name, filter_args = @site.compiler.rules_collection.filter_for_layout(layout)
|
106
|
+
raise Nanoc::Errors::CannotDetermineFilter.new(layout.identifier) if filter_name.nil?
|
107
|
+
|
108
|
+
# Get filter class
|
109
|
+
filter_class = Nanoc::Filter.named(filter_name)
|
110
|
+
raise Nanoc::Errors::UnknownFilter.new(filter_name) if filter_class.nil?
|
111
|
+
|
112
|
+
# Create filter
|
113
|
+
filter = filter_class.new(assigns)
|
114
|
+
|
115
|
+
begin
|
116
|
+
# Notify start
|
117
|
+
Nanoc::NotificationCenter.post(:processing_started, layout)
|
118
|
+
|
119
|
+
# Layout
|
120
|
+
result = filter.run(layout.raw_content, filter_args)
|
121
|
+
|
122
|
+
# Append to erbout if we have a block
|
123
|
+
if block_given?
|
124
|
+
# Append result and return nothing
|
125
|
+
erbout = eval('_erbout', block.binding)
|
126
|
+
erbout << result
|
127
|
+
''
|
128
|
+
else
|
129
|
+
# Return result
|
130
|
+
result
|
131
|
+
end
|
132
|
+
ensure
|
133
|
+
# Notify end
|
134
|
+
Nanoc::NotificationCenter.post(:processing_ended, layout)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|