nanoc 3.2.4 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,58 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Nanoc::CodeSnippet represent a piece of custom code of a nanoc site.
6
+ class CodeSnippet
7
+
8
+ # A string containing the actual code in this code snippet.
9
+ #
10
+ # @return [String]
11
+ attr_reader :data
12
+
13
+ # The filename corresponding to this code snippet.
14
+ #
15
+ # @return [String]
16
+ attr_reader :filename
17
+
18
+ # Creates a new code snippet.
19
+ #
20
+ # @param [String] data The raw source code which will be executed before
21
+ # compilation
22
+ #
23
+ # @param [String] filename The filename corresponding to this code snippet
24
+ #
25
+ # @param [Time, Hash] params Extra parameters. Ignored by nanoc; it is
26
+ # only included for backwards compatibility.
27
+ def initialize(data, filename, params=nil)
28
+ @data = data
29
+ @filename = filename
30
+ end
31
+
32
+ # Loads the code by executing it.
33
+ #
34
+ # @return [void]
35
+ def load
36
+ eval(@data, TOPLEVEL_BINDING, @filename)
37
+ end
38
+
39
+ # Returns an object that can be used for uniquely identifying objects.
40
+ #
41
+ # @return [Object] An unique reference to this object
42
+ def reference
43
+ [ :code_snippet, filename ]
44
+ end
45
+
46
+ def inspect
47
+ "<#{self.class} filename=#{self.filename}>"
48
+ end
49
+
50
+ # @return [String] The checksum for this object. If its contents change,
51
+ # the checksum will change as well.
52
+ def checksum
53
+ @data.checksum
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Represents the site configuration.
6
+ class Configuration < ::Hash
7
+
8
+ # Creates a new configuration with the given hash.
9
+ #
10
+ # @param [Hash] hash The actual configuration hash
11
+ def initialize(hash)
12
+ self.replace(hash)
13
+ end
14
+
15
+ # Returns an object that can be used for uniquely identifying objects.
16
+ #
17
+ # @return [Object] An unique reference to this object
18
+ def reference
19
+ :config
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,234 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Responsible for loading site data. It is the (abstract) superclass for all
6
+ # data sources. Subclasses must at least implement the data reading methods
7
+ # ({#items} and {#layouts}); all other methods involving data manipulation
8
+ # are optional.
9
+ #
10
+ # Apart from the methods for loading and storing data, there are the {#up}
11
+ # and {#down} methods for bringing up and tearing down the connection to the
12
+ # data source. These should be overridden in subclasses. The {#loading}
13
+ # method wraps {#up} and {#down}. {#loading} is a convenience method for the
14
+ # more low-level methods {#use} and {#unuse}, which respectively increment
15
+ # and decrement the reference count; when the reference count goes from 0 to
16
+ # 1, the data source will be loaded ({#up} will be called) and when the
17
+ # reference count goes from 1 to 0, the data source will be unloaded
18
+ # ({#down} will be called).
19
+ #
20
+ # The {#setup} method is used for setting up a site's data source for the
21
+ # first time.
22
+ #
23
+ # @abstract Subclasses should at least implement {#items} and {#layouts}. If
24
+ # the data source should support creating items and layouts using the
25
+ # `create_item` and `create_layout` CLI commands, the {#setup},
26
+ # {#create_item} and {#create_layout} methods should be implemented as
27
+ # well.
28
+ class DataSource
29
+
30
+ # @return [String] The root path where items returned by this data source
31
+ # should be mounted.
32
+ attr_reader :items_root
33
+
34
+ # @return [String] The root path where layouts returned by this data
35
+ # source should be mounted.
36
+ attr_reader :layouts_root
37
+
38
+ # @return [Hash] The configuration for this data source. For example,
39
+ # online data sources could contain authentication details.
40
+ attr_reader :config
41
+
42
+ extend Nanoc::PluginRegistry::PluginMethods
43
+
44
+ # Creates a new data source for the given site.
45
+ #
46
+ # @param [Nanoc::Site] site The site this data source belongs to.
47
+ #
48
+ # @param [String] items_root The prefix that should be given to all items
49
+ # returned by the #items method (comparable to mount points for
50
+ # filesystems in Unix-ish OSes).
51
+ #
52
+ # @param [String] layouts_root The prefix that should be given to all
53
+ # layouts returned by the #layouts method (comparable to mount points
54
+ # for filesystems in Unix-ish OSes).
55
+ #
56
+ # @param [Hash] config The configuration for this data source.
57
+ def initialize(site, items_root, layouts_root, config)
58
+ @site = site
59
+ @items_root = items_root
60
+ @layouts_root = layouts_root
61
+ @config = config
62
+
63
+ @references = 0
64
+ end
65
+
66
+ # Loads the data source when necessary (calling {#up}), yields, and
67
+ # unloads (using {#down}) the data source when it is not being used
68
+ # elsewhere. All data source queries and data manipulations should be
69
+ # wrapped in a {#loading} block; it ensures that the data source is loaded
70
+ # when necessary and makes sure the data source does not get unloaded
71
+ # while it is still being used elsewhere.
72
+ #
73
+ # @return [void]
74
+ def loading
75
+ use
76
+ yield
77
+ ensure
78
+ unuse
79
+ end
80
+
81
+ # Marks the data source as used by the caller.
82
+ #
83
+ # Calling this method increases the internal reference count. When the
84
+ # data source is used for the first time (first {#use} call), the data
85
+ # source will be loaded ({#up} will be called).
86
+ #
87
+ # @return [void]
88
+ def use
89
+ up if @references == 0
90
+ @references += 1
91
+ end
92
+
93
+ # Marks the data source as unused by the caller.
94
+ #
95
+ # Calling this method decreases the internal reference count. When the
96
+ # reference count reaches zero, i.e. when the data source is not used any
97
+ # more, the data source will be unloaded ({#down} will be called).
98
+ #
99
+ # @return [void]
100
+ def unuse
101
+ @references -= 1
102
+ down if @references == 0
103
+ end
104
+
105
+ # Brings up the connection to the data. Depending on the way data is
106
+ # stored, this may not be necessary. This is the ideal place to connect to
107
+ # the database, for example.
108
+ #
109
+ # Subclasses may override this method, but are not required to do so; the
110
+ # default implementation simply does nothing.
111
+ #
112
+ # @return [void]
113
+ def up
114
+ end
115
+
116
+ # Brings down the connection to the data. This method should undo the
117
+ # effects of the {#up} method. For example, a database connection
118
+ # established in {#up} should be closed in this method.
119
+ #
120
+ # Subclasses may override this method, but are not required to do so; the
121
+ # default implementation simply does nothing.
122
+ #
123
+ # @return [void]
124
+ def down
125
+ end
126
+
127
+ # Creates the bare minimum essentials for this data source to work. This
128
+ # action will likely be destructive. This method should not create sample
129
+ # data such as a default home page, a default layout, etc. For example,
130
+ # when using a database, this is where you should create the necessary
131
+ # tables for the data source to function properly.
132
+ #
133
+ # @abstract
134
+ #
135
+ # @return [void]
136
+ def setup
137
+ not_implemented('setup')
138
+ end
139
+
140
+ # Updated the content stored in this site to a newer version. A newer
141
+ # version of a data source may store content in a different format, and
142
+ # this method will update the stored content to this newer format.
143
+ #
144
+ # Subclasses may override this method, but are not required to do so; the
145
+ # default implementation simply does nothing.
146
+ #
147
+ # @return [void]
148
+ def update
149
+ end
150
+
151
+ # Returns the list of items (represented by {Nanoc::Item}) in this site.
152
+ # The default implementation simply returns an empty array.
153
+ #
154
+ # Subclasses should not prepend `items_root` to the item's identifiers, as
155
+ # this will be done automatically.
156
+ #
157
+ # Subclasses may override this method, but are not required to do so; the
158
+ # default implementation simply does nothing.
159
+ #
160
+ # @return [Array<Nanoc::Item>] A list of items
161
+ def items
162
+ []
163
+ end
164
+
165
+ # Returns the list of layouts (represented by {Nanoc::Layout}) in this
166
+ # site. The default implementation simply returns an empty array.
167
+ #
168
+ # Subclasses should prepend `layout_root` to the layout's identifiers,
169
+ # since this is not done automatically.
170
+ #
171
+ # Subclasses may override this method, but are not required to do so; the
172
+ # default implementation simply does nothing.
173
+ #
174
+ # @return [Array<Nanoc::Layout>] A list of layouts
175
+ def layouts
176
+ []
177
+ end
178
+
179
+ # Creates a new item with the given content, attributes and identifier. No
180
+ # instance of {Nanoc::Item} will be created; this method creates the item
181
+ # in the data source so that it can be loaded and turned into a
182
+ # {Nanoc::Item} instance by the {#items} method.
183
+ #
184
+ # @abstract
185
+ #
186
+ # @param [String] content
187
+ #
188
+ # @param [Hash] attributes
189
+ #
190
+ # @param [String] identifier
191
+ #
192
+ # @param [Hash] params Extra parameters to give to the data source. This
193
+ # can be used to influence the way items are stored. For example,
194
+ # filesystem data sources could use this to pass the extension of the
195
+ # files that should be generated.
196
+ #
197
+ # @return [void]
198
+ def create_item(content, attributes, identifier, params={})
199
+ not_implemented('create_item')
200
+ end
201
+
202
+ # Creates a new layout with the given content, attributes and identifier.
203
+ # No instance of {Nanoc::Layout} will be created; this method creates the
204
+ # layout in the data source so that it can be loaded and turned into a
205
+ # {Nanoc::Layout} instance by the {#layouts} method.
206
+ #
207
+ # @abstract
208
+ #
209
+ # @param [String] content
210
+ #
211
+ # @param [Hash] attributes
212
+ #
213
+ # @param [String] identifier
214
+ #
215
+ # @param [Hash] params Extra parameters to give to the data source. This
216
+ # can be used to influence the way items are stored. For example,
217
+ # filesystem data sources could use this to pass the extension of the
218
+ # files that should be generated.
219
+ #
220
+ # @return [void]
221
+ def create_layout(content, attributes, identifier, params={})
222
+ not_implemented('create_layout')
223
+ end
224
+
225
+ private
226
+
227
+ def not_implemented(name)
228
+ raise NotImplementedError.new(
229
+ "#{self.class} does not implement ##{name}"
230
+ )
231
+ end
232
+
233
+ end
234
+ end
@@ -0,0 +1,301 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Represents a compileable item in a site. It has content and attributes, as
6
+ # well as an identifier (which starts and ends with a slash). It can also
7
+ # store the modification time to speed up compilation.
8
+ class Item
9
+
10
+ extend Nanoc::Memoization
11
+
12
+ # @return [Hash] This item's attributes
13
+ attr_accessor :attributes
14
+
15
+ # A string that uniquely identifies an item in a site.
16
+ #
17
+ # Identifiers start and end with a slash. They are comparable to paths on
18
+ # the filesystem, with the difference that file system paths usually do
19
+ # not have a trailing slash. The item hierarchy (parent and children of
20
+ # items) is determined by the item identifier.
21
+ #
22
+ # The root page (the home page) has the identifier “/”, which means
23
+ # that it is the ancestor of all other items.
24
+ #
25
+ # @return [String] This item's identifier
26
+ attr_accessor :identifier
27
+
28
+ # @return [Array<Nanoc::ItemRep>] This item’s list of item reps
29
+ attr_reader :reps
30
+
31
+ # @return [String] This item's raw, uncompiled content of this item (only
32
+ # available for textual items)
33
+ attr_reader :raw_content
34
+
35
+ # @return [String] The filename pointing to the file containing this
36
+ # item’s content (only available for binary items)
37
+ attr_reader :raw_filename
38
+
39
+ # @return [Nanoc::Item, nil] The parent item of this item. This can be
40
+ # nil even for non-root items.
41
+ attr_accessor :parent
42
+
43
+ # @return [Array<Nanoc::Item>] The child items of this item
44
+ attr_accessor :children
45
+
46
+ # Creates a new item with the given content or filename, attributes and
47
+ # identifier.
48
+ #
49
+ # @param [String] raw_content_or_raw_filename The uncompiled item content
50
+ # (if it is a textual item) or the path to the filename containing the
51
+ # content (if it is a binary item).
52
+ #
53
+ # @param [Hash] attributes A hash containing this item's attributes.
54
+ #
55
+ # @param [String] identifier This item's identifier.
56
+ #
57
+ # @param [Time, Hash] params Extra parameters. For backwards
58
+ # compatibility, this can be a Time instance indicating the time when
59
+ # this item was last modified (mtime).
60
+ #
61
+ # @option params [Time, nil] :mtime (nil) The time when this item was last
62
+ # modified. Deprecated; pass the modification time as the `:mtime`
63
+ # attribute instead.
64
+ #
65
+ # @option params [Symbol, nil] :binary (true) Whether or not this item is
66
+ # binary
67
+ def initialize(raw_content_or_raw_filename, attributes, identifier, params=nil)
68
+ # Parse params
69
+ params ||= {}
70
+ params = { :mtime => params } if params.is_a?(Time)
71
+ params[:binary] = false unless params.has_key?(:binary)
72
+
73
+ if raw_content_or_raw_filename.nil?
74
+ raise "attempted to create an item with no content/filename (identifier #{identifier})"
75
+ end
76
+
77
+ # Get type and raw content or raw filename
78
+ @is_binary = params[:binary]
79
+ if @is_binary
80
+ @raw_filename = raw_content_or_raw_filename
81
+ else
82
+ @raw_content = raw_content_or_raw_filename
83
+ end
84
+
85
+ # Get rest of params
86
+ @attributes = attributes.symbolize_keys
87
+ @identifier = identifier.cleaned_identifier.freeze
88
+
89
+ # Set mtime
90
+ @attributes.merge!(:mtime => params[:mtime]) if params[:mtime]
91
+
92
+ @parent = nil
93
+ @children = []
94
+
95
+ @reps = []
96
+ end
97
+
98
+ # Returns the rep with the given name.
99
+ #
100
+ # @param [Symbol] rep_name The name of the representation to return
101
+ #
102
+ # @return [Nanoc::ItemRep] The representation with the given name
103
+ def rep_named(rep_name)
104
+ @reps.find { |r| r.name == rep_name }
105
+ end
106
+
107
+ # Returns the compiled content from a given representation and a given
108
+ # snapshot. This is a convenience method that makes fetching compiled
109
+ # content easier.
110
+ #
111
+ # @option params [String] :rep (:default) The name of the representation
112
+ # from which the compiled content should be fetched. By default, the
113
+ # compiled content will be fetched from the default representation.
114
+ #
115
+ # @option params [String] :snapshot The name of the snapshot from which to
116
+ # fetch the compiled content. By default, the returned compiled content
117
+ # will be the content compiled right before the first layout call (if
118
+ # any).
119
+ #
120
+ # @return [String] The compiled content of the given rep (or the default
121
+ # rep if no rep is specified) at the given snapshot (or the default
122
+ # snapshot if no snapshot is specified)
123
+ #
124
+ # @see ItemRep#compiled_content
125
+ def compiled_content(params={})
126
+ # Get rep
127
+ rep_name = params[:rep] || :default
128
+ rep = reps.find { |r| r.name == rep_name }
129
+ if rep.nil?
130
+ raise Nanoc::Errors::Generic,
131
+ "No rep named #{rep_name.inspect} was found."
132
+ end
133
+
134
+ # Get rep's content
135
+ rep.compiled_content(params)
136
+ end
137
+
138
+ # Returns the path from a given representation. This is a convenience
139
+ # method that makes fetching the path of a rep easier.
140
+ #
141
+ # @option params [String] :rep (:default) The name of the representation
142
+ # from which the path should be fetched. By default, the path will be
143
+ # fetched from the default representation.
144
+ #
145
+ # @return [String] The path of the given rep ( or the default rep if no
146
+ # rep is specified)
147
+ def path(params={})
148
+ rep_name = params[:rep] || :default
149
+
150
+ # Get rep
151
+ rep = reps.find { |r| r.name == rep_name }
152
+ if rep.nil?
153
+ raise Nanoc::Errors::Generic,
154
+ "No rep named #{rep_name.inspect} was found."
155
+ end
156
+
157
+ # Get rep's path
158
+ rep.path
159
+ end
160
+
161
+ # Requests the attribute with the given key.
162
+ #
163
+ # @param [Symbol] key The name of the attribute to fetch
164
+ #
165
+ # @return [Object] The value of the requested attribute
166
+ def [](key)
167
+ Nanoc::NotificationCenter.post(:visit_started, self)
168
+ Nanoc::NotificationCenter.post(:visit_ended, self)
169
+
170
+ # Get captured content (hax)
171
+ # TODO [in nanoc 4.0] remove me
172
+ if key.to_s =~ /^content_for_(.*)$/
173
+ @@_content_for_warning_issued ||= false
174
+ @@_Nanoc_Helpers_Capturing_included ||= false
175
+
176
+ # Warn
177
+ unless @@_content_for_warning_issued
178
+ warn 'WARNING: Accessing captured content should happen using the #content_for method defined in the Capturing helper instead of using item[:content_for_something]. The latter way of accessing captured content will be removed in nanoc 4.0.'
179
+ @@_content_for_warning_issued = true
180
+ end
181
+
182
+ # Include capturing helper if necessary
183
+ unless @@_Nanoc_Helpers_Capturing_included
184
+ self.class.send(:include, ::Nanoc::Helpers::Capturing)
185
+ @@_Nanoc_Helpers_Capturing_included = true
186
+ end
187
+
188
+ # Get content
189
+ return content_for(self, $1.to_sym)
190
+ end
191
+
192
+ @attributes[key]
193
+ end
194
+
195
+ # Sets the attribute with the given key to the given value.
196
+ #
197
+ # @param [Symbol] key The name of the attribute to set
198
+ #
199
+ # @param [Object] value The value of the attribute to set
200
+ def []=(key, value)
201
+ @attributes[key] = value
202
+ end
203
+
204
+ # @return [Boolean] True if the item is binary; false if it is not
205
+ def binary?
206
+ !!@is_binary
207
+ end
208
+
209
+ # Returns the type of this object. Will always return `:item`, because
210
+ # this is an item. For layouts, this method returns `:layout`.
211
+ #
212
+ # @api private
213
+ #
214
+ # @return [Symbol] :item
215
+ def type
216
+ :item
217
+ end
218
+
219
+ # Returns an object that can be used for uniquely identifying objects.
220
+ #
221
+ # @api private
222
+ #
223
+ # @return [Object] An unique reference to this object
224
+ def reference
225
+ [ type, self.identifier ]
226
+ end
227
+
228
+ # Prevents all further modifications to its attributes.
229
+ #
230
+ # @return [void]
231
+ def freeze
232
+ attributes.freeze_recursively
233
+ children.freeze
234
+ identifier.freeze
235
+ raw_filename.freeze if raw_filename
236
+ raw_content.freeze if raw_content
237
+ end
238
+
239
+ def inspect
240
+ "<#{self.class} identifier=#{self.identifier} binary?=#{self.binary?}>"
241
+ end
242
+
243
+ # @return [String] The checksum for this object. If its contents change,
244
+ # the checksum will change as well.
245
+ def checksum
246
+ content_checksum = if binary?
247
+ if File.exist?(raw_filename)
248
+ Pathname.new(raw_filename).checksum
249
+ else
250
+ ''.checksum
251
+ end
252
+ else
253
+ @raw_content.checksum
254
+ end
255
+
256
+ attributes = @attributes.dup
257
+ attributes.delete(:file)
258
+ attributes_checksum = attributes.checksum
259
+
260
+ content_checksum + ',' + attributes_checksum
261
+ end
262
+ memoize :checksum
263
+
264
+ def hash
265
+ self.class.hash ^ self.identifier.hash
266
+ end
267
+
268
+ def eql?(other)
269
+ self.class == other.class && self.identifier == other.identifier
270
+ end
271
+
272
+ def ==(other)
273
+ self.eql?(other)
274
+ end
275
+
276
+ def marshal_dump
277
+ [
278
+ @is_binary,
279
+ @raw_filename,
280
+ @raw_content,
281
+ @attributes,
282
+ @identifier
283
+ ]
284
+ end
285
+
286
+ def marshal_load(source)
287
+ @is_binary,
288
+ @raw_filename,
289
+ @raw_content,
290
+ @attributes,
291
+ @identifier = *source
292
+ end
293
+
294
+ # @deprecated Access the modification time using `item[:mtime]` instead.
295
+ def mtime
296
+ self[:mtime]
297
+ end
298
+
299
+ end
300
+
301
+ end