nanoc 4.5.4 → 4.6.0

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