nanoc 4.0.0a1 → 4.0.0a2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +9 -4
  3. data/NEWS.md +13 -0
  4. data/lib/nanoc/base.rb +2 -0
  5. data/lib/nanoc/base/compilation/compiler.rb +0 -1
  6. data/lib/nanoc/base/compilation/compiler_dsl.rb +21 -7
  7. data/lib/nanoc/base/compilation/item_rep_proxy.rb +10 -1
  8. data/lib/nanoc/base/compilation/rule.rb +10 -12
  9. data/lib/nanoc/base/compilation/rules_collection.rb +2 -2
  10. data/lib/nanoc/base/pattern.rb +63 -0
  11. data/lib/nanoc/base/source_data/data_source.rb +33 -18
  12. data/lib/nanoc/base/source_data/identifier.rb +65 -3
  13. data/lib/nanoc/base/source_data/item.rb +1 -1
  14. data/lib/nanoc/base/source_data/item_array.rb +17 -2
  15. data/lib/nanoc/base/source_data/layout.rb +1 -1
  16. data/lib/nanoc/base/source_data/site.rb +4 -3
  17. data/lib/nanoc/base/views/config.rb +22 -0
  18. data/lib/nanoc/base/views/item.rb +76 -0
  19. data/lib/nanoc/base/views/item_collection.rb +46 -4
  20. data/lib/nanoc/base/views/item_rep.rb +23 -0
  21. data/lib/nanoc/base/views/layout.rb +4 -0
  22. data/lib/nanoc/base/views/layout_collection.rb +7 -1
  23. data/lib/nanoc/base/views/mutable_config.rb +5 -0
  24. data/lib/nanoc/base/views/mutable_item.rb +15 -0
  25. data/lib/nanoc/base/views/mutable_item_collection.rb +25 -0
  26. data/lib/nanoc/base/views/mutable_layout.rb +5 -0
  27. data/lib/nanoc/base/views/mutable_layout_collection.rb +20 -2
  28. data/lib/nanoc/cli/cleaning_stream.rb +15 -0
  29. data/lib/nanoc/cli/commands/create-site.rb +17 -35
  30. data/lib/nanoc/cli/commands/shell.rb +7 -4
  31. data/lib/nanoc/data_sources.rb +0 -1
  32. data/lib/nanoc/data_sources/filesystem.rb +75 -76
  33. data/lib/nanoc/data_sources/filesystem_unified.rb +4 -27
  34. data/lib/nanoc/data_sources/filesystem_verbose.rb +4 -21
  35. data/lib/nanoc/version.rb +1 -1
  36. data/nanoc.gemspec +1 -1
  37. data/test/base/test_compiler.rb +35 -15
  38. data/test/base/test_compiler_dsl.rb +32 -30
  39. data/test/base/test_data_source.rb +2 -2
  40. data/test/base/test_item_array.rb +10 -1
  41. data/test/base/test_rule.rb +2 -2
  42. data/test/base/test_site.rb +32 -0
  43. data/test/cli/commands/test_create_site.rb +7 -1
  44. data/test/cli/commands/test_prune.rb +2 -2
  45. data/test/data_sources/test_filesystem.rb +29 -9
  46. data/test/data_sources/test_filesystem_unified.rb +48 -68
  47. data/test/helper.rb +1 -0
  48. data/test/helpers/test_breadcrumbs.rb +4 -4
  49. data/test/test_gem.rb +0 -1
  50. metadata +4 -5
  51. data/lib/nanoc/data_sources/static.rb +0 -62
  52. data/test/data_sources/test_static.rb +0 -93
@@ -70,7 +70,7 @@ module Nanoc::Int
70
70
 
71
71
  # Get rest of params
72
72
  @attributes = attributes.__nanoc_symbolize_keys_recursively
73
- @identifier = Nanoc::Identifier.new(identifier)
73
+ @identifier = Nanoc::Identifier.from(identifier)
74
74
 
75
75
  # Set mtime
76
76
  @attributes.merge!(mtime: params[:mtime]) if params[:mtime]
@@ -21,7 +21,9 @@ module Nanoc::Int
21
21
  DELEGATED_METHODS = (Array.instance_methods + Enumerable.instance_methods).map(&:to_sym) - EXCLUDED_METHODS
22
22
  def_delegators :@items, *DELEGATED_METHODS
23
23
 
24
- def initialize
24
+ def initialize(config)
25
+ @config = config
26
+
25
27
  @items = []
26
28
  end
27
29
 
@@ -33,7 +35,7 @@ module Nanoc::Int
33
35
 
34
36
  def [](*args)
35
37
  if 1 == args.size && args.first.is_a?(String)
36
- item_with_identifier(args.first)
38
+ item_with_identifier(args.first) || item_matching_glob(args.first)
37
39
  elsif 1 == args.size && args.first.is_a?(Regexp)
38
40
  @items.select { |i| i.identifier.to_s =~ args.first }
39
41
  else
@@ -60,6 +62,15 @@ module Nanoc::Int
60
62
  end
61
63
  end
62
64
 
65
+ def item_matching_glob(glob)
66
+ if use_globs?
67
+ pat = Nanoc::Int::Pattern.from(glob)
68
+ @items.find { |i| pat.match?(i.identifier) }
69
+ else
70
+ nil
71
+ end
72
+ end
73
+
63
74
  def build_mapping
64
75
  @mapping = {}
65
76
  @items.each do |item|
@@ -67,5 +78,9 @@ module Nanoc::Int
67
78
  end
68
79
  @mapping.freeze
69
80
  end
81
+
82
+ def use_globs?
83
+ @config[:pattern_syntax] == 'glob'
84
+ end
70
85
  end
71
86
  end
@@ -29,7 +29,7 @@ module Nanoc::Int
29
29
  def initialize(raw_content, attributes, identifier, params = {})
30
30
  @raw_content = raw_content
31
31
  @attributes = attributes.__nanoc_symbolize_keys_recursively
32
- @identifier = Nanoc::Identifier.new(identifier)
32
+ @identifier = Nanoc::Identifier.from(identifier)
33
33
  end
34
34
 
35
35
  # Requests the attribute with the given key.
@@ -176,6 +176,7 @@ module Nanoc::Int
176
176
 
177
177
  item_map = {}
178
178
  @items.each do |item|
179
+ next if item.identifier !~ /\/\z/
179
180
  item_map[item.identifier.to_s] = item
180
181
  end
181
182
 
@@ -324,11 +325,11 @@ module Nanoc::Int
324
325
  @items_loaded = true
325
326
 
326
327
  # Get items
327
- @items = Nanoc::Int::ItemArray.new
328
+ @items = Nanoc::Int::ItemArray.new(@config)
328
329
  data_sources.each do |ds|
329
330
  items_in_ds = ds.items
330
331
  items_in_ds.each do |i|
331
- i.identifier = Nanoc::Identifier.new(File.join(ds.items_root, i.identifier.to_s))
332
+ i.identifier = i.identifier.prefix(ds.items_root)
332
333
  i.site = self
333
334
  end
334
335
  @items.concat(items_in_ds)
@@ -346,7 +347,7 @@ module Nanoc::Int
346
347
  data_sources.each do |ds|
347
348
  layouts_in_ds = ds.layouts
348
349
  layouts_in_ds.each do |l|
349
- l.identifier = Nanoc::Identifier.new(File.join(ds.layouts_root, l.identifier.to_s))
350
+ l.identifier = l.identifier.prefix(ds.layouts_root)
350
351
  end
351
352
  @layouts.concat(layouts_in_ds)
352
353
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Nanoc
4
4
  class ConfigView
5
+ # @api private
6
+ NONE = Object.new
7
+
5
8
  # @api private
6
9
  def initialize(config)
7
10
  @config = config
@@ -12,6 +15,25 @@ module Nanoc
12
15
  @config
13
16
  end
14
17
 
18
+ # @see Hash#fetch
19
+ def fetch(key, fallback=NONE, &block)
20
+ @config.fetch(key) do
21
+ if !fallback.equal?(NONE)
22
+ fallback
23
+ elsif block_given?
24
+ yield(key)
25
+ else
26
+ raise KeyError, "key not found: #{key.inspect}"
27
+ end
28
+ end
29
+ end
30
+
31
+ # @see Hash#key?
32
+ def key?(key)
33
+ @config.key?(key)
34
+ end
35
+
36
+ # @see Hash#[]
15
37
  def [](key)
16
38
  @config[key]
17
39
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Nanoc
4
4
  class ItemView
5
+ # @api private
6
+ NONE = Object.new
7
+
5
8
  # @api private
6
9
  def initialize(item)
7
10
  @item = item
@@ -12,39 +15,112 @@ module Nanoc
12
15
  @item
13
16
  end
14
17
 
18
+ # @see Object#==
15
19
  def ==(other)
16
20
  identifier == other.identifier
17
21
  end
18
22
  alias_method :eql?, :==
19
23
 
24
+ # @see Object#hash
20
25
  def hash
21
26
  self.class.hash ^ identifier.hash
22
27
  end
23
28
 
29
+ # @return [Nanoc::Identifier]
24
30
  def identifier
25
31
  @item.identifier
26
32
  end
27
33
 
34
+ # @see Hash#fetch
35
+ def fetch(key, fallback=NONE, &block)
36
+ res = @item[key] # necessary for dependency tracking
37
+
38
+ if @item.attributes.key?(key)
39
+ res
40
+ else
41
+ if !fallback.equal?(NONE)
42
+ fallback
43
+ elsif block_given?
44
+ yield(key)
45
+ else
46
+ raise KeyError, "key not found: #{key.inspect}"
47
+ end
48
+ end
49
+ end
50
+
51
+ # @see Hash#key?
52
+ def key?(key)
53
+ _res = @item[key] # necessary for dependency tracking
54
+ @item.attributes.key?(key)
55
+ end
56
+
57
+ # @see Hash#[]
28
58
  def [](key)
29
59
  @item[key]
30
60
  end
31
61
 
62
+ # Returns the compiled content.
63
+ #
64
+ # @option params [String] :rep (:default) The name of the representation
65
+ # from which the compiled content should be fetched. By default, the
66
+ # compiled content will be fetched from the default representation.
67
+ #
68
+ # @option params [String] :snapshot The name of the snapshot from which to
69
+ # fetch the compiled content. By default, the returned compiled content
70
+ # will be the content compiled right before the first layout call (if
71
+ # any).
72
+ #
73
+ # @return [String] The content of the given rep at the given snapshot.
32
74
  def compiled_content(params = {})
33
75
  @item.compiled_content(params)
34
76
  end
35
77
 
78
+ # Returns the item path, as used when being linked to. It starts
79
+ # with a slash and it is relative to the output directory. It does not
80
+ # include the path to the output directory. It will not include the
81
+ # filename if the filename is an index filename.
82
+ #
83
+ # @option params [String] :rep (:default) The name of the representation
84
+ # from which the path should be fetched. By default, the path will be
85
+ # fetched from the default representation.
86
+ #
87
+ # @option params [Symbol] :snapshot (:last) The snapshot for which the
88
+ # path should be returned.
89
+ #
90
+ # @return [String] The item’s path.
36
91
  def path(params = {})
37
92
  @item.path(params)
38
93
  end
39
94
 
95
+ # Returns the children of this item. For items with identifiers that have
96
+ # extensions, returns an empty collection.
97
+ #
98
+ # @return [Enumerable<Nanoc::ItemView>]
40
99
  def children
41
100
  @item.children.map { |i| Nanoc::ItemView.new(i) }
42
101
  end
43
102
 
103
+ # Returns the parent of this item, if one exists. For items with identifiers
104
+ # that have extensions, returns nil.
105
+ #
106
+ # @return [Nanoc::ItemView] if the item has a parent
107
+ #
108
+ # @return [nil] if the item has no parent
109
+ def parent
110
+ Nanoc::ItemView.new(@item.parent)
111
+ end
112
+
113
+ # @return [Boolean] True if the item is binary, false otherwise
44
114
  def binary?
45
115
  @item.binary?
46
116
  end
47
117
 
118
+ # For textual items, returns the raw (source) content of this item; for
119
+ # binary items, returns `nil`.
120
+ #
121
+ # @return [String] if the item is textual
122
+ #
123
+ # @return [nil] if the item is binary
48
124
  def raw_content
49
125
  @item.raw_content
50
126
  end
@@ -19,20 +19,62 @@ module Nanoc
19
19
  Nanoc::ItemView
20
20
  end
21
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]
22
29
  def each
23
30
  @items.each { |i| yield view_class.new(i) }
31
+ self
24
32
  end
25
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
26
48
  def at(arg)
27
49
  item = @items.at(arg)
28
50
  item && view_class.new(item)
29
51
  end
30
52
 
31
- def [](*args)
32
- res = @items[*args]
53
+ # @overload [](string)
54
+ #
55
+ # Finds the item whose identifier matches the given string.
56
+ #
57
+ # If the glob syntax is enabled, the string can be a glob, in which case
58
+ # this method finds the first item that matches the given glob.
59
+ #
60
+ # @param [String] string
61
+ #
62
+ # @return [nil] if no item matches the string
63
+ #
64
+ # @return [Nanoc::ItemView] if an item was found
65
+ #
66
+ # @overload [](regex)
67
+ #
68
+ # Finds the item whose identifier matches the given regular expression.
69
+ #
70
+ # @param [Regex] regex
71
+ #
72
+ # @return [nil] if no item matches the regex
73
+ #
74
+ # @return [Nanoc::ItemView] if an item was found
75
+ def [](arg)
76
+ res = @items[arg]
33
77
  case res
34
- when Array
35
- res.map { |r| view_class.new(r) }
36
78
  when nil
37
79
  nil
38
80
  else
@@ -12,27 +12,50 @@ module Nanoc
12
12
  @item_rep
13
13
  end
14
14
 
15
+ # @see Object#==
15
16
  def ==(other)
16
17
  item.identifier == other.item.identifier && name == other.name
17
18
  end
18
19
  alias_method :eql?, :==
19
20
 
21
+ # @see Object#hash
20
22
  def hash
21
23
  self.class.hash ^ item.identifier.hash ^ name.hash
22
24
  end
23
25
 
26
+ # @return [Symbol]
24
27
  def name
25
28
  @item_rep.name
26
29
  end
27
30
 
31
+ # Returns the compiled content.
32
+ #
33
+ # @option params [String] :snapshot The name of the snapshot from which to
34
+ # fetch the compiled content. By default, the returned compiled content
35
+ # will be the content compiled right before the first layout call (if
36
+ # any).
37
+ #
38
+ # @return [String] The content at the given snapshot.
28
39
  def compiled_content(params = {})
29
40
  @item_rep.compiled_content(params)
30
41
  end
31
42
 
43
+ # Returns the item rep’s path, as used when being linked to. It starts
44
+ # with a slash and it is relative to the output directory. It does not
45
+ # include the path to the output directory. It will not include the
46
+ # filename if the filename is an index filename.
47
+ #
48
+ # @option params [Symbol] :snapshot (:last) The snapshot for which the
49
+ # path should be returned.
50
+ #
51
+ # @return [String] The item rep’s path.
32
52
  def path(params = {})
33
53
  @item_rep.path(params)
34
54
  end
35
55
 
56
+ # Returns the item that this item rep belongs to.
57
+ #
58
+ # @return [Nanoc::ItemView]
36
59
  def item
37
60
  Nanoc::ItemView.new(@item_rep.item)
38
61
  end
@@ -12,19 +12,23 @@ module Nanoc
12
12
  @layout
13
13
  end
14
14
 
15
+ # @see Object#==
15
16
  def ==(other)
16
17
  identifier == other.identifier
17
18
  end
18
19
  alias_method :eql?, :==
19
20
 
21
+ # @see Object#hash
20
22
  def hash
21
23
  self.class.hash ^ identifier.hash
22
24
  end
23
25
 
26
+ # @return [Nanoc::Identifier]
24
27
  def identifier
25
28
  @layout.identifier
26
29
  end
27
30
 
31
+ # @see Hash#[]
28
32
  def [](key)
29
33
  @layout[key]
30
34
  end
@@ -11,7 +11,7 @@ module Nanoc
11
11
 
12
12
  # @api private
13
13
  def unwrap
14
- @item
14
+ @layouts
15
15
  end
16
16
 
17
17
  # @api private
@@ -19,8 +19,14 @@ module Nanoc
19
19
  Nanoc::LayoutView
20
20
  end
21
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]
22
27
  def each
23
28
  @layouts.each { |l| yield view_class.new(l) }
29
+ self
24
30
  end
25
31
  end
26
32
  end
@@ -2,6 +2,11 @@
2
2
 
3
3
  module Nanoc
4
4
  class MutableConfigView < Nanoc::ConfigView
5
+ # Sets the value for the given attribute.
6
+ #
7
+ # @param [Symbol] key
8
+ #
9
+ # @see Hash#[]=
5
10
  def []=(key, value)
6
11
  @config[key] = value
7
12
  end
@@ -2,8 +2,23 @@
2
2
 
3
3
  module Nanoc
4
4
  class MutableItemView < Nanoc::ItemView
5
+ # Sets the value for the given attribute.
6
+ #
7
+ # @param [Symbol] key
8
+ #
9
+ # @see Hash#[]=
5
10
  def []=(key, value)
6
11
  unwrap[key] = value
7
12
  end
13
+
14
+ # Updates the attributes based on the given hash.
15
+ #
16
+ # @param [Hash] hash
17
+ #
18
+ # @return [self]
19
+ def update_attributes(hash)
20
+ hash.each { |k, v| unwrap[k] = v }
21
+ self
22
+ end
8
23
  end
9
24
  end