nanoc 4.0.0a1 → 4.0.0a2

Sign up to get free protection for your applications and to get access to all the features.
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