nanoc 3.7.5 → 3.8.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +2 -2
  3. data/Gemfile +1 -1
  4. data/NEWS.md +24 -3
  5. data/README.md +1 -1
  6. data/bin/nanoc +1 -1
  7. data/lib/nanoc/base/compilation/dependency_tracker.rb +1 -1
  8. data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +1 -1
  9. data/lib/nanoc/base/compilation/rule.rb +15 -1
  10. data/lib/nanoc/base/result_data/item_rep.rb +27 -10
  11. data/lib/nanoc/base/source_data/item_array.rb +2 -0
  12. data/lib/nanoc/base/source_data/site.rb +1 -0
  13. data/lib/nanoc/cli.rb +16 -7
  14. data/lib/nanoc/cli/commands/autocompile.rb +1 -1
  15. data/lib/nanoc/cli/commands/create-site.rb +2 -2
  16. data/lib/nanoc/cli/commands/show-rules.rb +3 -6
  17. data/lib/nanoc/cli/commands/watch.rb +3 -3
  18. data/lib/nanoc/cli/error_handler.rb +1 -1
  19. data/lib/nanoc/cli/logger.rb +3 -5
  20. data/lib/nanoc/data_sources/filesystem.rb +2 -2
  21. data/lib/nanoc/extra/auto_compiler.rb +1 -1
  22. data/lib/nanoc/extra/checking/checks.rb +2 -0
  23. data/lib/nanoc/extra/checking/checks/mixed_content.rb +31 -0
  24. data/lib/nanoc/extra/deployers/fog.rb +24 -0
  25. data/lib/nanoc/extra/link_collector.rb +42 -9
  26. data/lib/nanoc/extra/pruner.rb +1 -1
  27. data/lib/nanoc/filters/colorize_syntax.rb +4 -4
  28. data/lib/nanoc/filters/pandoc.rb +23 -4
  29. data/lib/nanoc/filters/sass/sass_filesystem_importer.rb +4 -2
  30. data/lib/nanoc/helpers/blogging.rb +17 -6
  31. data/lib/nanoc/helpers/tagging.rb +1 -1
  32. data/lib/nanoc/helpers/text.rb +1 -1
  33. data/lib/nanoc/version.rb +1 -1
  34. data/tasks/test.rake +1 -1
  35. data/test/base/test_item_array.rb +8 -0
  36. data/test/base/test_item_rep.rb +51 -0
  37. data/test/base/test_item_rep_recorder_proxy.rb +19 -0
  38. data/test/base/test_rule.rb +10 -0
  39. data/test/cli/commands/test_create_site.rb +13 -0
  40. data/test/cli/test_cli.rb +30 -0
  41. data/test/extra/checking/checks/test_mixed_content.rb +188 -0
  42. data/test/extra/deployers/test_fog.rb +32 -0
  43. data/test/filters/test_pandoc.rb +17 -3
  44. data/test/filters/test_sass.rb +11 -0
  45. data/test/helper.rb +3 -3
  46. data/test/helpers/test_blogging.rb +30 -0
  47. metadata +6 -3
@@ -8,6 +8,10 @@ module Nanoc::Extra::Deployers
8
8
  # deploy:
9
9
  # public:
10
10
  # kind: fog
11
+ # bucket: nanoc-site
12
+ # cdn_id: XXXXXX
13
+ # preprod:
14
+ # kind: fog
11
15
  # provider: local
12
16
  # local_root: ~/myCloud
13
17
  # bucket: nanoc-site
@@ -25,6 +29,7 @@ module Nanoc::Extra::Deployers
25
29
  src = File.expand_path(source_path)
26
30
  bucket = config.delete(:bucket) || config.delete(:bucket_name)
27
31
  path = config.delete(:path)
32
+ cdn_id = config.delete(:cdn_id)
28
33
 
29
34
  config.delete(:kind)
30
35
 
@@ -33,6 +38,7 @@ module Nanoc::Extra::Deployers
33
38
 
34
39
  # Mock if necessary
35
40
  if self.dry_run?
41
+ puts 'Dry run - simulation'
36
42
  ::Fog.mock!
37
43
  end
38
44
 
@@ -51,6 +57,7 @@ module Nanoc::Extra::Deployers
51
57
 
52
58
  # Create bucket if necessary
53
59
  if should_create_bucket
60
+ puts 'Creating bucket'
54
61
  directory = connection.directories.create(key: bucket, prefix: path)
55
62
  end
56
63
 
@@ -63,6 +70,7 @@ module Nanoc::Extra::Deployers
63
70
  files += set
64
71
  end
65
72
  keys_to_destroy = files.all.map(&:key)
73
+ keys_to_invalidate = []
66
74
 
67
75
  # Upload all the files in the output folder to the clouds
68
76
  puts 'Uploading local files'
@@ -75,6 +83,7 @@ module Nanoc::Extra::Deployers
75
83
  body: File.open(file_path),
76
84
  public: true)
77
85
  keys_to_destroy.delete(key)
86
+ keys_to_invalidate.push(key)
78
87
  end
79
88
  end
80
89
 
@@ -84,6 +93,21 @@ module Nanoc::Extra::Deployers
84
93
  directory.files.get(key).destroy
85
94
  end
86
95
 
96
+ # invalidate CDN objects
97
+ if cdn_id
98
+ puts 'Invalidating CDN distribution'
99
+ keys_to_invalidate.concat(keys_to_destroy)
100
+ cdn = ::Fog::CDN.new(config)
101
+ # fog cannot mock CDN requests
102
+ unless self.dry_run?
103
+ distribution = cdn.get_distribution(cdn_id)
104
+ # usual limit per invalidation: 1000 objects
105
+ keys_to_invalidate.each_slice(1000) do |paths|
106
+ cdn.post_invalidation(distribution, paths)
107
+ end
108
+ end
109
+ end
110
+
87
111
  puts 'Done!'
88
112
  end
89
113
 
@@ -4,6 +4,17 @@ require 'set'
4
4
 
5
5
  module ::Nanoc::Extra
6
6
  class LinkCollector
7
+ URI_ATTRS = {
8
+ 'a' => :href,
9
+ 'audio' => :src,
10
+ 'form' => :action,
11
+ 'iframe' => :src,
12
+ 'img' => :src,
13
+ 'link' => :href,
14
+ 'script' => :src,
15
+ 'video' => :src
16
+ }
17
+
7
18
  def initialize(filenames, mode = nil)
8
19
  Nanoc::Extra::JRubyNokogiriWarner.check_and_warn
9
20
 
@@ -33,24 +44,46 @@ module ::Nanoc::Extra
33
44
  filenames_per_href
34
45
  end
35
46
 
47
+ def filenames_per_resource_uri
48
+ require 'nokogiri'
49
+ filenames_per_resource_uri = {}
50
+ @filenames.each do |filename|
51
+ resource_uris_in_file(filename).each do |resouce_uri|
52
+ filenames_per_resource_uri[resouce_uri] ||= Set.new
53
+ filenames_per_resource_uri[resouce_uri] << filename
54
+ end
55
+ end
56
+ filenames_per_resource_uri
57
+ end
58
+
36
59
  def external_href?(href)
37
60
  href =~ %r{^(\/\/|[a-z\-]+:)}
38
61
  end
39
62
 
40
63
  def hrefs_in_file(filename)
41
- hrefs_in_file = Set.new
42
- doc = Nokogiri::HTML(::File.read(filename))
43
- doc.css('a').each { |e| hrefs_in_file << e[:href] unless e[:href].nil? }
44
- doc.css('img').each { |e| hrefs_in_file << e[:src] }
64
+ uris_in_file filename, %w(a img)
65
+ end
66
+
67
+ def resource_uris_in_file(filename)
68
+ uris_in_file filename, %w(audio form img iframe link script video)
69
+ end
70
+
71
+ private
45
72
 
46
- # Convert protocol-relative urls
47
- # e.g. //example.com => http://example.com
48
- hrefs_in_file.map! { |href| href.gsub(/^\/\//, 'http://') }
73
+ def uris_in_file(filename, tag_names)
74
+ uris = Set.new
75
+ doc = Nokogiri::HTML(::File.read(filename))
76
+ tag_names.each do |tag_name|
77
+ attr = URI_ATTRS[tag_name]
78
+ doc.css(tag_name).each do |e|
79
+ uris << e[attr] unless e[attr].nil?
80
+ end
81
+ end
49
82
 
50
83
  # Strip fragment
51
- hrefs_in_file.map! { |href| href.gsub(/#.*$/, '') }
84
+ uris.map! { |href| href.gsub(/#.*$/, '') }
52
85
 
53
- hrefs_in_file.select(&@filter)
86
+ uris.select(&@filter)
54
87
  end
55
88
  end
56
89
  end
@@ -35,7 +35,7 @@ module Nanoc::Extra
35
35
  present_dirs = []
36
36
  Find.find(site.config[:output_dir] + '/') do |f|
37
37
  present_files << f if File.file?(f)
38
- present_dirs << f if File.directory?(f)
38
+ present_dirs << f if File.directory?(f)
39
39
  end
40
40
 
41
41
  # Remove stray files
@@ -29,7 +29,7 @@ module Nanoc::Filters
29
29
  #
30
30
  # * `:coderay` for [Coderay](http://coderay.rubychan.de/)
31
31
  # * `:pygmentize` for [pygmentize](http://pygments.org/docs/cmdline/), the
32
- # commandline frontend for [Pygments](http://pygments.org/)
32
+ # command-line frontend for [Pygments](http://pygments.org/)
33
33
  # * `:pygmentsrb` for [pygments.rb](https://github.com/tmm1/pygments.rb),
34
34
  # a Ruby interface for [Pygments](http://pygments.org/)
35
35
  # * `:simon_highlight` for [Highlight](http://www.andre-simon.de/doku/highlight/en/highlight.html)
@@ -201,7 +201,7 @@ module Nanoc::Filters
201
201
  end
202
202
 
203
203
  # Runs the content through [pygmentize](http://pygments.org/docs/cmdline/),
204
- # the commandline frontend for [Pygments](http://pygments.org/).
204
+ # the command-line frontend for [Pygments](http://pygments.org/).
205
205
  #
206
206
  # @api private
207
207
  #
@@ -216,7 +216,7 @@ module Nanoc::Filters
216
216
  check_availability('pygmentize', '-V')
217
217
 
218
218
  params[:encoding] ||= 'utf-8'
219
- params[:nowrap] ||= 'True'
219
+ params[:nowrap] ||= 'True'
220
220
 
221
221
  cmd = ['pygmentize', '-l', language, '-f', 'html']
222
222
  cmd << '-O' << params.map { |k, v| "#{k}=#{v}" }.join(',') unless params.empty?
@@ -246,7 +246,7 @@ module Nanoc::Filters
246
246
  args[:lexer] ||= language
247
247
  args[:options] ||= {}
248
248
  args[:options][:encoding] ||= 'utf-8'
249
- args[:options][:nowrap] ||= 'True'
249
+ args[:options][:nowrap] ||= 'True'
250
250
 
251
251
  Pygments.highlight(code, args)
252
252
  end
@@ -5,14 +5,33 @@ module Nanoc::Filters
5
5
  requires 'pandoc-ruby'
6
6
 
7
7
  # Runs the content through [Pandoc](http://johnmacfarlane.net/pandoc/)
8
- # using [PandocRuby](https://github.com/alphabetum/pandoc-ruby). Options
9
- # are passed on to PandocRuby.
8
+ # using [PandocRuby](https://github.com/alphabetum/pandoc-ruby).
9
+ #
10
+ # Arguments can be passed to PandocRuby in two ways:
11
+ #
12
+ # * Use the `:args` option. This approach is more flexible, since it
13
+ # allows passing an array instead of a hash.
14
+ #
15
+ # * Pass the arguments directly to the filter. With this approach, only
16
+ # hashes can be passed, which is more limiting than the `:args` approach.
17
+ #
18
+ # The `:args` approach is recommended.
19
+ #
20
+ # @example Passing arguments using `:arg`
21
+ #
22
+ # filter :pandoc, args: [:s, {:f => :markdown, :to => :html}, 'no-wrap', :toc]
23
+ #
24
+ # @example Passing arguments not using `:arg`
25
+ #
26
+ # filter :pandoc, :f => :markdown, :to => :html
10
27
  #
11
28
  # @param [String] content The content to filter
12
29
  #
13
30
  # @return [String] The filtered content
14
- def run(content, *params)
15
- PandocRuby.convert(content, *params)
31
+ def run(content, params = {})
32
+ args = params.key?(:args) ? params[:args] : params
33
+
34
+ PandocRuby.convert(content, *args)
16
35
  end
17
36
  end
18
37
  end
@@ -10,8 +10,10 @@ class ::Sass::Importers::Filesystem
10
10
 
11
11
  # Create dependency
12
12
  filter = options[:nanoc_current_filter]
13
- item = filter.imported_filename_to_item(full_filename)
14
- filter.depend_on([item]) unless item.nil?
13
+ if filter
14
+ item = filter.imported_filename_to_item(full_filename)
15
+ filter.depend_on([item]) unless item.nil?
16
+ end
15
17
 
16
18
  # Call original _find
17
19
  _orig_find(dir, name, options)
@@ -56,6 +56,7 @@ module Nanoc::Helpers
56
56
 
57
57
  attr_accessor :limit
58
58
  attr_accessor :relevant_articles
59
+ attr_accessor :preserve_order
59
60
  attr_accessor :content_proc
60
61
  attr_accessor :excerpt_proc
61
62
  attr_accessor :title
@@ -85,9 +86,13 @@ module Nanoc::Helpers
85
86
  protected
86
87
 
87
88
  def sorted_relevant_articles
88
- relevant_articles.sort_by do |a|
89
- attribute_to_time(a[:created_at])
90
- end.reverse.first(limit)
89
+ all = relevant_articles
90
+
91
+ unless @preserve_order
92
+ all = all.sort_by { |a| attribute_to_time(a[:created_at]) }
93
+ end
94
+
95
+ all.reverse.first(limit)
91
96
  end
92
97
 
93
98
  def last_article
@@ -172,7 +177,7 @@ module Nanoc::Helpers
172
177
  if a[:author_name] || a[:author_uri]
173
178
  xml.author do
174
179
  xml.name a[:author_name] || author_name
175
- xml.uri a[:author_uri] || author_uri
180
+ xml.uri a[:author_uri] || author_uri
176
181
  end
177
182
  end
178
183
 
@@ -268,8 +273,13 @@ module Nanoc::Helpers
268
273
  # @option params [Number] :limit (5) The maximum number of articles to
269
274
  # show
270
275
  #
271
- # @option params [Array] :articles (sorted_articles) A list of articles to
272
- # include in the feed
276
+ # @option params [Array] :articles (articles) A list of articles to include
277
+ # in the feed
278
+ #
279
+ # @option params [Boolean] :preserve_order (false) Whether or not the
280
+ # ordering of the list of articles should be preserved. If false, the
281
+ # articles will be sorted by `created_at`. If true, the list of articles
282
+ # will be used as-is, and should have the most recent articles last.
273
283
  #
274
284
  # @option params [Proc] :content_proc (->{ |article|
275
285
  # article.compiled_content(:snapshot => :pre) }) A proc that returns the
@@ -303,6 +313,7 @@ module Nanoc::Helpers
303
313
  # Fill builder
304
314
  builder.limit = params[:limit] || 5
305
315
  builder.relevant_articles = params[:articles] || articles || []
316
+ builder.preserve_order = params.fetch(:preserve_order, false)
306
317
  builder.content_proc = params[:content_proc] || ->(a) { a.compiled_content(snapshot: :pre) }
307
318
  builder.excerpt_proc = params[:excerpt_proc] || ->(a) { a[:excerpt] }
308
319
  builder.title = params[:title] || @item[:title] || @site.config[:title]
@@ -29,7 +29,7 @@ module Nanoc::Helpers
29
29
  #
30
30
  # @return [String] A hyperlinked list of tags for the given item
31
31
  def tags_for(item, params = {})
32
- base_url = params[:base_url] || 'http://technorati.com/tag/'
32
+ base_url = params[:base_url] || 'http://technorati.com/tag/'
33
33
  none_text = params[:none_text] || '(none)'
34
34
  separator = params[:separator] || ', '
35
35
 
@@ -18,7 +18,7 @@ module Nanoc::Helpers
18
18
  # @return [String] The excerpt of the given string
19
19
  def excerptize(string, params = {})
20
20
  # Initialize params
21
- params[:length] ||= 25
21
+ params[:length] ||= 25
22
22
  params[:omission] ||= '...'
23
23
 
24
24
  # Get excerpt
data/lib/nanoc/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nanoc
4
4
  # The current nanoc version.
5
- VERSION = '3.7.5'
5
+ VERSION = '3.8.0'
6
6
  end
data/tasks/test.rake CHANGED
@@ -12,7 +12,7 @@ def run_tests(dir_glob)
12
12
  test_files = Dir["#{dir_glob}*_spec.rb"] + Dir["#{dir_glob}test_*.rb"]
13
13
  test_files.each { |f| require f }
14
14
 
15
- res = MiniTest::Unit.new.run(ENV['ARGS'].split)
15
+ res = Minitest.run(ENV['ARGS'].split)
16
16
  exit(res) if res != 0
17
17
  end
18
18
 
@@ -96,6 +96,14 @@ class Nanoc::ItemArrayTest < Nanoc::TestCase
96
96
  assert_nil @items.at('/tenthousand/')
97
97
  end
98
98
 
99
+ def test_regex
100
+ foo = Nanoc::Item.new('Item Foo', {}, '/foo/')
101
+ @items << foo
102
+
103
+ assert_equal [@one], @items[/n/]
104
+ assert_equal [@two, foo], @items[%r{o/}]
105
+ end
106
+
99
107
  def test_less_than_less_than
100
108
  assert_nil @items[2]
101
109
  assert_nil @items['/foo/']
@@ -77,6 +77,57 @@ class Nanoc::ItemRepTest < Nanoc::TestCase
77
77
  end
78
78
  end
79
79
 
80
+ def test_compiled_content_with_moving_pre_snapshot
81
+ # Create rep
82
+ item = Nanoc::Item.new(
83
+ 'blah blah', {}, '/',
84
+ binary: false
85
+ )
86
+ rep = Nanoc::ItemRep.new(item, nil)
87
+ rep.expects(:compiled?).returns(false)
88
+ rep.instance_eval { @content = { pre: 'pre!', last: 'last!' } }
89
+
90
+ # Check
91
+ assert_raises(Nanoc::Errors::UnmetDependency) do
92
+ rep.compiled_content(snapshot: :pre)
93
+ end
94
+ end
95
+
96
+ def test_compiled_content_with_non_moving_pre_snapshot
97
+ # Create rep
98
+ item = Nanoc::Item.new(
99
+ 'blah blah', {}, '/',
100
+ binary: false
101
+ )
102
+ rep = Nanoc::ItemRep.new(item, nil)
103
+ rep.expects(:compiled?).returns(false)
104
+ rep.snapshots = [[:pre, true]]
105
+ rep.instance_eval { @content = { pre: 'pre!', post: 'post!', last: 'last!' } }
106
+
107
+ # Check
108
+ assert_equal 'pre!', rep.compiled_content(snapshot: :pre)
109
+ end
110
+
111
+ def test_compiled_content_with_final_pre_snapshot_in_layout
112
+ # Mock layout
113
+ layout = Nanoc::Layout.new(
114
+ %(BEFORE <%= @item_rep.compiled_content(snapshot: :pre) %> AFTER),
115
+ {},
116
+ '/somelayout/')
117
+
118
+ # Create item and item rep
119
+ item = Nanoc::Item.new(
120
+ 'blah blah', {}, '/',
121
+ binary: false
122
+ )
123
+ rep = create_rep_for(item, :foo)
124
+ rep.assigns = { item_rep: rep }
125
+
126
+ # Run and check
127
+ rep.layout(layout, :erb, {})
128
+ assert_equal('BEFORE blah blah AFTER', rep.instance_eval { @content[:last] })
129
+ end
130
+
80
131
  def test_filter
81
132
  # Mock site
82
133
  site = MiniTest::Mock.new
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ class Nanoc::ItemRepRecorderProxyTest < Nanoc::TestCase
4
+ def test_double_names
5
+ proxy = Nanoc::ItemRepRecorderProxy.new(mock)
6
+
7
+ proxy.snapshot(:foo, stuff: :giraffe)
8
+ assert_raises(Nanoc::Errors::CannotCreateMultipleSnapshotsWithSameName) do
9
+ proxy.snapshot(:foo, stuff: :donkey)
10
+ end
11
+ end
12
+
13
+ def test_double_params
14
+ proxy = Nanoc::ItemRepRecorderProxy.new(mock)
15
+
16
+ proxy.snapshot(:foo)
17
+ proxy.snapshot(:bar)
18
+ end
19
+ end
@@ -12,4 +12,14 @@ class Nanoc::RuleTest < Nanoc::TestCase
12
12
  def test_apply_to
13
13
  # TODO: implement
14
14
  end
15
+
16
+ def test_matches
17
+ regexp = %r</(.*)/(.*)/>
18
+ identifier = '/anything/else/'
19
+ expected = ['anything', 'else']
20
+
21
+ rule = Nanoc::Rule.new(regexp, :string, Proc.new {})
22
+
23
+ assert_equal expected, rule.send(:matches, identifier)
24
+ end
15
25
  end