nanoc 2.0.4 → 2.1

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 (99) hide show
  1. data/ChangeLog +31 -1
  2. data/LICENSE +1 -1
  3. data/README +63 -3
  4. data/Rakefile +59 -12
  5. data/bin/nanoc +7 -199
  6. data/lib/nanoc.rb +83 -12
  7. data/lib/nanoc/base/asset.rb +113 -0
  8. data/lib/nanoc/base/asset_defaults.rb +21 -0
  9. data/lib/nanoc/base/asset_rep.rb +277 -0
  10. data/lib/nanoc/base/binary_filter.rb +44 -0
  11. data/lib/nanoc/base/code.rb +41 -0
  12. data/lib/nanoc/base/compiler.rb +46 -34
  13. data/lib/nanoc/base/core_ext/hash.rb +51 -7
  14. data/lib/nanoc/base/core_ext/string.rb +8 -0
  15. data/lib/nanoc/base/data_source.rb +253 -20
  16. data/lib/nanoc/base/defaults.rb +30 -0
  17. data/lib/nanoc/base/enhancements.rb +9 -84
  18. data/lib/nanoc/base/filter.rb +109 -6
  19. data/lib/nanoc/base/layout.rb +91 -0
  20. data/lib/nanoc/base/notification_center.rb +66 -0
  21. data/lib/nanoc/base/page.rb +94 -126
  22. data/lib/nanoc/base/page_defaults.rb +20 -0
  23. data/lib/nanoc/base/page_rep.rb +318 -0
  24. data/lib/nanoc/base/plugin.rb +57 -9
  25. data/lib/nanoc/base/proxies/asset_proxy.rb +29 -0
  26. data/lib/nanoc/base/proxies/asset_rep_proxy.rb +26 -0
  27. data/lib/nanoc/base/proxies/layout_proxy.rb +25 -0
  28. data/lib/nanoc/base/proxies/page_proxy.rb +35 -0
  29. data/lib/nanoc/base/proxies/page_rep_proxy.rb +28 -0
  30. data/lib/nanoc/base/proxy.rb +37 -0
  31. data/lib/nanoc/base/router.rb +72 -0
  32. data/lib/nanoc/base/site.rb +219 -88
  33. data/lib/nanoc/base/template.rb +64 -0
  34. data/lib/nanoc/binary_filters/image_science_thumbnail.rb +28 -0
  35. data/lib/nanoc/cli.rb +1 -0
  36. data/lib/nanoc/cli/base.rb +219 -0
  37. data/lib/nanoc/cli/cli.rb +16 -0
  38. data/lib/nanoc/cli/command.rb +105 -0
  39. data/lib/nanoc/cli/commands/autocompile.rb +80 -0
  40. data/lib/nanoc/cli/commands/compile.rb +273 -0
  41. data/lib/nanoc/cli/commands/create_layout.rb +85 -0
  42. data/lib/nanoc/cli/commands/create_page.rb +85 -0
  43. data/lib/nanoc/cli/commands/create_site.rb +327 -0
  44. data/lib/nanoc/cli/commands/create_template.rb +76 -0
  45. data/lib/nanoc/cli/commands/help.rb +69 -0
  46. data/lib/nanoc/cli/commands/info.rb +114 -0
  47. data/lib/nanoc/cli/commands/switch.rb +141 -0
  48. data/lib/nanoc/cli/commands/update.rb +91 -0
  49. data/lib/nanoc/cli/ext.rb +37 -0
  50. data/lib/nanoc/cli/logger.rb +66 -0
  51. data/lib/nanoc/cli/option_parser.rb +168 -0
  52. data/lib/nanoc/data_sources/filesystem.rb +645 -224
  53. data/lib/nanoc/data_sources/filesystem_combined.rb +495 -0
  54. data/lib/nanoc/extra/auto_compiler.rb +265 -0
  55. data/lib/nanoc/extra/context.rb +22 -0
  56. data/lib/nanoc/extra/core_ext/hash.rb +54 -0
  57. data/lib/nanoc/extra/core_ext/time.rb +13 -0
  58. data/lib/nanoc/extra/file_proxy.rb +29 -0
  59. data/lib/nanoc/extra/vcs.rb +48 -0
  60. data/lib/nanoc/extra/vcses/bazaar.rb +21 -0
  61. data/lib/nanoc/extra/vcses/dummy.rb +20 -0
  62. data/lib/nanoc/extra/vcses/git.rb +21 -0
  63. data/lib/nanoc/extra/vcses/mercurial.rb +21 -0
  64. data/lib/nanoc/extra/vcses/subversion.rb +21 -0
  65. data/lib/nanoc/filters/bluecloth.rb +13 -0
  66. data/lib/nanoc/filters/erb.rb +6 -22
  67. data/lib/nanoc/filters/erubis.rb +14 -0
  68. data/lib/nanoc/filters/haml.rb +7 -23
  69. data/lib/nanoc/filters/markaby.rb +5 -5
  70. data/lib/nanoc/filters/maruku.rb +14 -0
  71. data/lib/nanoc/filters/old.rb +19 -0
  72. data/lib/nanoc/filters/rdiscount.rb +13 -0
  73. data/lib/nanoc/filters/rdoc.rb +5 -4
  74. data/lib/nanoc/filters/redcloth.rb +14 -0
  75. data/lib/nanoc/filters/rubypants.rb +14 -0
  76. data/lib/nanoc/filters/sass.rb +13 -0
  77. data/lib/nanoc/helpers/blogging.rb +170 -0
  78. data/lib/nanoc/helpers/capturing.rb +59 -0
  79. data/lib/nanoc/helpers/html_escape.rb +23 -0
  80. data/lib/nanoc/helpers/link_to.rb +69 -0
  81. data/lib/nanoc/helpers/render.rb +47 -0
  82. data/lib/nanoc/helpers/tagging.rb +52 -0
  83. data/lib/nanoc/helpers/xml_sitemap.rb +58 -0
  84. data/lib/nanoc/routers/default.rb +54 -0
  85. data/lib/nanoc/routers/no_dirs.rb +66 -0
  86. data/lib/nanoc/routers/versioned.rb +79 -0
  87. metadata +112 -22
  88. data/lib/nanoc/base/auto_compiler.rb +0 -132
  89. data/lib/nanoc/base/layout_processor.rb +0 -33
  90. data/lib/nanoc/base/page_proxy.rb +0 -31
  91. data/lib/nanoc/base/plugin_manager.rb +0 -33
  92. data/lib/nanoc/data_sources/database.rb +0 -259
  93. data/lib/nanoc/data_sources/trivial.rb +0 -145
  94. data/lib/nanoc/filters/markdown.rb +0 -13
  95. data/lib/nanoc/filters/smartypants.rb +0 -13
  96. data/lib/nanoc/filters/textile.rb +0 -13
  97. data/lib/nanoc/layout_processors/erb.rb +0 -35
  98. data/lib/nanoc/layout_processors/haml.rb +0 -38
  99. data/lib/nanoc/layout_processors/markaby.rb +0 -16
@@ -0,0 +1,20 @@
1
+ module Nanoc::Extra::VCSes
2
+
3
+ class Dummy < Nanoc::Extra::VCS
4
+
5
+ identifiers :dummy
6
+
7
+ def add(filename)
8
+ end
9
+
10
+ def remove(filename)
11
+ FileUtils.rm_rf(filename)
12
+ end
13
+
14
+ def move(src, dst)
15
+ FileUtils.move(src, dst)
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,21 @@
1
+ module Nanoc::Extra::VCSes
2
+
3
+ class Git < Nanoc::Extra::VCS
4
+
5
+ identifiers :git
6
+
7
+ def add(filename)
8
+ system('git', 'add', filename)
9
+ end
10
+
11
+ def remove(filename)
12
+ system('git', 'rm', filename)
13
+ end
14
+
15
+ def move(src, dst)
16
+ system('git', 'mv', src, dst)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module Nanoc::Extra::VCSes
2
+
3
+ class Mercurial < Nanoc::Extra::VCS
4
+
5
+ identifiers :mercurial, :hg
6
+
7
+ def add(filename)
8
+ system('hg', 'add', filename)
9
+ end
10
+
11
+ def remove(filename)
12
+ system('hg', 'rm', filename)
13
+ end
14
+
15
+ def move(src, dst)
16
+ system('hg', 'mv', src, dst)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module Nanoc::Extra::VCSes
2
+
3
+ class Subversion < Nanoc::Extra::VCS
4
+
5
+ identifiers :subversion, :svn
6
+
7
+ def add(filename)
8
+ system('svn', 'add', filename)
9
+ end
10
+
11
+ def remove(filename)
12
+ system('svn', 'rm', filename)
13
+ end
14
+
15
+ def move(src, dst)
16
+ system('svn', 'mv', src, dst)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,13 @@
1
+ module Nanoc::Filters
2
+ class BlueCloth < Nanoc::Filter
3
+
4
+ identifiers :bluecloth
5
+
6
+ def run(content)
7
+ require 'bluecloth'
8
+
9
+ ::BlueCloth.new(content).to_html
10
+ end
11
+
12
+ end
13
+ end
@@ -1,34 +1,18 @@
1
- module Nanoc::Filter::ERB
1
+ module Nanoc::Filters
2
+ class ERB < Nanoc::Filter
2
3
 
3
- class Context
4
-
5
- def initialize(hash)
6
- hash.each_pair do |key, value|
7
- instance_variable_set('@' + key.to_s, value)
8
- end
9
- end
10
-
11
- def get_binding
12
- binding
13
- end
14
-
15
- end
16
-
17
- class ERBFilter < Nanoc::Filter
18
-
19
- identifiers :erb, :eruby
4
+ identifiers :erb
5
+ extensions '.erb', '.rhtml'
20
6
 
21
7
  def run(content)
22
- nanoc_require 'erb'
8
+ require 'erb'
23
9
 
24
10
  # Create context
25
- assigns = { :page => @page, :pages => @pages, :config => @config, :site => @site }
26
- context = Context.new(assigns)
11
+ context = ::Nanoc::Extra::Context.new(assigns)
27
12
 
28
13
  # Get result
29
14
  ::ERB.new(content).result(context.get_binding)
30
15
  end
31
16
 
32
17
  end
33
-
34
18
  end
@@ -0,0 +1,14 @@
1
+ module Nanoc::Filters
2
+ class Erubis < Nanoc::Filter
3
+
4
+ identifiers :erubis
5
+
6
+ def run(content)
7
+ require 'erubis'
8
+
9
+ # Get result
10
+ ::Erubis::Eruby.new(content).evaluate(assigns)
11
+ end
12
+
13
+ end
14
+ end
@@ -1,37 +1,21 @@
1
- module Nanoc::Filter::Haml
2
-
3
- class Context
4
-
5
- def initialize(hash)
6
- hash.each_pair do |key, value|
7
- instance_variable_set('@' + key.to_s, value)
8
- end
9
- end
10
-
11
- def get_binding
12
- binding
13
- end
14
-
15
- end
16
-
17
- class HamlFilter < Nanoc::Filter
1
+ module Nanoc::Filters
2
+ class Haml < Nanoc::Filter
18
3
 
19
4
  identifiers :haml
5
+ extensions '.haml'
20
6
 
21
7
  def run(content)
22
- nanoc_require 'haml'
8
+ require 'haml'
23
9
 
24
10
  # Get options
25
- options = @page.haml_options || {}
11
+ options = @page.attribute_named(:haml_options) || {}
26
12
 
27
- # Get assigns/locals
28
- assigns = { :page => @page, :pages => @pages, :config => @config, :site => @site }
29
- context = Context.new(assigns)
13
+ # Create context
14
+ context = ::Nanoc::Extra::Context.new(assigns)
30
15
 
31
16
  # Get result
32
17
  ::Haml::Engine.new(content, options).render(context, assigns)
33
18
  end
34
19
 
35
20
  end
36
-
37
21
  end
@@ -1,13 +1,13 @@
1
- module Nanoc::Filter::Markaby
2
- class MarkabyFilter < Nanoc::Filter
1
+ module Nanoc::Filters
2
+ class Markaby < Nanoc::Filter
3
3
 
4
4
  identifiers :markaby
5
+ extensions '.mab'
5
6
 
6
7
  def run(content)
7
- nanoc_require 'markaby'
8
-
9
- assigns = { :page => @page, :pages => @pages, :config => @config, :site => @site }
8
+ require 'markaby'
10
9
 
10
+ # Get result
11
11
  ::Markaby::Builder.new(assigns).instance_eval(content).to_s
12
12
  end
13
13
 
@@ -0,0 +1,14 @@
1
+ module Nanoc::Filters
2
+ class Maruku < Nanoc::Filter
3
+
4
+ identifiers :maruku
5
+
6
+ def run(content)
7
+ require 'maruku'
8
+
9
+ # Get result
10
+ ::Maruku.new(content).to_html
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module Nanoc::Filters
2
+ class Old < Nanoc::Filter
3
+
4
+ identifiers :eruby, :markdown, :smartypants, :textile
5
+
6
+ def run(content)
7
+ raise Nanoc::Error.new(
8
+ "The 'eruby', markdown', 'smartypants' and 'textile' filters no " +
9
+ "longer exist. Instead, use the following filters:\n" +
10
+ "\n" +
11
+ "* for Markdown: bluecloth, rdiscount, redcloth\n" +
12
+ "* for Textile: redcloth\n" +
13
+ "* for embedded Ruby: erb, erubis\n" +
14
+ "* for Smartypants: rubypants"
15
+ )
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Nanoc::Filters
2
+ class RDiscount < Nanoc::Filter
3
+
4
+ identifiers :rdiscount
5
+
6
+ def run(content)
7
+ require 'rdiscount'
8
+
9
+ ::RDiscount.new(content).to_html
10
+ end
11
+
12
+ end
13
+ end
@@ -1,12 +1,13 @@
1
- module Nanoc::Filter::RDoc
2
- class RDocFilter < Nanoc::Filter
1
+ module Nanoc::Filters
2
+ class RDoc < Nanoc::Filter
3
3
 
4
4
  identifiers :rdoc
5
5
 
6
6
  def run(content)
7
- nanoc_require 'rdoc/markup/simple_markup'
8
- nanoc_require 'rdoc/markup/simple_markup/to_html'
7
+ require 'rdoc/markup/simple_markup'
8
+ require 'rdoc/markup/simple_markup/to_html'
9
9
 
10
+ # Get result
10
11
  ::SM::SimpleMarkup.new.convert(content, SM::ToHtml.new)
11
12
  end
12
13
 
@@ -0,0 +1,14 @@
1
+ module Nanoc::Filters
2
+ class RedCloth < Nanoc::Filter
3
+
4
+ identifiers :redcloth
5
+
6
+ def run(content)
7
+ require 'redcloth'
8
+
9
+ # Get result
10
+ ::RedCloth.new(content).to_html
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Nanoc::Filters
2
+ class SmartyPants < Nanoc::Filter
3
+
4
+ identifiers :rubypants
5
+
6
+ def run(content)
7
+ require 'rubypants'
8
+
9
+ # Get result
10
+ ::RubyPants.new(content).to_html
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Nanoc::Filters
2
+ class Sass < Nanoc::Filter
3
+
4
+ identifiers :sass
5
+
6
+ def run(content)
7
+ require 'sass'
8
+
9
+ ::Sass::Engine.new(content).render
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,170 @@
1
+ module Nanoc::Helpers
2
+
3
+ # Nanoc::Helpers::Blogging provides some functionality for building blogs,
4
+ # such as finding articles and constructing feeds.
5
+ #
6
+ # This helper has a few requirements. First, all blog articles should have
7
+ # the following attributes:
8
+ #
9
+ # * 'kind', set to 'article'.
10
+ #
11
+ # * 'created_at', set to the creation timestamp.
12
+ #
13
+ # Some functions in this blogging helper, such as the +atom_feed+ function,
14
+ # require additional attributes to be set; these attributes are described in
15
+ # the documentation for these functions.
16
+ #
17
+ # The two main functions are sorted_articles and atom_feed.
18
+ module Blogging
19
+
20
+ # Returns the list of articles, sorted by descending creation date (so
21
+ # newer articles appear first).
22
+ def sorted_articles
23
+ @pages.select do |page|
24
+ page.kind == 'article'
25
+ end.sort do |x,y|
26
+ y.created_at <=> x.created_at
27
+ end
28
+ end
29
+
30
+ # Returns a string representing the atom feed containing recent articles,
31
+ # sorted by descending creation date. +params+ is a hash where the
32
+ # following keys can be set:
33
+ #
34
+ # +limit+:: The maximum number of articles to show. Defaults to 5.
35
+ #
36
+ # The following attributes must be set on blog articles:
37
+ #
38
+ # * 'title', containing the title of the blog post.
39
+ #
40
+ # * all other attributes mentioned above.
41
+ #
42
+ # The following attributes can optionally be set on blog articles to
43
+ # change the behaviour of the Atom feed:
44
+ #
45
+ # * 'excerpt', containing an excerpt of the article, usually only a few
46
+ # lines long.
47
+ #
48
+ # * 'custom_path_in_feed', containing the path that will be used instead
49
+ # of the normal path in the feed. This can be useful when including
50
+ # non-outputted pages in a feed; such pages could have their custom feed
51
+ # path set to the blog path instead, for example.
52
+ #
53
+ # The feed will also include dates on which the articles were updated.
54
+ # These are generated automatically; the way this happens depends on the
55
+ # used data source (the filesystem data source checks the file mtimes, for
56
+ # instance).
57
+ #
58
+ # The feed page will need to have the following attributes:
59
+ #
60
+ # * 'base_url', containing the URL to the site, without trailing slash.
61
+ # For example, if the site is at "http://example.com/", the base_url
62
+ # would be "http://example.com". It is probably a good idea to define
63
+ # this in the page defaults, i.e. the 'meta.yaml' file (at least if the
64
+ # filesystem data source is being used, which is probably the case).
65
+ #
66
+ # * 'title', containing the title of the feed, which is usually also the
67
+ # title of the blog.
68
+ #
69
+ # * 'author_name', containing the name of the page's author. This will
70
+ # likely be a global attribute, unless the site is managed by several
71
+ # people/
72
+ #
73
+ # * 'author_uri', containing the URI for the page's author, such as the
74
+ # author's web site URL. This will also likely be a global attribute.
75
+ #
76
+ # The feed page can have the following optional attributes:
77
+ #
78
+ # * 'feed_url', containing the custom URL of the feed. This can be useful
79
+ # when the private feed URL shouldn't be exposed; for example, when
80
+ # using FeedBurner this would be set to the public FeedBurner URL.
81
+ #
82
+ # To construct a feed, create a blank page with no layout, only the 'erb'
83
+ # (or 'erubis') filter, and an 'xml' extension. It may also be useful to
84
+ # set 'is_hidden' to true, so that helpers such as the sitemap helper will
85
+ # ignore the page. The content of the feed page should be:
86
+ #
87
+ # <%= atom_feed %>
88
+ def atom_feed(params={})
89
+ require 'builder'
90
+
91
+ # Extract parameters
92
+ limit = params[:limit] || 5
93
+
94
+ # Get most recent article
95
+ last_article = sorted_articles.first
96
+
97
+ # Create builder
98
+ buffer = ''
99
+ xml = Builder::XmlMarkup.new(:target => buffer, :indent => 2)
100
+
101
+ # Build feed
102
+ xml.instruct!
103
+ xml.feed(:xmlns => 'http://www.w3.org/2005/Atom') do
104
+ # Add primary attributes
105
+ xml.id @page.base_url + '/'
106
+ xml.title @page.title
107
+
108
+ # Add date
109
+ xml.updated last_article.created_at.to_iso8601_time
110
+
111
+ # Add links
112
+ xml.link(:rel => 'alternate', :href => @page.base_url)
113
+ xml.link(:rel => 'self', :href => feed_url)
114
+
115
+ # Add author information
116
+ xml.author do
117
+ xml.name @page.author_name
118
+ xml.uri @page.author_uri
119
+ end
120
+
121
+ # Add articles
122
+ sorted_articles.first(limit).each do |a|
123
+ xml.entry do
124
+ # Add primary attributes
125
+ xml.id atom_tag_for(a)
126
+ xml.title a.title, :type => 'html'
127
+
128
+ # Add dates
129
+ xml.published a.created_at.to_iso8601_time
130
+ xml.updated a.mtime.to_iso8601_time
131
+
132
+ # Add link
133
+ xml.link(:rel => 'alternate', :href => url_for(a))
134
+
135
+ # Add content
136
+ xml.content a.content, :type => 'html'
137
+ xml.summary a.excerpt, :type => 'html' unless a.excerpt.nil?
138
+ end
139
+ end
140
+ end
141
+
142
+ buffer
143
+ end
144
+
145
+ # Returns the URL for the given page. It will return the URL containing
146
+ # the custom path in the feed if possible, otherwise the normal path.
147
+ def url_for(page)
148
+ @page.base_url + (page.custom_path_in_feed || page.path)
149
+ end
150
+
151
+ # Returns the URL of the feed. It will return the custom feed URL if set,
152
+ # or otherwise the normal feed URL.
153
+ def feed_url
154
+ @page[:feed_url] || @page.base_url + @page.path
155
+ end
156
+
157
+ # Returns an URI containing an unique ID for the given page. This will be
158
+ # used in the Atom feed to uniquely identify articles. These IDs are
159
+ # created using a procedure suggested by Mark Pilgrim in this blog post:
160
+ # http://diveintomark.org/archives/2004/05/28/howto-atom-id.
161
+ def atom_tag_for(page)
162
+ hostname = @page.base_url.sub(/.*:\/\/(.+?)\/?$/, '\1')
163
+ formatted_date = page.created_at.to_iso8601_date
164
+
165
+ 'tag:' + hostname + ',' + formatted_date + ':' + page.path
166
+ end
167
+
168
+ end
169
+
170
+ end