nanoc 4.5.4 → 4.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a383a3d98b256b56a7e6590371884c6f189b14dc
4
- data.tar.gz: a5564e313aff3b6a2a1fad8eb6378ebb7ea58136
3
+ metadata.gz: 9c5effeb7d9dc719725af84e69e43fd8114804d9
4
+ data.tar.gz: '068728706ce3eaa7ca6b05627b23f2c014c9b33e'
5
5
  SHA512:
6
- metadata.gz: cd7789992a7d9ee85236ab87fc1ce6fcd7a134713a60a86528abce3d28d0700d5b687cb182170e5afcda5dd9eaac5b0d32c3f5a20b44e8671c2b6351c59447c2
7
- data.tar.gz: 440ebab06d975006331704bf5d72e775ec65aa668bea50557163f1e3af033e0e27ca9b71347b24f6c79941efb7fb333fa841e82babe8f47d860982fa83ca3582
6
+ metadata.gz: a7ca4e77db7c096579d28c7af8206505d11fad7c858d87362ceda01087ee39ea8da60cadb2833911e9ed37fe505a68bda39b933bd6bde84ee27a0ec99c84d26e
7
+ data.tar.gz: db7dcee097e6515ca68ba39ec8a139070b003120c23864dfe20b02f7ab79b7e617be4d6be46cdf0da8808c86b51c9137fdf6e1f5a908a27894aaf27771d67974
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  GIT
2
2
  remote: git://github.com/bbatsov/rubocop.git
3
- revision: d2652328e819cc8317e69b883449e71b83dcdffc
3
+ revision: c500b3c760d334c733af1ce2229a2db65957c875
4
4
  specs:
5
- rubocop (0.46.0)
5
+ rubocop (0.47.1)
6
6
  parser (>= 2.3.3.1, < 3.0)
7
7
  powerpack (~> 0.1)
8
8
  rainbow (>= 1.99.1, < 3.0)
@@ -27,7 +27,7 @@ GIT
27
27
  PATH
28
28
  remote: .
29
29
  specs:
30
- nanoc (4.5.4)
30
+ nanoc (4.6.0)
31
31
  cri (~> 2.3)
32
32
  ddplugin (~> 1.0)
33
33
  hamster (~> 3.0)
@@ -71,7 +71,7 @@ GEM
71
71
  sass (>= 3.2, < 3.5)
72
72
  concurrent-ruby (1.0.4)
73
73
  contracts (0.14.0)
74
- coveralls (0.8.17)
74
+ coveralls (0.8.19)
75
75
  json (>= 1.8, < 3)
76
76
  simplecov (~> 0.12.0)
77
77
  term-ansicolor (~> 1.3)
@@ -82,7 +82,7 @@ GEM
82
82
  cri (2.7.1)
83
83
  colored (~> 1.2)
84
84
  ddplugin (1.0.0)
85
- diff-lcs (1.2.5)
85
+ diff-lcs (1.3)
86
86
  docile (1.1.5)
87
87
  erubis (2.7.0)
88
88
  excon (0.54.0)
@@ -127,7 +127,7 @@ GEM
127
127
  fog-atmos (0.1.0)
128
128
  fog-core
129
129
  fog-xml
130
- fog-aws (1.1.0)
130
+ fog-aws (1.2.0)
131
131
  fog-core (~> 1.38)
132
132
  fog-json (~> 1.0)
133
133
  fog-xml (~> 0.1)
@@ -172,7 +172,7 @@ GEM
172
172
  fog-profitbricks (3.0.0)
173
173
  fog-core (~> 1.42)
174
174
  fog-json (~> 1.0)
175
- fog-rackspace (0.1.3)
175
+ fog-rackspace (0.1.4)
176
176
  fog-core (>= 1.35)
177
177
  fog-json (>= 1.0)
178
178
  fog-xml (>= 0.1)
@@ -206,7 +206,7 @@ GEM
206
206
  fog-voxel (0.1.0)
207
207
  fog-core
208
208
  fog-xml
209
- fog-vsphere (1.6.0)
209
+ fog-vsphere (1.7.0)
210
210
  fog-core
211
211
  rbvmomi (~> 1.9)
212
212
  fog-xenserver (0.2.3)
@@ -346,8 +346,8 @@ GEM
346
346
  execjs (>= 0.3.0, < 3)
347
347
  unicode-display_width (1.1.3)
348
348
  vcr (3.0.3)
349
- w3c_validators (1.3.1)
350
- json (~> 2.0)
349
+ w3c_validators (1.3.2)
350
+ json (>= 1.8)
351
351
  nokogiri (~> 1.6)
352
352
  webmock (2.3.2)
353
353
  addressable (>= 2.3.6)
@@ -425,4 +425,4 @@ DEPENDENCIES
425
425
  yuicompressor
426
426
 
427
427
  BUNDLED WITH
428
- 1.13.7
428
+ 1.14.1
data/NEWS.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.6.0 (2017-01-22)
4
+
5
+ Features:
6
+
7
+ * Made `#content_for` accept a string as well as a block, to allow setting captured content outside of ERB (#1066, #1073)
8
+ * Added `#raw_content=` to items and layouts during preprocessing (#1057)
9
+ * Added `#snapshot?` to item rep views (#1056)
10
+
11
+ Enhancements:
12
+
13
+ * Prevented useless recompilations when switching Nanoc environments (#1070, #1071)
14
+
3
15
  ## 4.5.4 (2017-01-16)
4
16
 
5
17
  Fixes:
@@ -58,7 +58,7 @@ module Nanoc::Int
58
58
  DEFAULT_DATA_SOURCE_CONFIG.merge(ds)
59
59
  end
60
60
 
61
- self.class.new(hash: new_wrapped)
61
+ self.class.new(hash: new_wrapped, env_name: @env_name)
62
62
  end
63
63
 
64
64
  def with_environment
@@ -135,6 +135,18 @@ module Nanoc::Int
135
135
  self
136
136
  end
137
137
 
138
+ contract C::None => String
139
+ def output_dir
140
+ self[:output_dir]
141
+ end
142
+
143
+ contract C::None => C::IterOf[String]
144
+ def output_dirs
145
+ envs = @wrapped.fetch(ENVIRONMENTS_CONFIG_KEY, {})
146
+ res = [output_dir] + envs.values.map { |v| v[:output_dir] }
147
+ res.uniq.compact
148
+ end
149
+
138
150
  # Returns an object that can be used for uniquely identifying objects.
139
151
  #
140
152
  # @return [Object] An unique reference to this object
@@ -44,6 +44,11 @@ module Nanoc::Int
44
44
  @compiled = false
45
45
  end
46
46
 
47
+ contract Symbol => C::Bool
48
+ def snapshot?(name)
49
+ snapshot_defs.any? { |sd| sd.name == name }
50
+ end
51
+
47
52
  contract C::KeywordArgs[snapshot: C::Optional[Symbol]] => C::Maybe[String]
48
53
  # Returns the item rep’s raw path. It includes the path to the output
49
54
  # directory and the full filename.
@@ -89,4 +89,4 @@ module Nanoc
89
89
  end
90
90
  end
91
91
 
92
- Nanoc::Feature.define('profiler', version: '4.5')
92
+ Nanoc::Feature.define('profiler', version: '4.6')
@@ -10,9 +10,9 @@ module Nanoc::Int
10
10
 
11
11
  c_obj = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration, Nanoc::Int::CodeSnippet]
12
12
 
13
- contract C::KeywordArgs[objects: C::IterOf[c_obj]] => C::Any
14
- def initialize(objects:)
15
- super('tmp/checksums', 1)
13
+ contract C::KeywordArgs[site: C::Maybe[Nanoc::Int::Site], objects: C::IterOf[c_obj]] => C::Any
14
+ def initialize(site: nil, objects:)
15
+ super(Nanoc::Int::Store.tmp_path_for(site: site, store_name: 'checksums'), 1)
16
16
 
17
17
  @objects = objects
18
18
 
@@ -6,9 +6,9 @@ module Nanoc::Int
6
6
  class CompiledContentCache < ::Nanoc::Int::Store
7
7
  include Nanoc::Int::ContractsSupport
8
8
 
9
- contract C::KeywordArgs[items: C::IterOf[Nanoc::Int::Item]] => C::Any
10
- def initialize(items:)
11
- super('tmp/compiled_content', 2)
9
+ contract C::KeywordArgs[site: C::Maybe[Nanoc::Int::Site], items: C::IterOf[Nanoc::Int::Item]] => C::Any
10
+ def initialize(site: nil, items:)
11
+ super(Nanoc::Int::Store.tmp_path_for(site: site, store_name: 'compiled_content'), 2)
12
12
 
13
13
  @items = items
14
14
  @cache = {}
@@ -7,8 +7,8 @@ module Nanoc::Int
7
7
  attr_accessor :objects
8
8
 
9
9
  # @param [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] objects
10
- def initialize(objects)
11
- super('tmp/dependencies', 4)
10
+ def initialize(objects, site: nil)
11
+ super(Nanoc::Int::Store.tmp_path_for(site: site, store_name: 'dependencies'), 4)
12
12
 
13
13
  @objects = objects
14
14
  @new_objects = []
@@ -4,8 +4,8 @@ module Nanoc::Int
4
4
  include Nanoc::Int::ContractsSupport
5
5
 
6
6
  contract C::KeywordArgs[site: C::Maybe[Nanoc::Int::Site], reps: Nanoc::Int::ItemRepRepo] => C::Any
7
- def initialize(reps:)
8
- super('tmp/outdatedness', 1)
7
+ def initialize(site: nil, reps:)
8
+ super(Nanoc::Int::Store.tmp_path_for(site: site, store_name: 'outdatedness'), 1)
9
9
 
10
10
  @outdated_reps = Set.new
11
11
  @all_reps = reps
@@ -4,8 +4,8 @@ module Nanoc::Int
4
4
  #
5
5
  # @api private
6
6
  class RuleMemoryStore < ::Nanoc::Int::Store
7
- def initialize
8
- super('tmp/rule_memory', 1)
7
+ def initialize(site: nil)
8
+ super(Nanoc::Int::Store.tmp_path_for(site: site, store_name: 'rule_memory'), 1)
9
9
 
10
10
  @rule_memories = {}
11
11
  end
@@ -36,6 +36,20 @@ module Nanoc::Int
36
36
  @version = version
37
37
  end
38
38
 
39
+ # Logic for building tmp path from active environment and store name
40
+ # @api private
41
+ contract C::KeywordArgs[site: C::Maybe[Nanoc::Int::Site], store_name: String] => String
42
+ def self.tmp_path_for(store_name:, site:)
43
+ # FIXME: disallow site from being nil
44
+ output_dir = site ? site.config.output_dir : ''
45
+ File.join(tmp_path_prefix(output_dir), store_name)
46
+ end
47
+
48
+ def self.tmp_path_prefix(output_dir)
49
+ dir = Digest::SHA1.hexdigest(output_dir)[0..12]
50
+ File.join('tmp', 'nanoc', dir)
51
+ end
52
+
39
53
  # @group Loading and storing data
40
54
 
41
55
  # @return The data that should be written to the disk
@@ -347,6 +347,32 @@ module Nanoc::Int
347
347
  end
348
348
  end
349
349
  end
350
+
351
+ class Cleanup
352
+ def initialize(config)
353
+ @config = config
354
+ end
355
+
356
+ def run
357
+ cleanup_temps(Nanoc::Filter::TMP_BINARY_ITEMS_DIR)
358
+ cleanup_temps(Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR)
359
+ cleanup_unused_stores
360
+ end
361
+
362
+ private
363
+
364
+ def cleanup_temps(dir)
365
+ Nanoc::Int::TempFilenameFactory.instance.cleanup(dir)
366
+ end
367
+
368
+ def cleanup_unused_stores
369
+ used_paths = @config.output_dirs.map { |d| Nanoc::Int::Store.tmp_path_prefix(d) }
370
+ all_paths = Dir.glob('tmp/nanoc/*')
371
+ (all_paths - used_paths).each do |obsolete_path|
372
+ FileUtils.rm_rf(obsolete_path)
373
+ end
374
+ end
375
+ end
350
376
  end
351
377
 
352
378
  include Nanoc::Int::ContractsSupport
@@ -409,12 +435,7 @@ module Nanoc::Int
409
435
  store_output_state
410
436
  @action_provider.postprocess(@site, @reps)
411
437
  ensure
412
- Nanoc::Int::TempFilenameFactory.instance.cleanup(
413
- Nanoc::Filter::TMP_BINARY_ITEMS_DIR,
414
- )
415
- Nanoc::Int::TempFilenameFactory.instance.cleanup(
416
- Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR,
417
- )
438
+ cleanup_stage.run
418
439
  end
419
440
 
420
441
  def load_stores
@@ -495,6 +516,10 @@ module Nanoc::Int
495
516
  )
496
517
  end
497
518
 
519
+ def cleanup_stage
520
+ @_cleanup_stage ||= Stages::Cleanup.new(site.config)
521
+ end
522
+
498
523
  def determine_outdatedness
499
524
  determine_outdatedness_stage.run do |outdated_items|
500
525
  @outdated_items = outdated_items
@@ -2,22 +2,22 @@ module Nanoc::Int
2
2
  # @api private
3
3
  class CompilerLoader
4
4
  def load(site, action_provider: nil)
5
- rule_memory_store = Nanoc::Int::RuleMemoryStore.new
5
+ rule_memory_store = Nanoc::Int::RuleMemoryStore.new(site: site)
6
6
 
7
7
  dependency_store =
8
- Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a)
8
+ Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a, site: site)
9
9
 
10
10
  objects = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
11
11
 
12
12
  checksum_store =
13
- Nanoc::Int::ChecksumStore.new(objects: objects)
13
+ Nanoc::Int::ChecksumStore.new(site: site, objects: objects)
14
14
 
15
15
  item_rep_repo = Nanoc::Int::ItemRepRepo.new
16
16
 
17
17
  action_provider ||= Nanoc::Int::ActionProvider.named(:rule_dsl).for(site)
18
18
 
19
19
  outdatedness_store =
20
- Nanoc::Int::OutdatednessStore.new(reps: item_rep_repo)
20
+ Nanoc::Int::OutdatednessStore.new(site: site, reps: item_rep_repo)
21
21
 
22
22
  outdatedness_checker =
23
23
  Nanoc::Int::OutdatednessChecker.new(
@@ -30,7 +30,10 @@ module Nanoc::Int
30
30
  )
31
31
 
32
32
  compiled_content_cache =
33
- Nanoc::Int::CompiledContentCache.new(items: site.items)
33
+ Nanoc::Int::CompiledContentCache.new(
34
+ site: site,
35
+ items: site.items,
36
+ )
34
37
 
35
38
  params = {
36
39
  compiled_content_cache: compiled_content_cache,
@@ -46,6 +46,11 @@ module Nanoc
46
46
  @context.snapshot_repo.compiled_content(rep: unwrap, snapshot: snapshot)
47
47
  end
48
48
 
49
+ def snapshot?(name)
50
+ @context.dependency_tracker.bounce(unwrap.item, compiled_content: true)
51
+ @item_rep.snapshot?(name)
52
+ end
53
+
49
54
  # Returns the item rep’s path, as used when being linked to. It starts
50
55
  # with a slash and it is relative to the output directory. It does not
51
56
  # include the path to the output directory. It will not include the
@@ -13,6 +13,10 @@ module Nanoc
13
13
  end
14
14
  end
15
15
 
16
+ def raw_content=(arg)
17
+ unwrap.content = Nanoc::Int::Content.create(arg)
18
+ end
19
+
16
20
  # Sets the value for the given attribute.
17
21
  #
18
22
  # @param [Symbol] key
@@ -1,30 +1,18 @@
1
1
  module Nanoc::Helpers
2
2
  # @see http://nanoc.ws/doc/reference/helpers/#capturing
3
3
  module Capturing
4
- # @overload content_for(name, params = {}, &block)
5
- # @param [Symbol, String] name
6
- # @option params [Symbol] existing
7
- # @return [void]
8
- #
9
- # @overload content_for(item, name)
10
- # @param [Symbol, String] name
11
- # @return [String]
12
- def content_for(*args, &block)
13
- if block_given? # Set content
14
- # Get args
15
- case args.size
16
- when 1
17
- name = args[0]
18
- params = {}
19
- when 2
20
- name = args[0]
21
- params = args[1]
22
- else
23
- raise ArgumentError, 'expected 1 or 2 argument (the name ' \
24
- "of the capture, and optionally params) but got #{args.size} instead"
25
- end
26
- name = args[0]
27
- existing_behavior = params.fetch(:existing, :error)
4
+ # @api private
5
+ class SetContent
6
+ include Nanoc::Helpers::Capturing
7
+
8
+ def initialize(name, params, item)
9
+ @name = name
10
+ @params = params
11
+ @item = item
12
+ end
13
+
14
+ def run(&block)
15
+ existing_behavior = @params.fetch(:existing, :error)
28
16
 
29
17
  # Capture
30
18
  content_string = capture(&block)
@@ -32,7 +20,7 @@ module Nanoc::Helpers
32
20
  # Get existing contents and prep for store
33
21
  snapshot_repo = @item._context.snapshot_repo
34
22
  rep = @item.reps[:default].unwrap
35
- capture_name = "__capture_#{name}".to_sym
23
+ capture_name = "__capture_#{@name}".to_sym
36
24
  old_content_string =
37
25
  case existing_behavior
38
26
  when :overwrite
@@ -44,7 +32,7 @@ module Nanoc::Helpers
44
32
  contents = snapshot_repo.get(rep, capture_name)
45
33
  if contents && contents.string != content_string
46
34
  # FIXME: get proper exception
47
- raise "a capture named #{name.inspect} for #{@item.identifier} already exists"
35
+ raise "a capture named #{@name.inspect} for #{@item.identifier} already exists"
48
36
  else
49
37
  ''
50
38
  end
@@ -56,33 +44,104 @@ module Nanoc::Helpers
56
44
  # Store
57
45
  new_content = Nanoc::Int::TextualContent.new(old_content_string + content_string)
58
46
  snapshot_repo.set(rep, capture_name, new_content)
59
- else # Get content
60
- if args.size != 2
61
- raise ArgumentError, 'expected 2 arguments (the item ' \
62
- "and the name of the capture) but got #{args.size} instead"
63
- end
64
- item = args[0]
65
- name = args[1]
47
+ end
48
+ end
49
+
50
+ # @api private
51
+ class GetContent
52
+ def initialize(requested_item, name, item, config)
53
+ @requested_item = requested_item
54
+ @name = name
55
+ @item = item
56
+ @config = config
57
+ end
66
58
 
67
- rep = item.reps[:default].unwrap
59
+ def run
60
+ rep = @requested_item.reps[:default].unwrap
68
61
 
69
62
  # Create dependency
70
- if @item.nil? || item != @item.unwrap
63
+ if @item.nil? || @requested_item != @item.unwrap
71
64
  dependency_tracker = @config._context.dependency_tracker
72
- dependency_tracker.bounce(item.unwrap, compiled_content: true)
65
+ dependency_tracker.bounce(@requested_item.unwrap, compiled_content: true)
73
66
 
74
67
  unless rep.compiled?
75
68
  Fiber.yield(Nanoc::Int::Errors::UnmetDependency.new(rep))
76
- return content_for(*args, &block)
69
+ return run
77
70
  end
78
71
  end
79
72
 
80
73
  snapshot_repo = @config._context.snapshot_repo
81
- content = snapshot_repo.get(rep, "__capture_#{name}".to_sym)
74
+ content = snapshot_repo.get(rep, "__capture_#{@name}".to_sym)
82
75
  content ? content.string : nil
83
76
  end
84
77
  end
85
78
 
79
+ # @overload content_for(name, &block)
80
+ # @param [Symbol, String] name
81
+ # @return [void]
82
+ #
83
+ # @overload content_for(name, params, &block)
84
+ # @param [Symbol, String] name
85
+ # @option params [Symbol] existing
86
+ # @return [void]
87
+ #
88
+ # @overload content_for(name, content)
89
+ # @param [Symbol, String] name
90
+ # @param [String] content
91
+ # @return [void]
92
+ #
93
+ # @overload content_for(name, params, content)
94
+ # @param [Symbol, String] name
95
+ # @param [String] content
96
+ # @option params [Symbol] existing
97
+ # @return [void]
98
+ #
99
+ # @overload content_for(item, name)
100
+ # @param [Symbol, String] name
101
+ # @return [String]
102
+ def content_for(*args, &block)
103
+ if block_given? # Set content
104
+ name = args[0]
105
+ params =
106
+ case args.size
107
+ when 1
108
+ {}
109
+ when 2
110
+ args[1]
111
+ else
112
+ raise ArgumentError, 'expected 1 or 2 argument (the name ' \
113
+ "of the capture, and optionally params) but got #{args.size} instead"
114
+ end
115
+
116
+ SetContent.new(name, params, @item).run(&block)
117
+ elsif args.size > 1 && (args.first.is_a?(Symbol) || args.first.is_a?(String)) # Set content
118
+ name = args[0]
119
+ content = args.last
120
+ params =
121
+ case args.size
122
+ when 2
123
+ {}
124
+ when 3
125
+ args[1]
126
+ else
127
+ raise ArgumentError, 'expected 2 or 3 arguments (the name ' \
128
+ "of the capture, optionally params, and the content) but got #{args.size} instead"
129
+ end
130
+
131
+ _erbout = '' # rubocop:disable Lint/UnderscorePrefixedVariableName
132
+ SetContent.new(name, params, @item).run { _erbout << content }
133
+ else # Get content
134
+ if args.size != 2
135
+ raise ArgumentError, 'expected 2 arguments (the item ' \
136
+ "and the name of the capture) but got #{args.size} instead"
137
+ end
138
+ requested_item = args[0]
139
+ name = args[1]
140
+
141
+ GetContent.new(requested_item, name, @item, @config).run
142
+ end
143
+ end
144
+
86
145
  # @return [String]
87
146
  def capture(&block)
88
147
  # Get erbout so far
data/lib/nanoc/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Nanoc
2
2
  # The current Nanoc version.
3
- VERSION = '4.5.4'.freeze
3
+ VERSION = '4.6.0'.freeze
4
4
  end
@@ -20,7 +20,7 @@ describe Nanoc::Int::Compiler do
20
20
  let(:reps) { Nanoc::Int::ItemRepRepo.new }
21
21
 
22
22
  let(:outdatedness_checker) { double(:outdatedness_checker) }
23
- let(:outdatedness_store) { Nanoc::Int::OutdatednessStore.new(reps: reps) }
23
+ let(:outdatedness_store) { Nanoc::Int::OutdatednessStore.new(site: site, reps: reps) }
24
24
  let(:action_provider) { double(:action_provider) }
25
25
 
26
26
  let(:compiled_content_cache) { Nanoc::Int::CompiledContentCache.new(items: items) }
@@ -16,6 +16,74 @@ describe Nanoc::Int::Configuration do
16
16
  end
17
17
  end
18
18
 
19
+ describe '#with_defaults' do
20
+ subject { config.with_defaults }
21
+
22
+ context 'no env' do
23
+ it 'has a default output_dir' do
24
+ expect(subject[:output_dir]).to eql('output')
25
+ end
26
+ end
27
+
28
+ context 'env' do
29
+ let(:config) { described_class.new(hash: hash, env_name: 'giraffes') }
30
+
31
+ it 'retains the env name' do
32
+ expect(subject.env_name).to eql('giraffes')
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#output_dir' do
38
+ subject { config.with_defaults.output_dir }
39
+
40
+ context 'not explicitly defined' do
41
+ let(:hash) { { foo: 'bar' } }
42
+ it { is_expected.to eql('output') }
43
+ end
44
+
45
+ context 'explicitly defined, top-level' do
46
+ let(:hash) { { foo: 'bar', output_dir: 'build' } }
47
+ it { is_expected.to eql('build') }
48
+ end
49
+ end
50
+
51
+ describe '#output_dirs' do
52
+ subject { config.with_defaults.output_dirs }
53
+
54
+ let(:hash) do
55
+ {
56
+ output_dir: 'output_toplevel',
57
+ environments: {
58
+ default: {
59
+ output_dir: 'output_default',
60
+ },
61
+ production: {
62
+ output_dir: 'output_prod',
63
+ },
64
+ staging: {
65
+ output_dir: 'output_staging',
66
+ },
67
+ other: {},
68
+ },
69
+ }
70
+ end
71
+
72
+ it 'contains both top-level and default output dir' do
73
+ expect(subject).to include('output_toplevel')
74
+ expect(subject).to include('output_default')
75
+ end
76
+
77
+ it 'does not contain nil' do
78
+ expect(subject).not_to include(nil)
79
+ end
80
+
81
+ it 'contains all other output dirs' do
82
+ expect(subject).to include('output_staging')
83
+ expect(subject).to include('output_prod')
84
+ end
85
+ end
86
+
19
87
  context 'with environments defined' do
20
88
  let(:hash) { { foo: 'bar', environments: { test: { foo: 'test-bar' }, default: { foo: 'default-bar' } } } }
21
89
  let(:config) { described_class.new(hash: hash, env_name: env_name).with_environment }
@@ -1,4 +1,24 @@
1
1
  describe Nanoc::Int::ItemRep do
2
2
  let(:item) { Nanoc::Int::Item.new('asdf', {}, '/foo.md') }
3
3
  let(:rep) { Nanoc::Int::ItemRep.new(item, :giraffe) }
4
+
5
+ describe '#snapshot?' do
6
+ subject { rep.snapshot?(snapshot_name) }
7
+
8
+ let(:snapshot_name) { raise 'override me' }
9
+
10
+ before do
11
+ rep.snapshot_defs = [Nanoc::Int::SnapshotDef.new(:donkey)]
12
+ end
13
+
14
+ context 'snapshot does not exist' do
15
+ let(:snapshot_name) { :giraffe }
16
+ it { is_expected.not_to be }
17
+ end
18
+
19
+ context 'snapshot exists' do
20
+ let(:snapshot_name) { :donkey }
21
+ it { is_expected.to be }
22
+ end
23
+ end
4
24
  end
@@ -1,5 +1,5 @@
1
1
  describe Nanoc::Int::OutdatednessStore do
2
- subject(:store) { described_class.new(reps: reps) }
2
+ subject(:store) { described_class.new(site: site, reps: reps) }
3
3
 
4
4
  let(:site) { double(:site) }
5
5
  let(:reps) { Nanoc::Int::ItemRepRepo.new }
@@ -0,0 +1,53 @@
1
+ describe Nanoc::Int::Store do
2
+ describe '#tmp_path_for' do
3
+ context 'passing site' do
4
+ subject { described_class.tmp_path_for(site: site, store_name: 'giraffes') }
5
+
6
+ let(:site) do
7
+ Nanoc::Int::Site.new(config: config, code_snippets: code_snippets, items: items, layouts: layouts)
8
+ end
9
+
10
+ let(:code_snippets) { [] }
11
+ let(:items) { [] }
12
+ let(:layouts) { [] }
13
+
14
+ context 'no env specified' do
15
+ let(:config) { Nanoc::Int::Configuration.new(hash: config_hash).with_defaults.with_environment }
16
+
17
+ context 'output dir at root is specified' do
18
+ let(:config_hash) { { output_dir: 'output-default' } }
19
+ it { is_expected.to eql('tmp/nanoc/b592240c777c6/giraffes') }
20
+ end
21
+
22
+ context 'output dir in default env is specified' do
23
+ let(:config_hash) { { environments: { default: { output_dir: 'output-default' } } } }
24
+ it { is_expected.to eql('tmp/nanoc/b592240c777c6/giraffes') }
25
+ end
26
+
27
+ context 'output dir in other env is specified' do
28
+ let(:config_hash) { { environments: { production: { output_dir: 'output-production' } } } }
29
+ it { is_expected.to eql('tmp/nanoc/1029d67644815/giraffes') }
30
+ end
31
+ end
32
+
33
+ context 'env specified' do
34
+ let(:config) { Nanoc::Int::Configuration.new(env_name: 'staging', hash: config_hash).with_defaults.with_environment }
35
+
36
+ context 'output dir at root is specified' do
37
+ let(:config_hash) { { output_dir: 'output-default' } }
38
+ it { is_expected.to eql('tmp/nanoc/b592240c777c6/giraffes') }
39
+ end
40
+
41
+ context 'output dir in given env is specified' do
42
+ let(:config_hash) { { environments: { staging: { output_dir: 'output-staging' } } } }
43
+ it { is_expected.to eql('tmp/nanoc/9d274da4d73ba/giraffes') }
44
+ end
45
+
46
+ context 'output dir in other env is specified' do
47
+ let(:config_hash) { { environments: { production: { output_dir: 'output-production' } } } }
48
+ it { is_expected.to eql('tmp/nanoc/1029d67644815/giraffes') }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ describe Nanoc::Int::Compiler::Stages::Cleanup do
2
+ let(:stage) { described_class.new(config) }
3
+
4
+ let(:config) do
5
+ Nanoc::Int::Configuration.new.with_defaults
6
+ end
7
+
8
+ describe '#run' do
9
+ subject { stage.run }
10
+
11
+ example do
12
+ FileUtils.mkdir_p('tmp/nanoc/2f0692fb1a1d')
13
+ FileUtils.mkdir_p('tmp/nanoc/1a2195bfef6c')
14
+ FileUtils.mkdir_p('tmp/nanoc/1029d67644815')
15
+
16
+ expect { subject }
17
+ .to change { Dir.glob('tmp/nanoc/*').sort }
18
+ .from(['tmp/nanoc/1029d67644815', 'tmp/nanoc/1a2195bfef6c', 'tmp/nanoc/2f0692fb1a1d'])
19
+ .to(['tmp/nanoc/1029d67644815'])
20
+ end
21
+ end
22
+ end
@@ -137,6 +137,73 @@ describe Nanoc::ItemRepView do
137
137
  it { should == described_class.hash ^ Nanoc::Identifier.new('/foo/').hash ^ :jacques.hash }
138
138
  end
139
139
 
140
+ describe '#snapshot?' do
141
+ subject { view.snapshot?(snapshot_name) }
142
+
143
+ let(:view) { described_class.new(rep, view_context) }
144
+
145
+ let(:rep) do
146
+ Nanoc::Int::ItemRep.new(item, :default).tap do |ir|
147
+ ir.compiled = true
148
+ ir.snapshot_defs = [
149
+ Nanoc::Int::SnapshotDef.new(:last),
150
+ ]
151
+ end
152
+ end
153
+
154
+ let(:item) do
155
+ Nanoc::Int::Item.new('content', {}, '/asdf.md')
156
+ end
157
+
158
+ let(:snapshot_name) { raise 'override me' }
159
+
160
+ before do
161
+ snapshot_repo.set(rep, :last, Nanoc::Int::TextualContent.new('Hallo'))
162
+ end
163
+
164
+ context 'snapshot exists' do
165
+ let(:snapshot_name) { :last }
166
+
167
+ it 'creates a dependency' do
168
+ expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
169
+ end
170
+
171
+ it 'creates a dependency with the right props' do
172
+ subject
173
+ dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
174
+
175
+ expect(dep.props.compiled_content?).to eq(true)
176
+
177
+ expect(dep.props.raw_content?).to eq(false)
178
+ expect(dep.props.attributes?).to eq(false)
179
+ expect(dep.props.path?).to eq(false)
180
+ end
181
+
182
+ it { is_expected.to be }
183
+ end
184
+
185
+ context 'snapshot does not exist' do
186
+ let(:snapshot_name) { :donkey }
187
+
188
+ it 'creates a dependency' do
189
+ expect { subject }.to change { dependency_store.objects_causing_outdatedness_of(base_item) }.from([]).to([item])
190
+ end
191
+
192
+ it 'creates a dependency with the right props' do
193
+ subject
194
+ dep = dependency_store.dependencies_causing_outdatedness_of(base_item)[0]
195
+
196
+ expect(dep.props.compiled_content?).to eq(true)
197
+
198
+ expect(dep.props.raw_content?).to eq(false)
199
+ expect(dep.props.attributes?).to eq(false)
200
+ expect(dep.props.path?).to eq(false)
201
+ end
202
+
203
+ it { is_expected.not_to be }
204
+ end
205
+ end
206
+
140
207
  describe '#compiled_content' do
141
208
  subject { view.compiled_content }
142
209
 
@@ -14,6 +14,17 @@ shared_examples 'a mutable document view' do
14
14
  let(:dependency_tracker) { Nanoc::Int::DependencyTracker.new(double(:dependency_store)) }
15
15
  let(:snapshot_repo) { double(:snapshot_repo) }
16
16
 
17
+ describe '#raw_content=' do
18
+ let(:document) { entity_class.new('content', {}, '/asdf/') }
19
+
20
+ it 'sets raw content' do
21
+ expect { view.raw_content = 'donkey' }
22
+ .to change { document.content.string }
23
+ .from('content')
24
+ .to('donkey')
25
+ end
26
+ end
27
+
17
28
  describe '#[]=' do
18
29
  let(:document) { entity_class.new('content', {}, '/asdf/') }
19
30
 
@@ -5,68 +5,122 @@ describe Nanoc::Helpers::Capturing, helper: true do
5
5
  ctx.create_rep(ctx.item, '/about.html')
6
6
  end
7
7
 
8
- describe 'with name + block' do
8
+ describe 'setting content' do
9
9
  let(:_erbout) { 'existing content' }
10
10
 
11
- context 'only name given' do
12
- subject { helper.content_for(:foo) { _erbout << 'foo' } }
11
+ let(:params) { raise 'overwrite me' }
13
12
 
14
- it 'stores snapshot content' do
15
- subject
16
- expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('foo')
13
+ let(:contents_enumerator) { %w(foo bar).to_enum }
14
+
15
+ shared_examples 'setting content' do
16
+ context 'only name given' do
17
+ subject { subject_proc_without_params.call }
18
+
19
+ it 'stores snapshot content' do
20
+ subject
21
+ expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('foo')
22
+ end
17
23
  end
18
- end
19
24
 
20
- context 'name and params given' do
21
- subject { helper.content_for(:foo, params) { _erbout << 'foo' } }
22
- let(:params) { raise 'overwrite me' }
25
+ context 'name and params given' do
26
+ subject { subject_proc_with_params.call }
27
+ let(:params) { raise 'overwrite me' }
23
28
 
24
- context 'no existing behavior specified' do
25
- let(:params) { {} }
29
+ context 'no existing behavior specified' do
30
+ let(:params) { {} }
26
31
 
27
- it 'errors after two times' do
28
- helper.content_for(:foo, params) { _erbout << 'foo' }
29
- expect { helper.content_for(:foo, params) { _erbout << 'bar' } }.to raise_error(RuntimeError)
32
+ it 'errors after two times' do
33
+ subject_proc_with_params.call
34
+ expect { subject_proc_with_params.call }.to raise_error(RuntimeError)
35
+ end
30
36
  end
31
- end
32
37
 
33
- context 'existing behavior is :overwrite' do
34
- let(:params) { { existing: :overwrite } }
38
+ context 'existing behavior is :overwrite' do
39
+ let(:params) { { existing: :overwrite } }
35
40
 
36
- it 'overwrites' do
37
- helper.content_for(:foo, params) { _erbout << 'foo' }
38
- helper.content_for(:foo, params) { _erbout << 'bar' }
39
- expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('bar')
41
+ it 'overwrites' do
42
+ subject_proc_with_params.call
43
+ subject_proc_with_params.call
44
+ expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('bar')
45
+ end
40
46
  end
41
- end
42
47
 
43
- context 'existing behavior is :append' do
44
- let(:params) { { existing: :append } }
48
+ context 'existing behavior is :append' do
49
+ let(:params) { { existing: :append } }
45
50
 
46
- it 'appends' do
47
- helper.content_for(:foo, params) { _erbout << 'foo' }
48
- helper.content_for(:foo, params) { _erbout << 'bar' }
49
- expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('foobar')
51
+ it 'appends' do
52
+ subject_proc_with_params.call
53
+ subject_proc_with_params.call
54
+ expect(ctx.snapshot_repo.get(ctx.item.reps[:default].unwrap, :__capture_foo).string).to eql('foobar')
55
+ end
50
56
  end
51
- end
52
57
 
53
- context 'existing behavior is :error' do
54
- let(:params) { { existing: :error } }
58
+ context 'existing behavior is :error' do
59
+ let(:params) { { existing: :error } }
55
60
 
56
- it 'errors after two times' do
57
- helper.content_for(:foo, params) { _erbout << 'foo' }
58
- expect { helper.content_for(:foo, params) { _erbout << 'bar' } }.to raise_error(RuntimeError)
61
+ it 'errors after two times' do
62
+ subject_proc_with_params.call
63
+ expect { subject_proc_with_params.call }.to raise_error(RuntimeError)
64
+ end
59
65
  end
60
- end
61
66
 
62
- context 'existing behavior is :something else' do
63
- let(:params) { { existing: :donkey } }
67
+ context 'existing behavior is :something else' do
68
+ let(:params) { { existing: :donkey } }
64
69
 
65
- it 'errors' do
66
- expect { subject }.to raise_error(ArgumentError)
70
+ it 'errors' do
71
+ expect { subject }.to raise_error(ArgumentError)
72
+ end
67
73
  end
68
74
  end
69
75
  end
76
+
77
+ context 'symbol name + block' do
78
+ let(:subject_proc_without_params) do
79
+ -> { helper.content_for(:foo) { _erbout << contents_enumerator.next } }
80
+ end
81
+
82
+ let(:subject_proc_with_params) do
83
+ -> { helper.content_for(:foo, params) { _erbout << contents_enumerator.next } }
84
+ end
85
+
86
+ include_examples 'setting content'
87
+ end
88
+
89
+ context 'string name + block' do
90
+ let(:subject_proc_without_params) do
91
+ -> { helper.content_for('foo') { _erbout << contents_enumerator.next } }
92
+ end
93
+
94
+ let(:subject_proc_with_params) do
95
+ -> { helper.content_for('foo', params) { _erbout << contents_enumerator.next } }
96
+ end
97
+
98
+ include_examples 'setting content'
99
+ end
100
+
101
+ context 'symbol name + string' do
102
+ let(:subject_proc_without_params) do
103
+ -> { helper.content_for(:foo, contents_enumerator.next) }
104
+ end
105
+
106
+ let(:subject_proc_with_params) do
107
+ -> { helper.content_for(:foo, params, contents_enumerator.next) }
108
+ end
109
+
110
+ include_examples 'setting content'
111
+ end
112
+
113
+ context 'string name + string' do
114
+ let(:subject_proc_without_params) do
115
+ -> { helper.content_for('foo', contents_enumerator.next) }
116
+ end
117
+
118
+ let(:subject_proc_with_params) do
119
+ -> { helper.content_for('foo', params, contents_enumerator.next) }
120
+ end
121
+
122
+ include_examples 'setting content'
123
+ end
70
124
  end
71
125
 
72
126
  describe 'with item + name' do
@@ -103,6 +157,21 @@ describe Nanoc::Helpers::Capturing, helper: true do
103
157
  expect(ctx.dependency_tracker).to receive(:bounce).with(item.unwrap, compiled_content: true)
104
158
  expect { subject }.to raise_error(FiberError)
105
159
  end
160
+
161
+ it 're-runs when fiber is resumed' do
162
+ expect(ctx.dependency_tracker).to receive(:bounce).with(item.unwrap, compiled_content: true).twice
163
+
164
+ fiber = Fiber.new { subject }
165
+ expect(fiber.resume).to be_a(Nanoc::Int::Errors::UnmetDependency)
166
+
167
+ item.reps[:default].unwrap.compiled = true
168
+ ctx.snapshot_repo.set(
169
+ item.reps[:default].unwrap,
170
+ :__capture_foo,
171
+ Nanoc::Int::TextualContent.new('content after compilation'),
172
+ )
173
+ expect(fiber.resume).to eql('content after compilation')
174
+ end
106
175
  end
107
176
 
108
177
  context 'other item is compiled' do
@@ -17,14 +17,14 @@ class Nanoc::Int::CompilerTest < Nanoc::TestCase
17
17
 
18
18
  params = {
19
19
  compiled_content_cache: Nanoc::Int::CompiledContentCache.new(items: site.items),
20
- checksum_store: Nanoc::Int::ChecksumStore.new(objects: objects),
20
+ checksum_store: Nanoc::Int::ChecksumStore.new(site: site, objects: objects),
21
21
  rule_memory_store: Nanoc::Int::RuleMemoryStore.new,
22
22
  dependency_store: Nanoc::Int::DependencyStore.new(
23
23
  site.items.to_a + site.layouts.to_a,
24
24
  ),
25
25
  action_provider: action_provider,
26
26
  reps: reps,
27
- outdatedness_store: Nanoc::Int::OutdatednessStore.new(reps: reps),
27
+ outdatedness_store: Nanoc::Int::OutdatednessStore.new(site: site, reps: reps),
28
28
  }
29
29
 
30
30
  params[:outdatedness_checker] =
@@ -34,7 +34,7 @@ class Nanoc::Int::OutdatednessCheckerTest < Nanoc::TestCase
34
34
 
35
35
  # Delete checksums
36
36
  with_site(name: 'foo') do |_site|
37
- FileUtils.rm('tmp/checksums')
37
+ Dir['tmp/nanoc/*/checksums'].each { |fn| FileUtils.rm(fn) }
38
38
  end
39
39
 
40
40
  # Check
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.4
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-16 00:00:00.000000000 Z
11
+ date: 2017-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cri
@@ -351,7 +351,9 @@ files:
351
351
  - spec/nanoc/base/repos/outdatedness_store_spec.rb
352
352
  - spec/nanoc/base/repos/site_loader_spec.rb
353
353
  - spec/nanoc/base/repos/snapshot_repo_spec.rb
354
+ - spec/nanoc/base/repos/store_spec.rb
354
355
  - spec/nanoc/base/services/compiler/phases/cache_spec.rb
356
+ - spec/nanoc/base/services/compiler/stages/cleanup_spec.rb
355
357
  - spec/nanoc/base/services/dependency_tracker_spec.rb
356
358
  - spec/nanoc/base/services/executor_spec.rb
357
359
  - spec/nanoc/base/services/item_rep_router_spec.rb
@@ -566,7 +568,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
566
568
  version: '0'
567
569
  requirements: []
568
570
  rubyforge_project:
569
- rubygems_version: 2.6.8
571
+ rubygems_version: 2.6.9
570
572
  signing_key:
571
573
  specification_version: 4
572
574
  summary: A static-site generator with a focus on flexibility.