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,211 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
|
5
|
+
# Module that contains all nanoc-specific errors.
|
6
|
+
module Errors
|
7
|
+
|
8
|
+
# Generic error. Superclass for all nanoc-specific errors.
|
9
|
+
class Generic < ::StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
# Error that is raised when a site is loaded that uses a data source with
|
13
|
+
# an unknown identifier.
|
14
|
+
class UnknownDataSource < Generic
|
15
|
+
|
16
|
+
# @param [String] data_source_name The data source name for which no
|
17
|
+
# data source could be found
|
18
|
+
def initialize(data_source_name)
|
19
|
+
super("The data source specified in the site’s configuration file, “#{data_source_name}”, does not exist.".make_compatible_with_env)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# Error that is raised during site compilation when an item uses a layout
|
25
|
+
# that is not present in the site.
|
26
|
+
class UnknownLayout < Generic
|
27
|
+
|
28
|
+
# @param [String] layout_identifier The layout identifier for which no
|
29
|
+
# layout could be found
|
30
|
+
def initialize(layout_identifier)
|
31
|
+
super("The site does not have a layout with identifier “#{layout_identifier}”.".make_compatible_with_env)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Error that is raised during site compilation when an item uses a filter
|
37
|
+
# that is not known.
|
38
|
+
class UnknownFilter < Generic
|
39
|
+
|
40
|
+
# @param [Symbol] filter_name The filter name for which no filter could
|
41
|
+
# be found
|
42
|
+
def initialize(filter_name)
|
43
|
+
super("The requested filter, “#{filter_name}”, does not exist.".make_compatible_with_env)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# Error that is raised during site compilation when a layout is compiled
|
49
|
+
# for which the filter cannot be determined. This is similar to the
|
50
|
+
# {UnknownFilter} error, but specific for filters for layouts.
|
51
|
+
class CannotDetermineFilter < Generic
|
52
|
+
|
53
|
+
# @param [String] layout_identifier The identifier of the layout for
|
54
|
+
# which the filter could not be determined
|
55
|
+
def initialize(layout_identifier)
|
56
|
+
super("The filter to be used for the “#{layout_identifier}” layout could not be determined. Make sure the layout does have a filter.".make_compatible_with_env)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# Error that is raised during site compilation when an item (directly or
|
62
|
+
# indirectly) includes its own item content, leading to endless recursion.
|
63
|
+
class RecursiveCompilation < Generic
|
64
|
+
|
65
|
+
# @param [Array<Nanoc::ItemRep>] reps A list of item representations
|
66
|
+
# that mutually depend on each other
|
67
|
+
def initialize(reps)
|
68
|
+
list = reps.map { |r| r.inspect }.join("\n")
|
69
|
+
super("The site cannot be compiled because the following items mutually depend on each other:\n#{list}.".make_compatible_with_env)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
# Error that is raised when no rules file can be found in the current
|
75
|
+
# working directory.
|
76
|
+
class NoRulesFileFound < Generic
|
77
|
+
|
78
|
+
def initialize
|
79
|
+
super("This site does not have a rules file, which is required for nanoc sites.".make_compatible_with_env)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# Error that is raised when no compilation rule that can be applied to the
|
85
|
+
# current item can be found.
|
86
|
+
class NoMatchingCompilationRuleFound < Generic
|
87
|
+
|
88
|
+
# @param [Nanoc::Item] item The item for which no compilation rule
|
89
|
+
# could be found
|
90
|
+
def initialize(item)
|
91
|
+
super("No compilation rules were found for the “#{item.identifier}” item.".make_compatible_with_env)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
# Error that is raised when no routing rule that can be applied to the
|
97
|
+
# current item can be found.
|
98
|
+
class NoMatchingRoutingRuleFound < Generic
|
99
|
+
|
100
|
+
# @param [Nanoc::Item] item The item for which no routing rule could be
|
101
|
+
# found
|
102
|
+
def initialize(rep)
|
103
|
+
super("No routing rules were found for the “#{rep.item.identifier}” item (rep “#{rep.name}”).".make_compatible_with_env)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
# Error that is raised when an rep cannot be compiled because it depends
|
109
|
+
# on other representations.
|
110
|
+
class UnmetDependency < Generic
|
111
|
+
|
112
|
+
# @return [Nanoc::ItemRep] The item representation that cannot yet be
|
113
|
+
# compiled
|
114
|
+
attr_reader :rep
|
115
|
+
|
116
|
+
# @param [Nanoc::ItemRep] The item representation that cannot yet be
|
117
|
+
# compiled
|
118
|
+
def initialize(rep)
|
119
|
+
@rep = rep
|
120
|
+
super("The current item cannot be compiled yet because of an unmet dependency on the “#{rep.item.identifier}” item (rep “#{rep.name}”).".make_compatible_with_env)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
# Error that is raised when a binary item is attempted to be laid out.
|
126
|
+
class CannotLayoutBinaryItem < Generic
|
127
|
+
|
128
|
+
# @param [Nanoc::ItemRep] The item representation that was attempted to
|
129
|
+
# be laid out
|
130
|
+
def initialize(rep)
|
131
|
+
super("The “{rep.item.identifier}” item (rep “#{rep.name}”) cannot be laid out because it is a binary item. If you are getting this error for an item that should be textual instead of binary, make sure that its extension is included in the text_extensions array in the site configuration.".make_compatible_with_env)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
# Error that is raised when a textual filter is attempted to be applied to
|
137
|
+
# a binary item representation.
|
138
|
+
class CannotUseTextualFilter < Generic
|
139
|
+
|
140
|
+
# @param [Nanoc::ItemRep] rep The item representation that was
|
141
|
+
# attempted to be filtered
|
142
|
+
#
|
143
|
+
# @param [Class] filter_class The filter class that was used
|
144
|
+
def initialize(rep, filter_class)
|
145
|
+
super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because textual filters cannot be used on binary items.".make_compatible_with_env)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
# Error that is raised when a binary filter is attempted to be applied to
|
151
|
+
# a textual item representation.
|
152
|
+
class CannotUseBinaryFilter < Generic
|
153
|
+
|
154
|
+
# @param [Nanoc::ItemRep] rep The item representation that was
|
155
|
+
# attempted to be filtered
|
156
|
+
#
|
157
|
+
# @param [Class] filter_class The filter class that was used
|
158
|
+
def initialize(rep, filter_class)
|
159
|
+
super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because binary filters cannot be used on textual items. If you are getting this error for an item that should be textual instead of binary, make sure that its extension is included in the text_extensions array in the site configuration.".make_compatible_with_env)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
# Error that is raised when the compiled content at a non-existing snapshot
|
165
|
+
# is requested.
|
166
|
+
class NoSuchSnapshot < Generic
|
167
|
+
|
168
|
+
# @return [Nanoc::ItemRep] The item rep from which the compiled content
|
169
|
+
# was requested
|
170
|
+
attr_reader :item_rep
|
171
|
+
|
172
|
+
# @return [Symbol] The requested snapshot
|
173
|
+
attr_reader :snapshot
|
174
|
+
|
175
|
+
# @param [Nanoc::ItemRep] item_rep The item rep from which the compiled
|
176
|
+
# content was requested
|
177
|
+
#
|
178
|
+
# @param [Symbol] snapshot The requested snapshot
|
179
|
+
def initialize(item_rep, snapshot)
|
180
|
+
@item_rep, @snapshot = item_rep, snapshot
|
181
|
+
super("The “#{item_rep.inspect}” item rep does not have a snapshot “#{snapshot.inspect}”")
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
# Error that is raised when a snapshot with an existing name is made.
|
187
|
+
class CannotCreateMultipleSnapshotsWithSameName < Generic
|
188
|
+
|
189
|
+
# @param [Nanoc::ItemRep] rep The item representation for which a
|
190
|
+
# snapshot was attempted to be made
|
191
|
+
#
|
192
|
+
# @param [Symbol] snapshot The name of the snapshot that was attempted to
|
193
|
+
# be made
|
194
|
+
def initialize(rep, snapshot)
|
195
|
+
super("Attempted to create a snapshot with a duplicate name #{snapshot.inspect} for the item rep “#{rep.inspect}”".make_compatible_with_env)
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
# @deprecated No longer necessary, but kept for backwards compatibility.
|
201
|
+
class DataNotYetAvailable < Generic
|
202
|
+
|
203
|
+
def initialize(type, plural)
|
204
|
+
super("#{type} #{plural ? 'are' : 'is'} not available yet. You may be missing a Nanoc::Site#load_data call.".make_compatible_with_env)
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
|
5
|
+
# Adds support for memoizing functions.
|
6
|
+
#
|
7
|
+
# @since 3.2.0
|
8
|
+
module Memoization
|
9
|
+
|
10
|
+
# Memoizes the method with the given name. The modified method will cache
|
11
|
+
# the results of the original method, so that calling a method twice with
|
12
|
+
# the same arguments will short-circuit and return the cached results
|
13
|
+
# immediately.
|
14
|
+
#
|
15
|
+
# Memoization assumes that the current object as well as the function
|
16
|
+
# arguments are immutable. Mutating the object or the arguments will not
|
17
|
+
# cause memoized methods to recalculate their results. There is no way to
|
18
|
+
# un-memoize a result, and calculation results will remain in memory even
|
19
|
+
# if they are no longer needed.
|
20
|
+
#
|
21
|
+
# @example A fast fib function due to memoization
|
22
|
+
#
|
23
|
+
# class FibFast
|
24
|
+
#
|
25
|
+
# extend Nanoc::Memoization
|
26
|
+
#
|
27
|
+
# def run(n)
|
28
|
+
# if n == 0
|
29
|
+
# 0
|
30
|
+
# elsif n == 1
|
31
|
+
# 1
|
32
|
+
# else
|
33
|
+
# run(n-1) + run(n-2)
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
# memoize :run
|
37
|
+
#
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# @param [Symbol, String] method_name The name of the method to memoize
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
def memoize(method_name)
|
44
|
+
# Alias
|
45
|
+
original_method_name = '__nonmemoized_' + method_name.to_s
|
46
|
+
alias_method original_method_name, method_name
|
47
|
+
|
48
|
+
# Redefine
|
49
|
+
define_method(method_name) do |*args|
|
50
|
+
# Get cache
|
51
|
+
@__memoization_cache ||= {}
|
52
|
+
@__memoization_cache[method_name] ||= {}
|
53
|
+
|
54
|
+
# Recalculate if necessary
|
55
|
+
if !@__memoization_cache[method_name].has_key?(args)
|
56
|
+
result = send(original_method_name, *args)
|
57
|
+
@__memoization_cache[method_name][args] = result
|
58
|
+
end
|
59
|
+
|
60
|
+
# Done
|
61
|
+
@__memoization_cache[method_name][args]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
|
5
|
+
# Provides a way to send notifications between objects. It allows blocks
|
6
|
+
# associated with a certain notification name to be registered; these blocks
|
7
|
+
# will be called when the notification with the given name is posted.
|
8
|
+
#
|
9
|
+
# It is a slightly different implementation of the Observer pattern; the
|
10
|
+
# table of subscribers is not stored in the observable object itself, but in
|
11
|
+
# the notification center.
|
12
|
+
class NotificationCenter
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
# Adds the given block to the list of blocks that should be called when
|
17
|
+
# the notification with the given name is received.
|
18
|
+
#
|
19
|
+
# @param [String, Symbol] name The name of the notification that will
|
20
|
+
# cause the given block to be called.
|
21
|
+
#
|
22
|
+
# @param [String, Symbol, nil] id An identifier for the block. This is
|
23
|
+
# only used to be able to remove the block (using the remove method)
|
24
|
+
# later. Can be nil, but this is not recommended because it prevents
|
25
|
+
# the given notification block from being unregistered.
|
26
|
+
#
|
27
|
+
# @yield [*args] Will be executed with the arguments passed to {.post}
|
28
|
+
#
|
29
|
+
# @return [void]
|
30
|
+
def on(name, id=nil, &block)
|
31
|
+
initialize_if_necessary(name)
|
32
|
+
|
33
|
+
# Add observer
|
34
|
+
@notifications[name] << { :id => id, :block => block }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Posts a notification with the given name and the given arguments.
|
38
|
+
#
|
39
|
+
# @param [String, Symbol] name The name of the notification that should
|
40
|
+
# be posted.
|
41
|
+
#
|
42
|
+
# @param args Arguments that wil be passed to the blocks handling the
|
43
|
+
# notification.
|
44
|
+
#
|
45
|
+
# @return [void]
|
46
|
+
def post(name, *args)
|
47
|
+
initialize_if_necessary(name)
|
48
|
+
|
49
|
+
# Notify all observers
|
50
|
+
@notifications[name].each do |observer|
|
51
|
+
observer[:block].call(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Removes the block with the given identifier from the list of blocks
|
56
|
+
# that should be called when the notification with the given name is
|
57
|
+
# posted.
|
58
|
+
#
|
59
|
+
# @param [String, Symbol] name The name of the notification that should
|
60
|
+
# no longer be registered.
|
61
|
+
#
|
62
|
+
# @param [String, Symbol] id The identifier of the block that should be
|
63
|
+
# removed.
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
def remove(name, id)
|
67
|
+
initialize_if_necessary(name)
|
68
|
+
|
69
|
+
# Remove relevant observers
|
70
|
+
@notifications[name].reject! { |i| i[:id] == id }
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def initialize_if_necessary(name)
|
76
|
+
@notifications ||= {} # name => observers dictionary
|
77
|
+
@notifications[name] ||= [] # list of observers
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
|
2
|
+
# AUTHOR
|
3
|
+
# jan molic /mig/at/1984/dot/cz/
|
4
|
+
#
|
5
|
+
# DESCRIPTION
|
6
|
+
# Hash with preserved order and some array-like extensions
|
7
|
+
# Public domain.
|
8
|
+
#
|
9
|
+
# THANKS
|
10
|
+
# Andrew Johnson for his suggestions and fixes of Hash[],
|
11
|
+
# merge, to_a, inspect and shift
|
12
|
+
class OrderedHash < ::Hash
|
13
|
+
attr_accessor :order
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def [] *args
|
17
|
+
hsh = OrderedHash.new
|
18
|
+
if Hash === args[0]
|
19
|
+
hsh.replace args[0]
|
20
|
+
elsif (args.size % 2) != 0
|
21
|
+
raise ArgumentError, "odd number of elements for Hash"
|
22
|
+
else
|
23
|
+
0.step(args.size - 1, 2) do |a|
|
24
|
+
b = a + 1
|
25
|
+
hsh[args[a]] = args[b]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
hsh
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def initialize(*a, &b)
|
32
|
+
super
|
33
|
+
@order = []
|
34
|
+
end
|
35
|
+
def store_only a,b
|
36
|
+
store a,b
|
37
|
+
end
|
38
|
+
alias orig_store store
|
39
|
+
def store a,b
|
40
|
+
@order.push a unless has_key? a
|
41
|
+
super a,b
|
42
|
+
end
|
43
|
+
alias []= store
|
44
|
+
def == hsh2
|
45
|
+
return false if @order != hsh2.order
|
46
|
+
super hsh2
|
47
|
+
end
|
48
|
+
def clear
|
49
|
+
@order = []
|
50
|
+
super
|
51
|
+
end
|
52
|
+
def delete key
|
53
|
+
@order.delete key
|
54
|
+
super
|
55
|
+
end
|
56
|
+
def each_key
|
57
|
+
@order.each { |k| yield k }
|
58
|
+
self
|
59
|
+
end
|
60
|
+
def each_value
|
61
|
+
@order.each { |k| yield self[k] }
|
62
|
+
self
|
63
|
+
end
|
64
|
+
def each
|
65
|
+
@order.each { |k| yield k,self[k] }
|
66
|
+
self
|
67
|
+
end
|
68
|
+
alias each_pair each
|
69
|
+
def delete_if
|
70
|
+
@order.clone.each { |k|
|
71
|
+
delete k if yield(k)
|
72
|
+
}
|
73
|
+
self
|
74
|
+
end
|
75
|
+
def values
|
76
|
+
ary = []
|
77
|
+
@order.each { |k| ary.push self[k] }
|
78
|
+
ary
|
79
|
+
end
|
80
|
+
def keys
|
81
|
+
@order
|
82
|
+
end
|
83
|
+
def first
|
84
|
+
{@order.first => self[@order.first]}
|
85
|
+
end
|
86
|
+
def last
|
87
|
+
{@order.last => self[@order.last]}
|
88
|
+
end
|
89
|
+
def invert
|
90
|
+
hsh2 = Hash.new
|
91
|
+
@order.each { |k| hsh2[self[k]] = k }
|
92
|
+
hsh2
|
93
|
+
end
|
94
|
+
def reject &block
|
95
|
+
self.dup.delete_if &block
|
96
|
+
end
|
97
|
+
def reject! &block
|
98
|
+
hsh2 = reject &block
|
99
|
+
self == hsh2 ? nil : hsh2
|
100
|
+
end
|
101
|
+
def replace hsh2
|
102
|
+
@order = hsh2.keys
|
103
|
+
super hsh2
|
104
|
+
end
|
105
|
+
def shift
|
106
|
+
key = @order.first
|
107
|
+
key ? [key,delete(key)] : super
|
108
|
+
end
|
109
|
+
def unshift k,v
|
110
|
+
unless self.include? k
|
111
|
+
@order.unshift k
|
112
|
+
orig_store(k,v)
|
113
|
+
true
|
114
|
+
else
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def push k,v
|
119
|
+
unless self.include? k
|
120
|
+
@order.push k
|
121
|
+
orig_store(k,v)
|
122
|
+
true
|
123
|
+
else
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
def pop
|
128
|
+
key = @order.last
|
129
|
+
key ? [key,delete(key)] : nil
|
130
|
+
end
|
131
|
+
def to_a
|
132
|
+
ary = []
|
133
|
+
each { |k,v| ary << [k,v] }
|
134
|
+
ary
|
135
|
+
end
|
136
|
+
def to_s
|
137
|
+
self.to_a.to_s
|
138
|
+
end
|
139
|
+
def inspect
|
140
|
+
ary = []
|
141
|
+
each {|k,v| ary << k.inspect + "=>" + v.inspect}
|
142
|
+
'{' + ary.join(", ") + '}'
|
143
|
+
end
|
144
|
+
def update hsh2
|
145
|
+
hsh2.each { |k,v| self[k] = v }
|
146
|
+
self
|
147
|
+
end
|
148
|
+
alias :merge! update
|
149
|
+
def merge hsh2
|
150
|
+
self.dup update(hsh2)
|
151
|
+
end
|
152
|
+
def select
|
153
|
+
ary = []
|
154
|
+
each { |k,v| ary << [k,v] if yield k,v }
|
155
|
+
ary
|
156
|
+
end
|
157
|
+
def class
|
158
|
+
Hash
|
159
|
+
end
|
160
|
+
def __class__
|
161
|
+
OrderedHash
|
162
|
+
end
|
163
|
+
|
164
|
+
attr_accessor "to_yaml_style"
|
165
|
+
def yaml_inline= bool
|
166
|
+
if respond_to?("to_yaml_style")
|
167
|
+
self.to_yaml_style = :inline
|
168
|
+
else
|
169
|
+
unless defined? @__yaml_inline_meth
|
170
|
+
@__yaml_inline_meth =
|
171
|
+
lambda {|opts|
|
172
|
+
YAML::quick_emit(object_id, opts) {|emitter|
|
173
|
+
emitter << '{ ' << map{|kv| kv.join ': '}.join(', ') << ' }'
|
174
|
+
}
|
175
|
+
}
|
176
|
+
class << self
|
177
|
+
def to_yaml opts = {}
|
178
|
+
begin
|
179
|
+
@__yaml_inline ? @__yaml_inline_meth[ opts ] : super
|
180
|
+
rescue
|
181
|
+
@to_yaml_style = :inline
|
182
|
+
super
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
@__yaml_inline = bool
|
189
|
+
end
|
190
|
+
def yaml_inline!() self.yaml_inline = true end
|
191
|
+
|
192
|
+
def each_with_index
|
193
|
+
@order.each_with_index { |k, index| yield k, self[k], index }
|
194
|
+
self
|
195
|
+
end
|
196
|
+
end # class OrderedHash
|
197
|
+
|
198
|
+
def OrderedHash(*a, &b)
|
199
|
+
OrderedHash.new(*a, &b)
|
200
|
+
end
|