nanoc 4.0.0b4 → 4.0.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +31 -32
  4. data/NEWS.md +7 -0
  5. data/README.md +1 -2
  6. data/Rakefile +2 -11
  7. data/TODO.md +0 -1
  8. data/bin/nanoc +4 -0
  9. data/lib/nanoc/base/checksummer.rb +1 -1
  10. data/lib/nanoc/base/compilation/compiler.rb +7 -13
  11. data/lib/nanoc/base/compilation/dependency_tracker.rb +1 -1
  12. data/lib/nanoc/base/compilation/rule.rb +2 -0
  13. data/lib/nanoc/base/compilation/rules_collection.rb +2 -2
  14. data/lib/nanoc/base/entities/identifier.rb +45 -15
  15. data/lib/nanoc/base/entities/pattern.rb +8 -0
  16. data/lib/nanoc/base/entities/snapshot_def.rb +16 -0
  17. data/lib/nanoc/base/entities.rb +1 -0
  18. data/lib/nanoc/base/plugin_registry.rb +1 -1
  19. data/lib/nanoc/base/{compilation → repos}/checksum_store.rb +0 -0
  20. data/lib/nanoc/base/{compilation → repos}/compiled_content_cache.rb +0 -0
  21. data/lib/nanoc/base/repos/config_loader.rb +67 -0
  22. data/lib/nanoc/base/{compilation → repos}/rule_memory_store.rb +0 -0
  23. data/lib/nanoc/base/repos/site_loader.rb +118 -0
  24. data/lib/nanoc/base/{store.rb → repos/store.rb} +0 -0
  25. data/lib/nanoc/base/repos.rb +7 -0
  26. data/lib/nanoc/base/result_data/item_rep.rb +37 -66
  27. data/lib/nanoc/base/services/executor.rb +15 -9
  28. data/lib/nanoc/base/services/item_rep_writer.rb +1 -1
  29. data/lib/nanoc/base/services/recording_executor.rb +4 -4
  30. data/lib/nanoc/base/source_data/configuration.rb +89 -3
  31. data/lib/nanoc/base/source_data/data_source.rb +2 -15
  32. data/lib/nanoc/base/source_data/site.rb +14 -378
  33. data/lib/nanoc/base/views/{config.rb → config_view.rb} +0 -0
  34. data/lib/nanoc/base/views/{identifiable_collection.rb → identifiable_collection_view.rb} +0 -0
  35. data/lib/nanoc/base/views/{item_collection.rb → item_collection_view.rb} +0 -0
  36. data/lib/nanoc/base/views/{item_rep_collection.rb → item_rep_collection_view.rb} +7 -1
  37. data/lib/nanoc/base/views/{item_rep.rb → item_rep_view.rb} +0 -0
  38. data/lib/nanoc/base/views/{item.rb → item_view.rb} +0 -0
  39. data/lib/nanoc/base/views/{layout_collection.rb → layout_collection_view.rb} +0 -0
  40. data/lib/nanoc/base/views/{layout.rb → layout_view.rb} +0 -0
  41. data/lib/nanoc/base/views/mixins/{document.rb → document_view_mixin.rb} +0 -0
  42. data/lib/nanoc/base/views/mixins/{mutable_document.rb → mutable_document_view_mixin.rb} +0 -0
  43. data/lib/nanoc/base/views/{mutable_config.rb → mutable_config_view.rb} +0 -0
  44. data/lib/nanoc/base/views/{mutable_identifiable_collection.rb → mutable_identifiable_collection_view.rb} +0 -0
  45. data/lib/nanoc/base/views/{mutable_item_collection.rb → mutable_item_collection_view.rb} +0 -0
  46. data/lib/nanoc/base/views/{mutable_item.rb → mutable_item_view.rb} +0 -0
  47. data/lib/nanoc/base/views/{mutable_layout_collection.rb → mutable_layout_collection_view.rb} +0 -0
  48. data/lib/nanoc/base/views/{mutable_layout.rb → mutable_layout_view.rb} +0 -0
  49. data/lib/nanoc/base/views/{site.rb → site_view.rb} +0 -0
  50. data/lib/nanoc/base/views.rb +17 -17
  51. data/lib/nanoc/base.rb +1 -4
  52. data/lib/nanoc/cli/ansi_string_colorizer.rb +1 -1
  53. data/lib/nanoc/cli/cleaning_stream.rb +5 -0
  54. data/lib/nanoc/cli/command_runner.rb +10 -4
  55. data/lib/nanoc/cli/commands/compile.rb +1 -1
  56. data/lib/nanoc/cli/commands/create-site.rb +12 -11
  57. data/lib/nanoc/cli/commands/prune.rb +1 -0
  58. data/lib/nanoc/cli/commands/show-plugins.rb +4 -4
  59. data/lib/nanoc/cli/commands/show-rules.rb +21 -30
  60. data/lib/nanoc/cli/commands/view.rb +1 -1
  61. data/lib/nanoc/cli/error_handler.rb +1 -1
  62. data/lib/nanoc/cli.rb +3 -3
  63. data/lib/nanoc/data_sources/filesystem.rb +4 -4
  64. data/lib/nanoc/extra/checking/runner.rb +3 -2
  65. data/lib/nanoc/extra/deployers/rsync.rb +1 -1
  66. data/lib/nanoc/extra/link_collector.rb +1 -1
  67. data/lib/nanoc/helpers/capturing.rb +1 -1
  68. data/lib/nanoc/helpers/rendering.rb +2 -2
  69. data/lib/nanoc/version.rb +1 -1
  70. data/nanoc.gemspec +3 -4
  71. data/tasks/doc.rake +1 -1
  72. data/tasks/rubocop.rake +4 -8
  73. data/tasks/test.rake +11 -27
  74. data/test/base/test_compiler.rb +21 -16
  75. data/test/base/test_compiler_dsl.rb +8 -8
  76. data/test/base/test_item.rb +1 -1
  77. data/test/base/test_item_rep.rb +16 -14
  78. data/test/base/test_memoization.rb +1 -38
  79. data/test/base/test_outdatedness_checker.rb +38 -6
  80. data/test/base/test_site.rb +19 -121
  81. data/test/cli/commands/test_compile.rb +1 -1
  82. data/test/cli/commands/test_create_site.rb +7 -8
  83. data/test/data_sources/test_filesystem.rb +7 -7
  84. data/test/data_sources/test_filesystem_unified.rb +17 -17
  85. data/test/extra/checking/checks/test_mixed_content.rb +8 -8
  86. data/test/extra/checking/checks/test_stale.rb +3 -4
  87. data/test/extra/deployers/test_fog.rb +1 -1
  88. data/test/extra/deployers/test_rsync.rb +2 -2
  89. data/test/extra/test_filesystem_tools.rb +1 -1
  90. data/test/filters/test_erb.rb +1 -1
  91. data/test/filters/test_handlebars.rb +2 -2
  92. data/test/filters/test_less.rb +2 -2
  93. data/test/filters/test_mustache.rb +2 -2
  94. data/test/filters/test_relativize_paths.rb +1 -1
  95. data/test/filters/test_sass.rb +6 -6
  96. data/test/filters/test_xsl.rb +3 -3
  97. data/test/helper.rb +10 -15
  98. data/test/helpers/test_blogging.rb +16 -16
  99. data/test/helpers/test_capturing.rb +6 -6
  100. data/test/helpers/test_link_to.rb +13 -13
  101. data/test/helpers/test_rendering.rb +33 -0
  102. data/test/helpers/test_tagging.rb +8 -8
  103. metadata +32 -30
  104. data/test/gem_loader.rb +0 -9
@@ -0,0 +1,118 @@
1
+ module Nanoc::Int
2
+ class SiteLoader
3
+ def new_empty
4
+ site_from_config(Nanoc::Int::Configuration.new.with_defaults)
5
+ end
6
+
7
+ def new_with_config(hash)
8
+ site_from_config(Nanoc::Int::Configuration.new(hash).with_defaults)
9
+ end
10
+
11
+ def new_from_cwd
12
+ site_from_config(Nanoc::Int::ConfigLoader.new.new_from_cwd)
13
+ end
14
+
15
+ # @api private
16
+ def setup_child_parent_links(items)
17
+ items.each do |item|
18
+ item.parent = nil
19
+ item.children = []
20
+ end
21
+
22
+ item_map = {}
23
+ items.each do |item|
24
+ next if item.identifier !~ /\/\z/
25
+ item_map[item.identifier.to_s] = item
26
+ end
27
+
28
+ items.each do |item|
29
+ parent_id_end = item.identifier.to_s.rindex('/', -2)
30
+ next unless parent_id_end
31
+
32
+ parent_id = item.identifier.to_s[0..parent_id_end]
33
+ parent = item_map[parent_id]
34
+ next unless parent
35
+
36
+ item.parent = parent
37
+ parent.children << item
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def site_from_config(config)
44
+ code_snippets = code_snippets_from_config(config)
45
+ code_snippets.each(&:load)
46
+
47
+ items = Nanoc::Int::IdentifiableCollection.new(config)
48
+ layouts = Nanoc::Int::IdentifiableCollection.new(config)
49
+
50
+ with_data_sources(config) do |data_sources|
51
+ data_sources.each do |ds|
52
+ items_in_ds = ds.items
53
+ layouts_in_ds = ds.layouts
54
+
55
+ items_in_ds.each { |i| i.identifier = i.identifier.prefix(ds.items_root) }
56
+ layouts_in_ds.each { |l| l.identifier = l.identifier.prefix(ds.layouts_root) }
57
+
58
+ items.concat(items_in_ds)
59
+ layouts.concat(layouts_in_ds)
60
+ end
61
+ end
62
+
63
+ setup_child_parent_links(items)
64
+
65
+ Nanoc::Int::Site.new(
66
+ config: config,
67
+ code_snippets: code_snippets,
68
+ items: items,
69
+ layouts: layouts,
70
+ )
71
+ end
72
+
73
+ # @return [Boolean]
74
+ def self.cwd_is_nanoc_site?
75
+ Nanoc::Int::ConfigLoader.cwd_is_nanoc_site?
76
+ end
77
+
78
+ def with_data_sources(config, &_block)
79
+ data_sources = create_data_sources(config)
80
+
81
+ begin
82
+ data_sources.each(&:use)
83
+ yield(data_sources)
84
+ ensure
85
+ data_sources.each(&:unuse)
86
+ end
87
+ end
88
+
89
+ def create_data_sources(config)
90
+ config[:data_sources].map do |data_source_hash|
91
+ # Get data source class
92
+ data_source_class = Nanoc::DataSource.named(data_source_hash[:type])
93
+ if data_source_class.nil?
94
+ raise Nanoc::Int::Errors::UnknownDataSource.new(data_source_hash[:type])
95
+ end
96
+
97
+ # Create data source
98
+ data_source_class.new(
99
+ config,
100
+ data_source_hash[:items_root],
101
+ data_source_hash[:layouts_root],
102
+ data_source_hash.merge(data_source_hash[:config] || {}),
103
+ )
104
+ end
105
+ end
106
+
107
+ def code_snippets_from_config(config)
108
+ config[:lib_dirs].flat_map do |lib|
109
+ Dir["#{lib}/**/*.rb"].sort.map do |filename|
110
+ Nanoc::Int::CodeSnippet.new(
111
+ File.read(filename),
112
+ filename,
113
+ )
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ require_relative 'repos/store'
2
+
3
+ require_relative 'repos/checksum_store'
4
+ require_relative 'repos/compiled_content_cache'
5
+ require_relative 'repos/config_loader'
6
+ require_relative 'repos/rule_memory_store'
7
+ require_relative 'repos/site_loader'
@@ -1,70 +1,31 @@
1
1
  module Nanoc::Int
2
- # A single representation (rep) of an item ({Nanoc::Int::Item}). An item can
3
- # have multiple representations. A representation has its own output file.
4
- # A single item can therefore have multiple output files, each run through
5
- # a different set of filters with a different layout.
6
- #
7
2
  # @api private
8
3
  class ItemRep
9
- # Contains all private methods. Mixed into {Nanoc::Int::ItemRep}.
10
- #
11
- # @api private
12
- module Private
13
- attr_accessor :content_snapshots
14
-
15
- # @return [Boolean] true if this representation has already been
16
- # compiled during the current or last compilation session; false
17
- # otherwise
18
- #
19
- # @api private
20
- attr_accessor :compiled
21
- alias_method :compiled?, :compiled
22
-
23
- # @return [Hash<Symbol,String>] A hash containing the raw paths (paths
24
- # including the path to the output directory and the filename) for all
25
- # snapshots. The keys correspond with the snapshot names, and the
26
- # values with the path.
27
- #
28
- # @api private
29
- attr_accessor :raw_paths
30
-
31
- # @return [Hash<Symbol,String>] A hash containing the paths for all
32
- # snapshots. The keys correspond with the snapshot names, and the
33
- # values with the path.
34
- #
35
- # @api private
36
- attr_accessor :paths
37
-
38
- # Resets the compilation progress for this item representation. This is
39
- # necessary when an unmet dependency is detected during compilation.
40
- #
41
- # @api private
42
- #
43
- # @return [void]
44
- def forget_progress
45
- initialize_content
46
- end
47
- end
4
+ # @return [Hash<Symbol,Nanoc::Int::Content]
5
+ attr_accessor :snapshot_contents
48
6
 
49
- include Private
7
+ # @return [Boolean]
8
+ attr_accessor :compiled
9
+ alias_method :compiled?, :compiled
50
10
 
51
- # @return [Nanoc::Int::Item] The item to which this rep belongs
11
+ # @return [Hash<Symbol,String>]
12
+ attr_accessor :raw_paths
13
+
14
+ # @return [Hash<Symbol,String>]
15
+ attr_accessor :paths
16
+
17
+ # @return [Nanoc::Int::Item]
52
18
  attr_reader :item
53
19
 
54
- # @return [Symbol] The representation's unique name
20
+ # @return [Symbol]
55
21
  attr_reader :name
56
22
 
57
- # @return [Array] A list of snapshots, represented as arrays where the
58
- # first element is the snapshot name (a Symbol) and the last element is
59
- # a Boolean indicating whether the snapshot is final or not
60
- attr_accessor :snapshots
23
+ # @return [Enumerable<Nanoc::Int:SnapshotDef]
24
+ attr_accessor :snapshot_defs
61
25
 
62
- # Creates a new item representation for the given item.
63
- #
64
- # @param [Nanoc::Int::Item] item The item to which the new representation will
65
- # belong.
26
+ # @param [Nanoc::Int::Item] item
66
27
  #
67
- # @param [Symbol] name The unique name for the new item representation.
28
+ # @param [Symbol] name
68
29
  def initialize(item, name)
69
30
  # Set primary attributes
70
31
  @item = item
@@ -73,7 +34,7 @@ module Nanoc::Int
73
34
  # Set default attributes
74
35
  @raw_paths = {}
75
36
  @paths = {}
76
- @snapshots = []
37
+ @snapshot_defs = []
77
38
  initialize_content
78
39
 
79
40
  # Reset flags
@@ -81,7 +42,7 @@ module Nanoc::Int
81
42
  end
82
43
 
83
44
  def binary?
84
- @content_snapshots[:last].binary?
45
+ @snapshot_contents[:last].binary?
85
46
  end
86
47
 
87
48
  # Returns the compiled content from a given snapshot.
@@ -100,12 +61,12 @@ module Nanoc::Int
100
61
  end
101
62
 
102
63
  # Get name of last pre-layout snapshot
103
- snapshot_name = params.fetch(:snapshot) { @content_snapshots[:pre] ? :pre : :last }
64
+ snapshot_name = params.fetch(:snapshot) { @snapshot_contents[:pre] ? :pre : :last }
104
65
  is_moving = [:pre, :post, :last].include?(snapshot_name)
105
66
 
106
67
  # Check existance of snapshot
107
- snapshot = snapshots.find { |s| s.first == snapshot_name }
108
- if !is_moving && (snapshot.nil? || snapshot[-1] == false)
68
+ snapshot_def = snapshot_defs.find { |sd| sd.name == snapshot_name }
69
+ if !is_moving && (snapshot_def.nil? || !snapshot_def.final?)
109
70
  raise Nanoc::Int::Errors::NoSuchSnapshot.new(self, snapshot_name)
110
71
  end
111
72
 
@@ -115,14 +76,14 @@ module Nanoc::Int
115
76
  when :post, :last
116
77
  true
117
78
  when :pre
118
- snapshot.nil? || !snapshot[-1]
79
+ snapshot_def.nil? || !snapshot_def.final?
119
80
  end
120
- is_usable_snapshot = @content_snapshots[snapshot_name] && (self.compiled? || !is_still_moving)
81
+ is_usable_snapshot = @snapshot_contents[snapshot_name] && (self.compiled? || !is_still_moving)
121
82
  unless is_usable_snapshot
122
83
  raise Nanoc::Int::Errors::UnmetDependency.new(self)
123
84
  end
124
85
 
125
- @content_snapshots[snapshot_name].string
86
+ @snapshot_contents[snapshot_name].string
126
87
  end
127
88
 
128
89
  # Checks whether content exists at a given snapshot.
@@ -132,7 +93,7 @@ module Nanoc::Int
132
93
  #
133
94
  # @since 3.2.0
134
95
  def snapshot?(snapshot_name)
135
- !@content_snapshots[snapshot_name].nil?
96
+ !@snapshot_contents[snapshot_name].nil?
136
97
  end
137
98
  alias_method :has_snapshot?, :snapshot?
138
99
 
@@ -162,6 +123,16 @@ module Nanoc::Int
162
123
  @paths[snapshot_name]
163
124
  end
164
125
 
126
+ # Resets the compilation progress for this item representation. This is
127
+ # necessary when an unmet dependency is detected during compilation.
128
+ #
129
+ # @api private
130
+ #
131
+ # @return [void]
132
+ def forget_progress
133
+ initialize_content
134
+ end
135
+
165
136
  # Returns an object that can be used for uniquely identifying objects.
166
137
  #
167
138
  # @api private
@@ -179,7 +150,7 @@ module Nanoc::Int
179
150
 
180
151
  def initialize_content
181
152
  # FIXME: Where is :raw?
182
- @content_snapshots = { last: @item.content }
153
+ @snapshot_contents = { last: @item.content }
183
154
  end
184
155
  end
185
156
  end
@@ -1,6 +1,12 @@
1
1
  module Nanoc
2
2
  module Int
3
3
  class Executor
4
+ class OutputNotWrittenError < ::Nanoc::Error
5
+ def initialize(filter_name, output_filename)
6
+ super("The #{filter_name.inspect} filter did not write anything to the required output file, #{output_filename}.")
7
+ end
8
+ end
9
+
4
10
  def initialize(compiler)
5
11
  @compiler = compiler
6
12
  end
@@ -25,22 +31,22 @@ module Nanoc
25
31
  filter = klass.new(assigns_for(rep))
26
32
 
27
33
  # Run filter
28
- last = rep.content_snapshots[:last]
34
+ last = rep.snapshot_contents[:last]
29
35
  source = rep.binary? ? last.filename : last.string
30
36
  result = filter.setup_and_run(source, filter_args)
31
37
  if klass.to_binary?
32
- rep.content_snapshots[:last] = Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
38
+ rep.snapshot_contents[:last] = Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
33
39
  else
34
- rep.content_snapshots[:last] = Nanoc::Int::TextualContent.new(result).tap(&:freeze)
40
+ rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(result).tap(&:freeze)
35
41
  end
36
42
 
37
43
  # Check whether file was written
38
44
  if klass.to_binary? && !File.file?(filter.output_filename)
39
- raise "The #{filter_name.inspect} filter did not write anything to the required output file, #{filter.output_filename}."
45
+ raise OutputNotWrittenError.new(filter_name, filter.output_filename)
40
46
  end
41
47
 
42
48
  # Create snapshot
43
- snapshot(rep, rep.content_snapshots[:post] ? :post : :pre, final: false) unless rep.binary?
49
+ snapshot(rep, rep.snapshot_contents[:post] ? :post : :pre, final: false) unless rep.binary?
44
50
  ensure
45
51
  # Notify end
46
52
  Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
@@ -59,7 +65,7 @@ module Nanoc
59
65
  raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(rep) if rep.binary?
60
66
 
61
67
  # Create "pre" snapshot
62
- if rep.content_snapshots[:post].nil?
68
+ if rep.snapshot_contents[:post].nil?
63
69
  snapshot(rep, :pre, final: true)
64
70
  end
65
71
 
@@ -81,7 +87,7 @@ module Nanoc
81
87
  content = layout.content
82
88
  arg = content.binary? ? content.filename : content.string
83
89
  res = filter.setup_and_run(arg, filter_args)
84
- rep.content_snapshots[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
90
+ rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
85
91
 
86
92
  # Create "post" snapshot
87
93
  snapshot(rep, :post, final: false)
@@ -96,11 +102,11 @@ module Nanoc
96
102
  is_final = params.fetch(:final, true)
97
103
 
98
104
  unless rep.binary?
99
- rep.content_snapshots[snapshot_name] = rep.content_snapshots[:last]
105
+ rep.snapshot_contents[snapshot_name] = rep.snapshot_contents[:last]
100
106
  end
101
107
 
102
108
  if snapshot_name == :pre && is_final
103
- rep.snapshots << [:pre, true]
109
+ rep.snapshot_defs << Nanoc::Int::SnapshotDef.new(:pre, true)
104
110
  end
105
111
 
106
112
  if is_final
@@ -14,7 +14,7 @@ module Nanoc::Int
14
14
  Nanoc::Int::NotificationCenter.post(
15
15
  :will_write_rep, item_rep, raw_path)
16
16
 
17
- content = item_rep.content_snapshots[:last]
17
+ content = item_rep.snapshot_contents[:last]
18
18
  if content.binary?
19
19
  temp_path = content.filename
20
20
  else
@@ -7,11 +7,11 @@ module Nanoc
7
7
  @rule_memory = []
8
8
  end
9
9
 
10
- def filter(rep, filter_name, filter_args = {})
10
+ def filter(_rep, filter_name, filter_args = {})
11
11
  @rule_memory << [:filter, filter_name, filter_args]
12
12
  end
13
13
 
14
- def layout(rep, layout_identifier, extra_filter_args = nil)
14
+ def layout(_rep, layout_identifier, extra_filter_args = nil)
15
15
  if extra_filter_args
16
16
  @rule_memory << [:layout, layout_identifier, extra_filter_args]
17
17
  else
@@ -19,7 +19,7 @@ module Nanoc
19
19
  end
20
20
  end
21
21
 
22
- def snapshot(rep, snapshot_name, params = {})
22
+ def snapshot(_rep, snapshot_name, params = {})
23
23
  @rule_memory << [:snapshot, snapshot_name, params]
24
24
 
25
25
  # Count
@@ -33,7 +33,7 @@ module Nanoc
33
33
  end
34
34
  end
35
35
 
36
- def record_write(rep, path)
36
+ def record_write(_rep, path)
37
37
  @rule_memory << [:write, path]
38
38
  end
39
39
  end
@@ -2,12 +2,94 @@ module Nanoc::Int
2
2
  # Represents the site configuration.
3
3
  #
4
4
  # @api private
5
- class Configuration < ::Hash
5
+ class Configuration
6
+ NONE = Object.new
7
+
8
+ # The default configuration for a data source. A data source's
9
+ # configuration overrides these options.
10
+ DEFAULT_DATA_SOURCE_CONFIG = {
11
+ type: 'filesystem',
12
+ items_root: '/',
13
+ layouts_root: '/',
14
+ config: {},
15
+ identifier_type: 'full',
16
+ }
17
+
18
+ # The default configuration for a site. A site's configuration overrides
19
+ # these options: when a {Nanoc::Int::Site} is created with a configuration
20
+ # that lacks some options, the default value will be taken from
21
+ # `DEFAULT_CONFIG`.
22
+ DEFAULT_CONFIG = {
23
+ text_extensions: %w( css erb haml htm html js less markdown md php rb sass scss txt xhtml xml coffee hb handlebars mustache ms slim rdoc ).sort,
24
+ lib_dirs: %w( lib ),
25
+ commands_dirs: %w( commands ),
26
+ output_dir: 'output',
27
+ data_sources: [{}],
28
+ index_filenames: ['index.html'],
29
+ enable_output_diff: false,
30
+ prune: { auto_prune: false, exclude: ['.git', '.hg', '.svn', 'CVS'] },
31
+ string_pattern_type: 'glob',
32
+ }
33
+
6
34
  # Creates a new configuration with the given hash.
7
35
  #
8
36
  # @param [Hash] hash The actual configuration hash
9
- def initialize(hash)
10
- replace(hash)
37
+ def initialize(hash = {})
38
+ @wrapped = hash.__nanoc_symbolize_keys_recursively
39
+ end
40
+
41
+ def with_defaults
42
+ new_wrapped = DEFAULT_CONFIG.merge(@wrapped)
43
+ new_wrapped[:data_sources] = new_wrapped[:data_sources].map do |ds|
44
+ DEFAULT_DATA_SOURCE_CONFIG.merge(ds)
45
+ end
46
+
47
+ self.class.new(new_wrapped)
48
+ end
49
+
50
+ def to_h
51
+ @wrapped
52
+ end
53
+
54
+ def [](key)
55
+ @wrapped[key]
56
+ end
57
+
58
+ def fetch(key, fallback = NONE, &_block)
59
+ @wrapped.fetch(key) do
60
+ if !fallback.equal?(NONE)
61
+ fallback
62
+ elsif block_given?
63
+ yield(key)
64
+ else
65
+ raise KeyError, "key not found: #{key.inspect}"
66
+ end
67
+ end
68
+ end
69
+
70
+ def []=(key, value)
71
+ @wrapped[key] = value
72
+ end
73
+
74
+ def merge(hash)
75
+ self.class.new(@wrapped.merge(hash.to_h))
76
+ end
77
+
78
+ def without(key)
79
+ self.class.new(@wrapped.reject { |k, _v| k == key })
80
+ end
81
+
82
+ def update(hash)
83
+ @wrapped.update(hash)
84
+ end
85
+
86
+ def each
87
+ @wrapped.each { |k, v| yield(k, v) }
88
+ self
89
+ end
90
+
91
+ def __nanoc_freeze_recursively
92
+ @wrapped.__nanoc_freeze_recursively
11
93
  end
12
94
 
13
95
  # Returns an object that can be used for uniquely identifying objects.
@@ -16,5 +98,9 @@ module Nanoc::Int
16
98
  def reference
17
99
  :config
18
100
  end
101
+
102
+ def inspect
103
+ "<#{self.class}>"
104
+ end
19
105
  end
20
106
  end
@@ -29,21 +29,8 @@ module Nanoc
29
29
 
30
30
  extend Nanoc::Int::PluginRegistry::PluginMethods
31
31
 
32
- # Creates a new data source for the given site.
33
- #
34
- # @param [Nanoc::Int::Site] site The site this data source belongs to.
35
- #
36
- # @param [String] items_root The prefix that should be given to all items
37
- # returned by the #items method (comparable to mount points for
38
- # filesystems in Unix-ish OSes).
39
- #
40
- # @param [String] layouts_root The prefix that should be given to all
41
- # layouts returned by the #layouts method (comparable to mount points
42
- # for filesystems in Unix-ish OSes).
43
- #
44
- # @param [Hash] config The configuration for this data source.
45
- def initialize(site, items_root, layouts_root, config)
46
- @site = site
32
+ def initialize(site_config, items_root, layouts_root, config)
33
+ @site_config = site_config
47
34
  @items_root = items_root
48
35
  @layouts_root = layouts_root
49
36
  @config = config || {}