nanoc 3.2.4 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (230) hide show
  1. data/.gemtest +0 -0
  2. data/ChangeLog +3 -0
  3. data/Gemfile +32 -0
  4. data/LICENSE +19 -0
  5. data/NEWS.md +470 -0
  6. data/README.md +114 -0
  7. data/Rakefile +14 -0
  8. data/bin/nanoc +7 -27
  9. data/bin/nanoc3 +3 -0
  10. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  11. data/lib/nanoc.rb +41 -0
  12. data/lib/nanoc/base.rb +49 -0
  13. data/lib/nanoc/base/compilation/checksum_store.rb +57 -0
  14. data/lib/nanoc/base/compilation/compiled_content_cache.rb +62 -0
  15. data/lib/nanoc/base/compilation/compiler.rb +458 -0
  16. data/lib/nanoc/base/compilation/compiler_dsl.rb +214 -0
  17. data/lib/nanoc/base/compilation/dependency_tracker.rb +200 -0
  18. data/lib/nanoc/base/compilation/filter.rb +165 -0
  19. data/lib/nanoc/base/compilation/item_rep_proxy.rb +103 -0
  20. data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +102 -0
  21. data/lib/nanoc/base/compilation/outdatedness_checker.rb +223 -0
  22. data/lib/nanoc/base/compilation/outdatedness_reasons.rb +46 -0
  23. data/lib/nanoc/base/compilation/rule.rb +73 -0
  24. data/lib/nanoc/base/compilation/rule_context.rb +84 -0
  25. data/lib/nanoc/base/compilation/rule_memory_calculator.rb +40 -0
  26. data/lib/nanoc/base/compilation/rule_memory_store.rb +53 -0
  27. data/lib/nanoc/base/compilation/rules_collection.rb +243 -0
  28. data/lib/nanoc/base/context.rb +47 -0
  29. data/lib/nanoc/base/core_ext.rb +6 -0
  30. data/lib/nanoc/base/core_ext/array.rb +62 -0
  31. data/lib/nanoc/base/core_ext/hash.rb +63 -0
  32. data/lib/nanoc/base/core_ext/pathname.rb +26 -0
  33. data/lib/nanoc/base/core_ext/string.rb +46 -0
  34. data/lib/nanoc/base/directed_graph.rb +275 -0
  35. data/lib/nanoc/base/errors.rb +211 -0
  36. data/lib/nanoc/base/memoization.rb +67 -0
  37. data/lib/nanoc/base/notification_center.rb +84 -0
  38. data/lib/nanoc/base/ordered_hash.rb +200 -0
  39. data/lib/nanoc/base/plugin_registry.rb +181 -0
  40. data/lib/nanoc/base/result_data/item_rep.rb +492 -0
  41. data/lib/nanoc/base/source_data/code_snippet.rb +58 -0
  42. data/lib/nanoc/base/source_data/configuration.rb +24 -0
  43. data/lib/nanoc/base/source_data/data_source.rb +234 -0
  44. data/lib/nanoc/base/source_data/item.rb +301 -0
  45. data/lib/nanoc/base/source_data/layout.rb +130 -0
  46. data/lib/nanoc/base/source_data/site.rb +361 -0
  47. data/lib/nanoc/base/store.rb +135 -0
  48. data/lib/nanoc/cli.rb +137 -0
  49. data/lib/nanoc/cli/command_runner.rb +104 -0
  50. data/lib/nanoc/cli/commands/autocompile.rb +58 -0
  51. data/lib/nanoc/cli/commands/compile.rb +297 -0
  52. data/lib/nanoc/cli/commands/create_item.rb +60 -0
  53. data/lib/nanoc/cli/commands/create_layout.rb +73 -0
  54. data/lib/nanoc/cli/commands/create_site.rb +411 -0
  55. data/lib/nanoc/cli/commands/debug.rb +117 -0
  56. data/lib/nanoc/cli/commands/deploy.rb +79 -0
  57. data/lib/nanoc/cli/commands/info.rb +98 -0
  58. data/lib/nanoc/cli/commands/nanoc.rb +38 -0
  59. data/lib/nanoc/cli/commands/prune.rb +50 -0
  60. data/lib/nanoc/cli/commands/update.rb +70 -0
  61. data/lib/nanoc/cli/commands/view.rb +82 -0
  62. data/lib/nanoc/cli/commands/watch.rb +124 -0
  63. data/lib/nanoc/cli/error_handler.rb +199 -0
  64. data/lib/nanoc/cli/logger.rb +92 -0
  65. data/lib/nanoc/data_sources.rb +29 -0
  66. data/lib/nanoc/data_sources/deprecated/delicious.rb +42 -0
  67. data/lib/nanoc/data_sources/deprecated/last_fm.rb +87 -0
  68. data/lib/nanoc/data_sources/deprecated/twitter.rb +38 -0
  69. data/lib/nanoc/data_sources/filesystem.rb +299 -0
  70. data/lib/nanoc/data_sources/filesystem_unified.rb +121 -0
  71. data/lib/nanoc/data_sources/filesystem_verbose.rb +91 -0
  72. data/lib/nanoc/extra.rb +24 -0
  73. data/lib/nanoc/extra/auto_compiler.rb +103 -0
  74. data/lib/nanoc/extra/chick.rb +125 -0
  75. data/lib/nanoc/extra/core_ext.rb +6 -0
  76. data/lib/nanoc/extra/core_ext/enumerable.rb +33 -0
  77. data/lib/nanoc/extra/core_ext/pathname.rb +30 -0
  78. data/lib/nanoc/extra/core_ext/time.rb +19 -0
  79. data/lib/nanoc/extra/deployer.rb +47 -0
  80. data/lib/nanoc/extra/deployers.rb +15 -0
  81. data/lib/nanoc/extra/deployers/fog.rb +98 -0
  82. data/lib/nanoc/extra/deployers/rsync.rb +70 -0
  83. data/lib/nanoc/extra/file_proxy.rb +40 -0
  84. data/lib/nanoc/extra/pruner.rb +86 -0
  85. data/lib/nanoc/extra/validators.rb +12 -0
  86. data/lib/nanoc/extra/validators/links.rb +268 -0
  87. data/lib/nanoc/extra/validators/w3c.rb +95 -0
  88. data/lib/nanoc/extra/vcs.rb +66 -0
  89. data/lib/nanoc/extra/vcses.rb +17 -0
  90. data/lib/nanoc/extra/vcses/bazaar.rb +25 -0
  91. data/lib/nanoc/extra/vcses/dummy.rb +24 -0
  92. data/lib/nanoc/extra/vcses/git.rb +25 -0
  93. data/lib/nanoc/extra/vcses/mercurial.rb +25 -0
  94. data/lib/nanoc/extra/vcses/subversion.rb +25 -0
  95. data/lib/nanoc/filters.rb +59 -0
  96. data/lib/nanoc/filters/asciidoc.rb +38 -0
  97. data/lib/nanoc/filters/bluecloth.rb +19 -0
  98. data/lib/nanoc/filters/coderay.rb +21 -0
  99. data/lib/nanoc/filters/coffeescript.rb +20 -0
  100. data/lib/nanoc/filters/colorize_syntax.rb +298 -0
  101. data/lib/nanoc/filters/erb.rb +38 -0
  102. data/lib/nanoc/filters/erubis.rb +34 -0
  103. data/lib/nanoc/filters/haml.rb +27 -0
  104. data/lib/nanoc/filters/kramdown.rb +20 -0
  105. data/lib/nanoc/filters/less.rb +53 -0
  106. data/lib/nanoc/filters/markaby.rb +20 -0
  107. data/lib/nanoc/filters/maruku.rb +20 -0
  108. data/lib/nanoc/filters/mustache.rb +24 -0
  109. data/lib/nanoc/filters/rainpress.rb +19 -0
  110. data/lib/nanoc/filters/rdiscount.rb +22 -0
  111. data/lib/nanoc/filters/rdoc.rb +33 -0
  112. data/lib/nanoc/filters/redcarpet.rb +62 -0
  113. data/lib/nanoc/filters/redcloth.rb +47 -0
  114. data/lib/nanoc/filters/relativize_paths.rb +94 -0
  115. data/lib/nanoc/filters/rubypants.rb +20 -0
  116. data/lib/nanoc/filters/sass.rb +74 -0
  117. data/lib/nanoc/filters/slim.rb +25 -0
  118. data/lib/nanoc/filters/typogruby.rb +23 -0
  119. data/lib/nanoc/filters/uglify_js.rb +42 -0
  120. data/lib/nanoc/filters/xsl.rb +46 -0
  121. data/lib/nanoc/filters/yui_compressor.rb +23 -0
  122. data/lib/nanoc/helpers.rb +16 -0
  123. data/lib/nanoc/helpers/blogging.rb +319 -0
  124. data/lib/nanoc/helpers/breadcrumbs.rb +40 -0
  125. data/lib/nanoc/helpers/capturing.rb +138 -0
  126. data/lib/nanoc/helpers/filtering.rb +50 -0
  127. data/lib/nanoc/helpers/html_escape.rb +55 -0
  128. data/lib/nanoc/helpers/link_to.rb +151 -0
  129. data/lib/nanoc/helpers/rendering.rb +140 -0
  130. data/lib/nanoc/helpers/tagging.rb +71 -0
  131. data/lib/nanoc/helpers/text.rb +44 -0
  132. data/lib/nanoc/helpers/xml_sitemap.rb +76 -0
  133. data/lib/nanoc/tasks.rb +10 -0
  134. data/lib/nanoc/tasks/clean.rake +16 -0
  135. data/lib/nanoc/tasks/clean.rb +29 -0
  136. data/lib/nanoc/tasks/deploy/rsync.rake +16 -0
  137. data/lib/nanoc/tasks/validate.rake +92 -0
  138. data/nanoc.gemspec +49 -0
  139. data/tasks/doc.rake +16 -0
  140. data/tasks/test.rake +46 -0
  141. data/test/base/core_ext/array_spec.rb +73 -0
  142. data/test/base/core_ext/hash_spec.rb +98 -0
  143. data/test/base/core_ext/pathname_spec.rb +27 -0
  144. data/test/base/core_ext/string_spec.rb +37 -0
  145. data/test/base/test_checksum_store.rb +35 -0
  146. data/test/base/test_code_snippet.rb +31 -0
  147. data/test/base/test_compiler.rb +403 -0
  148. data/test/base/test_compiler_dsl.rb +161 -0
  149. data/test/base/test_context.rb +31 -0
  150. data/test/base/test_data_source.rb +46 -0
  151. data/test/base/test_dependency_tracker.rb +262 -0
  152. data/test/base/test_directed_graph.rb +288 -0
  153. data/test/base/test_filter.rb +83 -0
  154. data/test/base/test_item.rb +179 -0
  155. data/test/base/test_item_rep.rb +579 -0
  156. data/test/base/test_layout.rb +59 -0
  157. data/test/base/test_memoization.rb +90 -0
  158. data/test/base/test_notification_center.rb +34 -0
  159. data/test/base/test_outdatedness_checker.rb +394 -0
  160. data/test/base/test_plugin.rb +30 -0
  161. data/test/base/test_rule.rb +19 -0
  162. data/test/base/test_rule_context.rb +65 -0
  163. data/test/base/test_site.rb +190 -0
  164. data/test/cli/commands/test_compile.rb +33 -0
  165. data/test/cli/commands/test_create_item.rb +14 -0
  166. data/test/cli/commands/test_create_layout.rb +28 -0
  167. data/test/cli/commands/test_create_site.rb +24 -0
  168. data/test/cli/commands/test_deploy.rb +74 -0
  169. data/test/cli/commands/test_help.rb +12 -0
  170. data/test/cli/commands/test_info.rb +11 -0
  171. data/test/cli/commands/test_prune.rb +98 -0
  172. data/test/cli/commands/test_update.rb +10 -0
  173. data/test/cli/test_cli.rb +102 -0
  174. data/test/cli/test_error_handler.rb +29 -0
  175. data/test/cli/test_logger.rb +10 -0
  176. data/test/data_sources/test_filesystem.rb +433 -0
  177. data/test/data_sources/test_filesystem_unified.rb +536 -0
  178. data/test/data_sources/test_filesystem_verbose.rb +357 -0
  179. data/test/extra/core_ext/test_enumerable.rb +30 -0
  180. data/test/extra/core_ext/test_pathname.rb +17 -0
  181. data/test/extra/core_ext/test_time.rb +15 -0
  182. data/test/extra/deployers/test_fog.rb +67 -0
  183. data/test/extra/deployers/test_rsync.rb +100 -0
  184. data/test/extra/test_auto_compiler.rb +417 -0
  185. data/test/extra/test_file_proxy.rb +19 -0
  186. data/test/extra/test_vcs.rb +22 -0
  187. data/test/extra/validators/test_links.rb +62 -0
  188. data/test/extra/validators/test_w3c.rb +47 -0
  189. data/test/filters/test_asciidoc.rb +22 -0
  190. data/test/filters/test_bluecloth.rb +18 -0
  191. data/test/filters/test_coderay.rb +44 -0
  192. data/test/filters/test_coffeescript.rb +18 -0
  193. data/test/filters/test_colorize_syntax.rb +379 -0
  194. data/test/filters/test_erb.rb +105 -0
  195. data/test/filters/test_erubis.rb +78 -0
  196. data/test/filters/test_haml.rb +96 -0
  197. data/test/filters/test_kramdown.rb +18 -0
  198. data/test/filters/test_less.rb +113 -0
  199. data/test/filters/test_markaby.rb +24 -0
  200. data/test/filters/test_maruku.rb +18 -0
  201. data/test/filters/test_mustache.rb +25 -0
  202. data/test/filters/test_rainpress.rb +29 -0
  203. data/test/filters/test_rdiscount.rb +31 -0
  204. data/test/filters/test_rdoc.rb +18 -0
  205. data/test/filters/test_redcarpet.rb +73 -0
  206. data/test/filters/test_redcloth.rb +33 -0
  207. data/test/filters/test_relativize_paths.rb +533 -0
  208. data/test/filters/test_rubypants.rb +18 -0
  209. data/test/filters/test_sass.rb +229 -0
  210. data/test/filters/test_slim.rb +35 -0
  211. data/test/filters/test_typogruby.rb +21 -0
  212. data/test/filters/test_uglify_js.rb +30 -0
  213. data/test/filters/test_xsl.rb +105 -0
  214. data/test/filters/test_yui_compressor.rb +44 -0
  215. data/test/gem_loader.rb +11 -0
  216. data/test/helper.rb +207 -0
  217. data/test/helpers/test_blogging.rb +754 -0
  218. data/test/helpers/test_breadcrumbs.rb +81 -0
  219. data/test/helpers/test_capturing.rb +41 -0
  220. data/test/helpers/test_filtering.rb +106 -0
  221. data/test/helpers/test_html_escape.rb +32 -0
  222. data/test/helpers/test_link_to.rb +249 -0
  223. data/test/helpers/test_rendering.rb +89 -0
  224. data/test/helpers/test_tagging.rb +87 -0
  225. data/test/helpers/test_text.rb +24 -0
  226. data/test/helpers/test_xml_sitemap.rb +103 -0
  227. data/test/tasks/test_clean.rb +67 -0
  228. metadata +327 -15
  229. data/bin/nanoc-select +0 -86
  230. 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