nanoc 2.1.6 → 2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/ChangeLog +3 -221
  2. data/Rakefile +9 -51
  3. data/bin/nanoc +5 -2
  4. data/lib/nanoc.rb +9 -31
  5. data/lib/nanoc/base.rb +26 -0
  6. data/lib/nanoc/base/core_ext.rb +2 -0
  7. data/lib/nanoc/base/filter.rb +11 -41
  8. data/lib/nanoc/base/layout.rb +1 -5
  9. data/lib/nanoc/base/page_rep.rb +1 -1
  10. data/lib/nanoc/base/proxies.rb +5 -0
  11. data/lib/nanoc/base/site.rb +4 -2
  12. data/lib/nanoc/binary_filters.rb +1 -0
  13. data/lib/nanoc/cli.rb +9 -1
  14. data/lib/nanoc/cli/base.rb +41 -129
  15. data/lib/nanoc/cli/commands.rb +10 -0
  16. data/lib/nanoc/cli/commands/autocompile.rb +1 -1
  17. data/lib/nanoc/cli/commands/compile.rb +51 -13
  18. data/lib/nanoc/cli/commands/create_layout.rb +1 -1
  19. data/lib/nanoc/cli/commands/create_page.rb +1 -1
  20. data/lib/nanoc/cli/commands/create_site.rb +1 -1
  21. data/lib/nanoc/cli/commands/create_template.rb +1 -1
  22. data/lib/nanoc/cli/commands/help.rb +1 -1
  23. data/lib/nanoc/cli/commands/info.rb +1 -1
  24. data/lib/nanoc/cli/commands/switch.rb +1 -1
  25. data/lib/nanoc/cli/commands/update.rb +1 -1
  26. data/lib/nanoc/cli/logger.rb +13 -7
  27. data/lib/nanoc/data_sources.rb +2 -0
  28. data/lib/nanoc/data_sources/filesystem.rb +3 -38
  29. data/lib/nanoc/extra.rb +6 -0
  30. data/lib/nanoc/extra/core_ext.rb +2 -0
  31. data/lib/nanoc/extra/vcses.rb +5 -0
  32. data/lib/nanoc/filters.rb +14 -0
  33. data/lib/nanoc/filters/erb.rb +3 -2
  34. data/lib/nanoc/filters/haml.rb +1 -1
  35. data/lib/nanoc/filters/markaby.rb +0 -1
  36. data/lib/nanoc/filters/rainpress.rb +13 -0
  37. data/lib/nanoc/filters/relativize_paths.rb +25 -0
  38. data/lib/nanoc/filters/sass.rb +1 -0
  39. data/lib/nanoc/helpers.rb +9 -0
  40. data/lib/nanoc/helpers/blogging.rb +55 -12
  41. data/lib/nanoc/helpers/filtering.rb +54 -0
  42. data/lib/nanoc/helpers/link_to.rb +40 -0
  43. data/lib/nanoc/helpers/text.rb +38 -0
  44. data/lib/nanoc/helpers/xml_sitemap.rb +3 -2
  45. data/lib/nanoc/routers.rb +3 -0
  46. data/vendor/cri/ChangeLog +0 -0
  47. data/vendor/cri/LICENSE +19 -0
  48. data/vendor/cri/NEWS +0 -0
  49. data/vendor/cri/README +4 -0
  50. data/vendor/cri/Rakefile +25 -0
  51. data/vendor/cri/lib/cri.rb +12 -0
  52. data/vendor/cri/lib/cri/base.rb +153 -0
  53. data/{lib/nanoc/cli → vendor/cri/lib/cri}/command.rb +5 -6
  54. data/vendor/cri/lib/cri/core_ext.rb +8 -0
  55. data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
  56. data/{lib/nanoc/cli → vendor/cri/lib/cri}/option_parser.rb +35 -17
  57. data/vendor/cri/test/test_base.rb +6 -0
  58. data/vendor/cri/test/test_command.rb +6 -0
  59. data/vendor/cri/test/test_core_ext.rb +21 -0
  60. data/vendor/cri/test/test_option_parser.rb +279 -0
  61. data/vendor/mime-types/lib/mime/types.rb +1558 -0
  62. metadata +45 -9
  63. data/lib/nanoc/base/enhancements.rb +0 -14
  64. data/lib/nanoc/cli/cli.rb +0 -16
  65. data/lib/nanoc/cli/ext.rb +0 -37
@@ -7,21 +7,27 @@ module Nanoc::CLI
7
7
  class Logger
8
8
 
9
9
  ACTION_COLORS = {
10
- :create => "\e[1m" + "\e[32m", # bold + green
11
- :update => "\e[1m" + "\e[33m", # bold + yellow
12
- :identical => "\e[1m", # bold
13
- :skip => "\e[1m" # bold
10
+ :create => "\e[1m" + "\e[32m", # bold + green
11
+ :update => "\e[1m" + "\e[33m", # bold + yellow
12
+ :identical => "\e[1m", # bold
13
+ :skip => "\e[1m", # bold
14
+ :'not written' => "\e[1m" # bold
14
15
  }
15
16
 
16
17
  include Singleton
17
18
 
18
- # The log leve, which can be :high, :low or :off (which will log all
19
+ # The log level, which can be :high, :low or :off (which will log all
19
20
  # messages, only high-priority messages, or no messages at all,
20
21
  # respectively).
21
22
  attr_accessor :level
22
23
 
24
+ # Whether to use color in log messages or not
25
+ attr_accessor :color
26
+ alias_method :color?, :color
27
+
23
28
  def initialize # :nodoc:
24
29
  @level = :high
30
+ @color = true
25
31
  end
26
32
 
27
33
  # Logs a file-related action.
@@ -36,9 +42,9 @@ module Nanoc::CLI
36
42
  log(
37
43
  level,
38
44
  '%s%12s%s %s%s' % [
39
- ACTION_COLORS[action.to_sym],
45
+ color? ? ACTION_COLORS[action.to_sym] : '',
40
46
  action,
41
- "\e[0m",
47
+ color? ? "\e[0m" : '',
42
48
  duration.nil? ? '' : "[%2.2fs] " % [ duration ],
43
49
  path
44
50
  ]
@@ -0,0 +1,2 @@
1
+ require 'nanoc/data_sources/filesystem'
2
+ require 'nanoc/data_sources/filesystem_combined'
@@ -120,7 +120,6 @@ module Nanoc::DataSources
120
120
  def update # :nodoc:
121
121
  update_page_defaults
122
122
  update_pages
123
- update_layouts
124
123
  update_templates
125
124
  end
126
125
 
@@ -368,8 +367,9 @@ module Nanoc::DataSources
368
367
  if is_old_school
369
368
  # Warn about deprecation
370
369
  warn(
371
- 'nanoc 2.1 changes the way layouts are stored. Future versions will not support these outdated sites. To update your site, issue \'nanoc update\'.',
372
- 'DEPRECATION WARNING'
370
+ 'DEPRECATION WARNING: nanoc 2.1 changes the way layouts are ' +
371
+ 'stored. Future versions will not support these outdated sites. ' +
372
+ 'To update your site, issue \'nanoc update\'.'
373
373
  )
374
374
 
375
375
  Dir[File.join('layouts', '*')].reject { |f| f =~ /~$/ }.map do |filename|
@@ -679,41 +679,6 @@ module Nanoc::DataSources
679
679
  end
680
680
  end
681
681
 
682
- # Updates outdated layouts.
683
- def update_layouts
684
- # layouts/abc.ext -> layouts/abc/abc.{html,yaml}
685
- Dir[File.join('layouts', '*')].select { |f| File.file?(f) }.each do |filename|
686
- # Get filter class
687
- filter_class = Nanoc::Filter.with_extension(File.extname(filename))
688
-
689
- # Get data
690
- content = File.read(filename)
691
- attributes = { :filter => filter_class.identifier.to_s }
692
- path = File.basename(filename, File.extname(filename))
693
-
694
- # Get layout
695
- tmp_layout = Nanoc::Layout.new(content, attributes, path)
696
-
697
- # Get filenames
698
- last_component = tmp_layout.path.split('/')[-1]
699
- dir_path = 'layouts' + tmp_layout.path
700
- meta_filename = dir_path + last_component + '.yaml'
701
- content_filename = dir_path + last_component + File.extname(filename)
702
-
703
- # Create new files
704
- FileUtils.mkdir_p(dir_path)
705
- File.open(meta_filename, 'w') { |io| io.write(tmp_layout.attributes.to_split_yaml) }
706
- File.open(content_filename, 'w') { |io| io.write(tmp_layout.content) }
707
-
708
- # Add
709
- vcs.add(meta_filename)
710
- vcs.add(content_filename)
711
-
712
- # Delete old files
713
- vcs.remove(filename)
714
- end
715
- end
716
-
717
682
  # Updates outdated templates (both content and meta file names).
718
683
  def update_templates
719
684
  # Update content files
@@ -0,0 +1,6 @@
1
+ require 'nanoc/extra/auto_compiler'
2
+ require 'nanoc/extra/context'
3
+ require 'nanoc/extra/core_ext'
4
+ require 'nanoc/extra/file_proxy'
5
+ require 'nanoc/extra/vcs'
6
+ require 'nanoc/extra/vcses'
@@ -0,0 +1,2 @@
1
+ require 'nanoc/extra/core_ext/hash'
2
+ require 'nanoc/extra/core_ext/time'
@@ -0,0 +1,5 @@
1
+ require 'nanoc/extra/vcses/bazaar'
2
+ require 'nanoc/extra/vcses/dummy'
3
+ require 'nanoc/extra/vcses/git'
4
+ require 'nanoc/extra/vcses/mercurial'
5
+ require 'nanoc/extra/vcses/subversion'
@@ -0,0 +1,14 @@
1
+ require 'nanoc/filters/bluecloth'
2
+ require 'nanoc/filters/erb'
3
+ require 'nanoc/filters/erubis'
4
+ require 'nanoc/filters/haml'
5
+ require 'nanoc/filters/markaby'
6
+ require 'nanoc/filters/maruku'
7
+ require 'nanoc/filters/old'
8
+ require 'nanoc/filters/rainpress'
9
+ require 'nanoc/filters/rdiscount'
10
+ require 'nanoc/filters/rdoc'
11
+ require 'nanoc/filters/redcloth'
12
+ require 'nanoc/filters/relativize_paths'
13
+ require 'nanoc/filters/rubypants'
14
+ require 'nanoc/filters/sass'
@@ -2,7 +2,6 @@ module Nanoc::Filters
2
2
  class ERB < Nanoc::Filter
3
3
 
4
4
  identifiers :erb
5
- extensions '.erb', '.rhtml'
6
5
 
7
6
  def run(content)
8
7
  require 'erb'
@@ -11,7 +10,9 @@ module Nanoc::Filters
11
10
  context = ::Nanoc::Extra::Context.new(assigns)
12
11
 
13
12
  # Get result
14
- ::ERB.new(content).result(context.get_binding)
13
+ erb = ::ERB.new(content)
14
+ erb.filename = filename
15
+ erb.result(context.get_binding)
15
16
  end
16
17
 
17
18
  end
@@ -2,13 +2,13 @@ module Nanoc::Filters
2
2
  class Haml < Nanoc::Filter
3
3
 
4
4
  identifiers :haml
5
- extensions '.haml'
6
5
 
7
6
  def run(content)
8
7
  require 'haml'
9
8
 
10
9
  # Get options
11
10
  options = @obj_rep.attribute_named(:haml_options) || {}
11
+ options[:filename] = filename
12
12
 
13
13
  # Create context
14
14
  context = ::Nanoc::Extra::Context.new(assigns)
@@ -2,7 +2,6 @@ module Nanoc::Filters
2
2
  class Markaby < Nanoc::Filter
3
3
 
4
4
  identifiers :markaby
5
- extensions '.mab'
6
5
 
7
6
  def run(content)
8
7
  require 'markaby'
@@ -0,0 +1,13 @@
1
+ module Nanoc::Filters
2
+ class Rainpress < Nanoc::Filter
3
+
4
+ identifier :rainpress
5
+
6
+ def run(content)
7
+ require 'rainpress'
8
+
9
+ ::Rainpress.compress(content)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module Nanoc::Filters
2
+ class RelativizePaths < Nanoc::Filter
3
+
4
+ identifier :relativize_paths
5
+
6
+ require 'nanoc/helpers/link_to'
7
+ include Nanoc::Helpers::LinkTo
8
+
9
+ def run(content, params={})
10
+ type = params[:type] || :html
11
+
12
+ case type
13
+ when :html
14
+ content.gsub(/(src|href)=(['"]?)(\/.+?)\2([ >])/) do
15
+ $1 + '=' + $2 + relative_path_to($3) + $2 + $4
16
+ end
17
+ when :css
18
+ content.gsub(/url\((['"]?)(\/.+?)\1\)/) do
19
+ 'url(' + $1 + relative_path_to($2) + $1 + ')'
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -8,6 +8,7 @@ module Nanoc::Filters
8
8
 
9
9
  # Get options
10
10
  options = @obj_rep.attribute_named(:sass_options) || {}
11
+ options[:filename] = filename
11
12
 
12
13
  # Get result
13
14
  ::Sass::Engine.new(content, options).render
@@ -0,0 +1,9 @@
1
+ require 'nanoc/helpers/blogging'
2
+ require 'nanoc/helpers/capturing'
3
+ require 'nanoc/helpers/filtering'
4
+ require 'nanoc/helpers/html_escape'
5
+ require 'nanoc/helpers/link_to'
6
+ require 'nanoc/helpers/render'
7
+ require 'nanoc/helpers/tagging'
8
+ require 'nanoc/helpers/text'
9
+ require 'nanoc/helpers/xml_sitemap'
@@ -21,14 +21,15 @@ module Nanoc::Helpers
21
21
  # include Nanoc::Helpers::Blogging
22
22
  module Blogging
23
23
 
24
- # Returns the list of articles, sorted by descending creation date (so
25
- # newer articles appear first).
24
+ # Returns an unsorted list of articles.
25
+ def articles
26
+ @pages.select { |page| page.kind == 'article' }
27
+ end
28
+
29
+ # Returns a list of articles, sorted by descending creation date (so newer
30
+ # articles appear first).
26
31
  def sorted_articles
27
- @pages.select do |page|
28
- page.kind == 'article'
29
- end.sort do |x,y|
30
- y.created_at <=> x.created_at
31
- end
32
+ articles.sort_by { |a| a.created_at }.reverse
32
33
  end
33
34
 
34
35
  # Returns a string representing the atom feed containing recent articles,
@@ -37,6 +38,19 @@ module Nanoc::Helpers
37
38
  #
38
39
  # +limit+:: The maximum number of articles to show. Defaults to 5.
39
40
  #
41
+ # +articles+:: A list of articles to include in the feed. Defaults to the
42
+ # list of articles returned by the articles function.
43
+ #
44
+ # +content_proc+:: A proc that returns the content of the given article,
45
+ # passed as a parameter. By default, given the argument
46
+ # +article+, this proc will return +article.content+.
47
+ # This function may not return nil.
48
+ #
49
+ # +excerpt_proc+:: A proc that returns the excerpt of the given article,
50
+ # passed as a parameter. By default, given the argument
51
+ # +article+, this proc will return +article.excerpt+.
52
+ # This function may return nil.
53
+ #
40
54
  # The following attributes must be set on blog articles:
41
55
  #
42
56
  # * 'title', containing the title of the blog post.
@@ -93,10 +107,38 @@ module Nanoc::Helpers
93
107
  require 'builder'
94
108
 
95
109
  # Extract parameters
96
- limit = params[:limit] || 5
110
+ limit = params[:limit] || 5
111
+ relevant_articles = params[:articles] || articles || []
112
+ content_proc = params[:content_proc] || lambda { |a| a.content }
113
+ excerpt_proc = params[:excerpt_proc] || lambda { |a| a.excerpt }
114
+
115
+ # Check feed page attributes
116
+ if @page.base_url.nil?
117
+ raise RuntimeError.new('Cannot build Atom feed: feed page has no base_url')
118
+ end
119
+ if @page.title.nil?
120
+ raise RuntimeError.new('Cannot build Atom feed: feed page has no title')
121
+ end
122
+ if @page.author_name.nil?
123
+ raise RuntimeError.new('Cannot build Atom feed: feed page has no author_name')
124
+ end
125
+ if @page.author_uri.nil?
126
+ raise RuntimeError.new('Cannot build Atom feed: feed page has no author_uri')
127
+ end
128
+
129
+ # Check article attributes
130
+ if relevant_articles.empty?
131
+ raise RuntimeError.new('Cannot build Atom feed: no articles')
132
+ end
133
+ if relevant_articles.any? { |a| a.created_at.nil? }
134
+ raise RuntimeError.new('Cannot build Atom feed: one or more articles lack created_at')
135
+ end
136
+
137
+ # Get sorted relevant articles
138
+ sorted_relevant_articles = relevant_articles.sort_by { |a| a.created_at }.reverse.first(limit)
97
139
 
98
140
  # Get most recent article
99
- last_article = sorted_articles.first
141
+ last_article = sorted_relevant_articles.first
100
142
 
101
143
  # Create builder
102
144
  buffer = ''
@@ -123,7 +165,7 @@ module Nanoc::Helpers
123
165
  end
124
166
 
125
167
  # Add articles
126
- sorted_articles.first(limit).each do |a|
168
+ sorted_relevant_articles.each do |a|
127
169
  xml.entry do
128
170
  # Add primary attributes
129
171
  xml.id atom_tag_for(a)
@@ -137,8 +179,9 @@ module Nanoc::Helpers
137
179
  xml.link(:rel => 'alternate', :href => url_for(a))
138
180
 
139
181
  # Add content
140
- xml.content a.content, :type => 'html'
141
- xml.summary a.excerpt, :type => 'html' unless a.excerpt.nil?
182
+ summary = excerpt_proc.call(a)
183
+ xml.content content_proc.call(a), :type => 'html'
184
+ xml.summary summary, :type => 'html' unless summary.nil?
142
185
  end
143
186
  end
144
187
  end
@@ -0,0 +1,54 @@
1
+ module Nanoc::Helpers
2
+
3
+ # Nanoc::Helpers::Filtering provides a filter method, which allows parts of
4
+ # a page to be filtered.
5
+ #
6
+ # For example, the following piece of code only runs the "rubypants" filter
7
+ # on the second paragraph:
8
+ #
9
+ # <p>Lorem ipsum dolor sit amet...</p>
10
+ # <% filter :rubypants do %>
11
+ # <p>Consectetur adipisicing elit...</p>
12
+ # <% end %>
13
+ #
14
+ # This helper likely only works with ERB (and perhaps Erubis).
15
+ #
16
+ # To activate this helper, +include+ it, like this:
17
+ #
18
+ # include Nanoc::Helpers::Filtering
19
+ module Filtering
20
+
21
+ # Filters the content in the given block and outputs it.
22
+ def filter(filter_name, &block)
23
+ # Capture block
24
+ data = capture(&block)
25
+
26
+ # Find filter
27
+ filter = Nanoc::Filter.named(filter_name).new(@_obj_rep)
28
+
29
+ # Filter captured data
30
+ filtered_data = filter.run(data)
31
+
32
+ # Append filtered data to buffer
33
+ buffer = eval('_erbout', block.binding)
34
+ buffer << filtered_data
35
+ end
36
+
37
+ private
38
+
39
+ def capture(*args, &block)
40
+ buffer = eval('_erbout', block.binding)
41
+
42
+ pos = buffer.length
43
+ block.call(*args)
44
+
45
+ data = buffer[pos..-1]
46
+
47
+ buffer[pos..-1] = ''
48
+
49
+ data
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -7,6 +7,7 @@ module Nanoc::Helpers
7
7
  # include Nanoc::Helpers::LinkTo
8
8
  module LinkTo
9
9
 
10
+ require 'nanoc/helpers/html_escape'
10
11
  include Nanoc::Helpers::HTMLEscape
11
12
 
12
13
  # Creates a HTML link to the given path or page/asset representation, and
@@ -68,6 +69,45 @@ module Nanoc::Helpers
68
69
  end
69
70
  end
70
71
 
72
+ # Returns the relative path from the current page to the given path or
73
+ # page/asset representation.
74
+ #
75
+ # +path_or_rep+:: the URL or path (a String) to where the relative should
76
+ # point, or the page or asset representation to which the
77
+ # relative should point.
78
+ #
79
+ # Example:
80
+ #
81
+ # # if the current item's path is /foo/bar/
82
+ # relative_path('/foo/qux/')
83
+ # # => '../qux/'
84
+ def relative_path_to(path_or_rep)
85
+ require 'pathname'
86
+
87
+ # Find path
88
+ path = path_or_rep.is_a?(String) ? path_or_rep : path_or_rep.path
89
+
90
+ # Get source and destination paths
91
+ dst_path = Pathname.new(path)
92
+ src_path = Pathname.new(@item.path)
93
+
94
+ # Calculate elative path (method depends on whether destination is a
95
+ # directory or not).
96
+ if src_path.to_s[-1,1] != '/'
97
+ relative_path = dst_path.relative_path_from(src_path.dirname).to_s
98
+ else
99
+ relative_path = dst_path.relative_path_from(src_path).to_s
100
+ end
101
+
102
+ # Add trailing slash if necessary
103
+ if dst_path.to_s[-1,1] == '/'
104
+ relative_path += '/'
105
+ end
106
+
107
+ # Done
108
+ relative_path
109
+ end
110
+
71
111
  end
72
112
 
73
113
  end