nanoc 4.0.0b1 → 4.0.0b2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/NEWS.md +26 -2
  4. data/README.md +1 -1
  5. data/lib/nanoc/base.rb +3 -1
  6. data/lib/nanoc/base/checksummer.rb +1 -3
  7. data/lib/nanoc/base/compilation/compiler.rb +3 -3
  8. data/lib/nanoc/base/compilation/compiler_dsl.rb +3 -3
  9. data/lib/nanoc/base/compilation/item_rep_proxy.rb +1 -1
  10. data/lib/nanoc/base/core_ext/array.rb +0 -11
  11. data/lib/nanoc/base/core_ext/hash.rb +0 -11
  12. data/lib/nanoc/base/identifiable_collection.rb +81 -0
  13. data/lib/nanoc/base/source_data/identifier.rb +9 -9
  14. data/lib/nanoc/base/source_data/site.rb +7 -5
  15. data/lib/nanoc/base/views/identifiable_collection.rb +78 -0
  16. data/lib/nanoc/base/views/item_collection.rb +1 -86
  17. data/lib/nanoc/base/views/layout_collection.rb +1 -57
  18. data/lib/nanoc/base/views/mutable_identifiable_collection.rb +17 -0
  19. data/lib/nanoc/base/views/mutable_item_collection.rb +2 -14
  20. data/lib/nanoc/base/views/mutable_layout_collection.rb +2 -14
  21. data/lib/nanoc/cli/commands/create-site.rb +44 -40
  22. data/lib/nanoc/data_sources/filesystem.rb +1 -1
  23. data/lib/nanoc/data_sources/filesystem_unified.rb +3 -3
  24. data/lib/nanoc/data_sources/filesystem_verbose.rb +3 -3
  25. data/lib/nanoc/filters/erb.rb +2 -2
  26. data/lib/nanoc/filters/rdiscount.rb +1 -1
  27. data/lib/nanoc/filters/redcarpet.rb +1 -1
  28. data/lib/nanoc/version.rb +1 -1
  29. data/tasks/test.rake +1 -0
  30. data/test/base/core_ext/array_spec.rb +0 -8
  31. data/test/base/core_ext/hash_spec.rb +0 -26
  32. data/test/base/test_compiler.rb +1 -1
  33. data/test/base/test_compiler_dsl.rb +13 -10
  34. data/test/base/test_item.rb +0 -6
  35. data/test/base/test_item_array.rb +8 -276
  36. data/test/base/test_layout.rb +1 -5
  37. data/test/base/test_outdatedness_checker.rb +9 -2
  38. data/test/base/test_site.rb +5 -5
  39. data/test/cli/commands/test_compile.rb +14 -0
  40. data/test/cli/commands/test_create_site.rb +40 -2
  41. data/test/cli/commands/test_prune.rb +19 -4
  42. data/test/data_sources/test_filesystem.rb +1 -1
  43. data/test/data_sources/test_filesystem_unified.rb +6 -6
  44. data/test/extra/checking/checks/test_stale.rb +2 -2
  45. data/test/helper.rb +8 -1
  46. data/test/helpers/test_blogging.rb +0 -235
  47. data/test/helpers/test_breadcrumbs.rb +31 -23
  48. data/test/helpers/test_xml_sitemap.rb +38 -29
  49. metadata +5 -3
  50. data/lib/nanoc/base/source_data/item_array.rb +0 -86
@@ -1,95 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Nanoc
4
- class ItemCollectionView
5
- include Enumerable
6
-
7
- # @api private
8
- def initialize(items)
9
- @items = items
10
- end
11
-
12
- # @api private
13
- def unwrap
14
- @items
15
- end
16
-
4
+ class ItemCollectionView < ::Nanoc::IdentifiableCollectionView
17
5
  # @api private
18
6
  def view_class
19
7
  Nanoc::ItemView
20
8
  end
21
-
22
- # Calls the given block once for each item, passing that item as a parameter.
23
- #
24
- # @yieldparam [Nanoc::ItemView] item
25
- #
26
- # @yieldreturn [void]
27
- #
28
- # @return [self]
29
- def each
30
- @items.each { |i| yield view_class.new(i) }
31
- self
32
- end
33
-
34
- # @return [Integer]
35
- def size
36
- @items.size
37
- end
38
-
39
- # @overload at(string)
40
- #
41
- # Finds the item whose identifier matches the given string.
42
- #
43
- # @param [String] string
44
- #
45
- # @return [nil] if no item matches the string
46
- #
47
- # @return [Nanoc::ItemView] if an item was found
48
- def at(arg)
49
- item = @items.at(arg)
50
- item && view_class.new(item)
51
- end
52
-
53
- # Finds all items whose identifier matches the given argument.
54
- #
55
- # @param [String, Regex] arg
56
- #
57
- # @return [Enumerable<Nanoc::ItemView>]
58
- def find_all(arg)
59
- pat = Nanoc::Int::Pattern.from(arg)
60
- @items.select { |i| pat.match?(i.identifier) }
61
- end
62
-
63
- # @overload [](string)
64
- #
65
- # Finds the item whose identifier matches the given string.
66
- #
67
- # If the glob syntax is enabled, the string can be a glob, in which case
68
- # this method finds the first item that matches the given glob.
69
- #
70
- # @param [String] string
71
- #
72
- # @return [nil] if no item matches the string
73
- #
74
- # @return [Nanoc::ItemView] if an item was found
75
- #
76
- # @overload [](regex)
77
- #
78
- # Finds the item whose identifier matches the given regular expression.
79
- #
80
- # @param [Regex] regex
81
- #
82
- # @return [nil] if no item matches the regex
83
- #
84
- # @return [Nanoc::ItemView] if an item was found
85
- def [](arg)
86
- res = @items[arg]
87
- case res
88
- when nil
89
- nil
90
- else
91
- view_class.new(res)
92
- end
93
- end
94
9
  end
95
10
  end
@@ -1,66 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Nanoc
4
- class LayoutCollectionView
5
- include Enumerable
6
-
7
- # @api private
8
- def initialize(layouts)
9
- @layouts = layouts
10
- end
11
-
12
- # @api private
13
- def unwrap
14
- @layouts
15
- end
16
-
4
+ class LayoutCollectionView < ::Nanoc::IdentifiableCollectionView
17
5
  # @api private
18
6
  def view_class
19
7
  Nanoc::LayoutView
20
8
  end
21
-
22
- # Calls the given block once for each layout, passing that layout as a parameter.
23
- #
24
- # @yieldparam [Nanoc::LayoutView] layout
25
- #
26
- # @yieldreturn [void]
27
- def each
28
- @layouts.each { |l| yield view_class.new(l) }
29
- self
30
- end
31
-
32
- # @overload [](string)
33
- #
34
- # Finds the item whose identifier matches the given string.
35
- #
36
- # If the glob syntax is enabled, the string can be a glob, in which case
37
- # this method finds the first item that matches the given glob.
38
- #
39
- # @param [String] string
40
- #
41
- # @return [nil] if no item matches the string
42
- #
43
- # @return [Nanoc::ItemView] if an item was found
44
- #
45
- # @overload [](regex)
46
- #
47
- # Finds the item whose identifier matches the given regular expression.
48
- #
49
- # @param [Regex] regex
50
- #
51
- # @return [nil] if no item matches the regex
52
- #
53
- # @return [Nanoc::ItemView] if an item was found
54
- def [](arg)
55
- layout = @layouts.find { |l| l.identifier == arg }
56
- return view_class.new(layout) if layout
57
-
58
- # FIXME: this should only work if globs are enabled
59
- pat = Nanoc::Int::Pattern.from(arg)
60
- layout = @layouts.find { |l| pat.match?(l.identifier) }
61
- return view_class.new(layout) if layout
62
-
63
- nil
64
- end
65
9
  end
66
10
  end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+ class MutableIdentifiableCollectionView < Nanoc::IdentifiableCollectionView
5
+ # Deletes every object for which the block evaluates to true.
6
+ #
7
+ # @yieldparam [#identifier] object
8
+ #
9
+ # @yieldreturn [Boolean]
10
+ #
11
+ # @return [self]
12
+ def delete_if(&block)
13
+ @objects.delete_if { |o| yield(view_class.new(o)) }
14
+ self
15
+ end
16
+ end
17
+ end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Nanoc
4
- class MutableItemCollectionView < Nanoc::ItemCollectionView
4
+ class MutableItemCollectionView < Nanoc::MutableIdentifiableCollectionView
5
5
  # @api private
6
6
  def view_class
7
7
  Nanoc::MutableItemView
@@ -24,19 +24,7 @@ module Nanoc
24
24
  #
25
25
  # @return [self]
26
26
  def create(content, attributes, identifier, params = {})
27
- @items << Nanoc::Int::Item.new(content, attributes, identifier, params)
28
- self
29
- end
30
-
31
- # Deletes every item for which the block evaluates to true.
32
- #
33
- # @yieldparam [Nanoc::ItemView] item
34
- #
35
- # @yieldreturn [Boolean]
36
- #
37
- # @return [self]
38
- def delete_if(&block)
39
- @items.delete_if(&block)
27
+ @objects << Nanoc::Int::Item.new(content, attributes, identifier, params)
40
28
  self
41
29
  end
42
30
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Nanoc
4
- class MutableLayoutCollectionView < Nanoc::LayoutCollectionView
4
+ class MutableLayoutCollectionView < Nanoc::MutableIdentifiableCollectionView
5
5
  # @api private
6
6
  def view_class
7
7
  Nanoc::MutableLayoutView
@@ -17,19 +17,7 @@ module Nanoc
17
17
  #
18
18
  # @return [self]
19
19
  def create(content, attributes, identifier)
20
- @layouts << Nanoc::Int::Layout.new(content, attributes, identifier)
21
- self
22
- end
23
-
24
- # Deletes every layout for which the block evaluates to true.
25
- #
26
- # @yieldparam [Nanoc::LayoutView] layout
27
- #
28
- # @yieldreturn [Boolean]
29
- #
30
- # @return [self]
31
- def delete_if(&block)
32
- @layouts.delete_if(&block)
20
+ @objects << Nanoc::Int::Layout.new(content, attributes, identifier)
33
21
  self
34
22
  end
35
23
  end
@@ -6,6 +6,7 @@ summary 'create a site'
6
6
  description "
7
7
  Create a new site at the given path. The site will use the `filesystem_unified` data source by default, but this can be changed using the `--datasource` command-line option.
8
8
  "
9
+ flag nil, :force, "Force creation of new site. Disregards previous existence of site in destination"
9
10
 
10
11
  module Nanoc::CLI::Commands
11
12
  class CreateSite < ::Nanoc::CLI::CommandRunner
@@ -20,9 +21,9 @@ module Nanoc::CLI::Commands
20
21
 
21
22
  DEFAULT_CONFIG = <<EOS unless defined? DEFAULT_CONFIG
22
23
  # The syntax to use for patterns in the Rules file. Can be either `"glob"`
23
- # (default) or `null`. The former will enable glob patterns, which behave like
24
- # Ruby’s File.fnmatch. The latter will enable nanoc 3.x-style patterns.
25
- pattern_syntax: glob
24
+ # (default) or `"legacy"`. The former will enable glob patterns, which behave
25
+ # like Ruby’s File.fnmatch. The latter will enable nanoc 3.x-style patterns.
26
+ string_pattern_type: glob
26
27
 
27
28
  # A list of file extensions that nanoc will consider to be textual rather than
28
29
  # binary. If an item with an extension not in this list is found, the file
@@ -47,8 +48,8 @@ enable_output_diff: false
47
48
 
48
49
  prune:
49
50
  # Whether to automatically remove files not managed by nanoc from the output
50
- # directory. For safety reasons, this is turned off by default.
51
- auto_prune: false
51
+ # directory.
52
+ auto_prune: true
52
53
 
53
54
  # Which files and directories you want to exclude from pruning. If you version
54
55
  # your output directory, you should probably exclude VCS directories such as
@@ -88,7 +89,7 @@ data_sources:
88
89
  # UTF-8 (which they should be!), change this.
89
90
  encoding: utf-8
90
91
 
91
- identifier_style: full
92
+ identifier_type: full
92
93
 
93
94
  # Configuration for the “check” command, which run unit tests on the site.
94
95
  checks:
@@ -106,13 +107,29 @@ EOS
106
107
  #!/usr/bin/env ruby
107
108
 
108
109
  compile '/**/*.html' do
109
- filter :erb
110
110
  layout '/default.*'
111
111
  end
112
112
 
113
+ # This is an example rule that matches Markdown (.md) files, and filters them
114
+ # using the :kramdown filter. It is commented out by default, because kramdown
115
+ # is not bundled with nanoc or Ruby.
116
+ #
117
+ #compile '/**/*.md' do
118
+ # filter :kramdown
119
+ # layout '/default.*'
120
+ #end
121
+
113
122
  compile '/**/*' do
114
123
  end
115
124
 
125
+ route '/**/*.{html,md}' do
126
+ if item.identifier =~ '/index.*'
127
+ '/index.html'
128
+ else
129
+ item.identifier.without_ext + '/index.html'
130
+ end
131
+ end
132
+
116
133
  route '/**/*' do
117
134
  item.identifier.to_s
118
135
  end
@@ -121,6 +138,10 @@ layout '/**/*', :erb
121
138
  EOS
122
139
 
123
140
  DEFAULT_ITEM = <<EOS unless defined? DEFAULT_ITEM
141
+ ---
142
+ title: Home
143
+ ---
144
+
124
145
  <h1>A Brand New nanoc Site</h1>
125
146
 
126
147
  <p>You’ve just created a new nanoc site. The page you are looking at right now is the home page for your site. To get started, consider replacing this default homepage with your own customized homepage. Some pointers on how to do so:</p>
@@ -280,8 +301,10 @@ EOS
280
301
  data_source = options[:datasource] || 'filesystem_unified'
281
302
 
282
303
  # Check whether site exists
283
- if File.exist?(path) && (!File.directory?(path) || !(Dir.entries(path) - %w{ . .. }).empty?)
284
- raise Nanoc::Int::Errors::GenericTrivial, "A site at '#{path}' already exists."
304
+ if File.exist?(path) && (!File.directory?(path) || !(Dir.entries(path) - %w{ . .. }).empty?) && !options[:force]
305
+ raise Nanoc::Int::Errors::GenericTrivial,
306
+ "The site was not created because '#{path}' already exists. " +
307
+ "Re-run the command using --force to create the site anyway."
285
308
  end
286
309
 
287
310
  # Check whether data source exists
@@ -302,41 +325,22 @@ EOS
302
325
  FileUtils.mkdir_p('lib')
303
326
  FileUtils.mkdir_p('output')
304
327
 
305
- # Config
306
- File.open('nanoc.yaml', 'w') { |io| io.write(DEFAULT_CONFIG) }
307
- Nanoc::Int::NotificationCenter.post(:file_created, 'nanoc.yaml')
308
-
309
- # Rules
310
- File.open('Rules', 'w') do |io|
311
- io.write DEFAULT_RULES
312
- end
313
- Nanoc::Int::NotificationCenter.post(:file_created, 'Rules')
314
-
315
- # Home page
316
- File.open('content/index.html', 'w') do |io|
317
- io << '---' << "\n"
318
- io << 'title: Home' << "\n"
319
- io << '---' << "\n"
320
- io << "\n"
321
- io << DEFAULT_ITEM
322
- end
323
- Nanoc::Int::NotificationCenter.post(:file_created, 'content/index.html')
324
-
325
- # Style sheet
326
- File.open('content/stylesheet.css', 'w') do |io|
327
- io << DEFAULT_STYLESHEET
328
- end
329
- Nanoc::Int::NotificationCenter.post(:file_created, 'content/stylesheet.css')
330
-
331
- # Layout
332
- File.open('layouts/default.html', 'w') do |io|
333
- io << DEFAULT_LAYOUT
334
- end
335
- Nanoc::Int::NotificationCenter.post(:file_created, 'layouts/default.html')
328
+ write('nanoc.yaml', DEFAULT_CONFIG)
329
+ write('Rules', DEFAULT_RULES)
330
+ write('content/index.html', DEFAULT_ITEM)
331
+ write('content/stylesheet.css', DEFAULT_STYLESHEET)
332
+ write('layouts/default.html', DEFAULT_LAYOUT)
336
333
  end
337
334
 
338
335
  puts "Created a blank nanoc site at '#{path}'. Enjoy!"
339
336
  end
337
+
338
+ private
339
+
340
+ def write(filename, content)
341
+ File.write(filename, content)
342
+ Nanoc::Int::NotificationCenter.post(:file_created, filename)
343
+ end
340
344
  end
341
345
  end
342
346
 
@@ -129,7 +129,7 @@ module Nanoc::DataSources
129
129
  unless [0, 1].include?(meta_filenames.size)
130
130
  raise "Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1"
131
131
  end
132
- unless config[:identifier_style] == 'full'
132
+ unless config[:identifier_type] == 'full'
133
133
  unless [0, 1].include?(content_filenames.size)
134
134
  raise "Found #{content_filenames.size} content files for #{basename}; expected 0 or 1"
135
135
  end
@@ -87,8 +87,8 @@ module Nanoc::DataSources
87
87
  # Returns the identifier derived from the given filename, first stripping
88
88
  # the given directory name off the filename.
89
89
  def identifier_for_filename(filename)
90
- if config[:identifier_style] == 'full'
91
- return Nanoc::Identifier.new(filename, style: :full)
90
+ if config[:identifier_type] == 'full'
91
+ return Nanoc::Identifier.new(filename)
92
92
  end
93
93
 
94
94
  if filename =~ /(^|\/)index(\.[^\/]+)?$/
@@ -96,7 +96,7 @@ module Nanoc::DataSources
96
96
  else
97
97
  regex = @config && @config[:allow_periods_in_identifiers] ? /\.[^\/\.]+$/ : /\.[^\/]+$/
98
98
  end
99
- filename.sub(regex, '').__nanoc_cleaned_identifier
99
+ Nanoc::Identifier.new(filename.sub(regex, ''), type: :legacy)
100
100
  end
101
101
  end
102
102
  end
@@ -61,11 +61,11 @@ module Nanoc::DataSources
61
61
 
62
62
  # See {Nanoc::DataSources::Filesystem#identifier_for_filename}.
63
63
  def identifier_for_filename(filename)
64
- if config[:identifier_style] == 'full'
65
- return Nanoc::Identifier.new(filename, style: :full)
64
+ if config[:identifier_type] == 'full'
65
+ return Nanoc::Identifier.new(filename)
66
66
  end
67
67
 
68
- filename.sub(/[^\/]+\.yaml$/, '')
68
+ Nanoc::Identifier.new(filename.sub(/[^\/]+\.yaml$/, ''), type: :legacy)
69
69
  end
70
70
  end
71
71
  end
@@ -9,10 +9,10 @@ module Nanoc::Filters
9
9
  #
10
10
  # @param [String] content The content to filter
11
11
  #
12
- # @option params [Integer] safe_level (nil) The safe level (`$SAFE`) to
12
+ # @option params [Integer] :safe_level (nil) The safe level (`$SAFE`) to
13
13
  # use while running this filter
14
14
  #
15
- # @option params [String] trim_mode (nil) The trim mode to use
15
+ # @option params [String] :trim_mode (nil) The trim mode to use
16
16
  #
17
17
  # @return [String] The filtered content
18
18
  def run(content, params = {})