nanoc 4.8.18 → 4.8.19

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
  SHA256:
3
- metadata.gz: 42c6429f3ab75c70a0616b03c8658442b860f3238e626e3b7a41e21b93558bc6
4
- data.tar.gz: 329c3e49d8813363facc58726517a330821866d2ef6dac20279aa61800c0c617
3
+ metadata.gz: 77b1cd3570e8e94e5d17d18bf9954f0ac8d8a45e48f4e3d2f7d39cbdc8a2e3ff
4
+ data.tar.gz: a5a95e6ab7be8df7c016fdd659bac76734965ed9aed677110647ae7d0cfa19b8
5
5
  SHA512:
6
- metadata.gz: 3caf2cc5572e4ccc9615ab06487391f6d691e4dbe9bb08d600f20f2f20284c827a7ce1fd6325e7ed5cd785d16d19b6e77380a2134fa505dd27f11c91defb780b
7
- data.tar.gz: 71c7a650d30c2d29ba5a38b8fc2eee74596102506dbc44956a733f914d1c7b58b87bdd0ac5603788eae03758b3ef8ebae6c65c3102b3743e68e17354846b0f0d
6
+ metadata.gz: 5860e580a17a5ed72590cb7c81eb6b6e1649e5c2973a322ed1ca544af0faa4a37de23343151a6dbbe730cd022b9d58f54feae6546c7f243e7c359bc2e3f1ea2a
7
+ data.tar.gz: e8642774bd3d54418ae6c78392dedca7eecbc80b2d06d7e83aa9a579ab35074a06de192420476b1ca7dfb48e29f2c7fc3b809925faedb23cb5522b89f170b9f0
data/NEWS.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.8.19 (2018-01-01)
4
+
5
+ Enhancements:
6
+
7
+ * Made `write nil` skip routing rule (#1286)
8
+
3
9
  ## 4.8.18 (2017-12-28)
4
10
 
5
11
  Enhancements:
@@ -27,6 +27,11 @@ module Nanoc
27
27
  def self.on_windows?
28
28
  RUBY_PLATFORM =~ /windows|bccwin|cygwin|djgpp|mingw|mswin|wince/i
29
29
  end
30
+
31
+ # Similar to `nil` except that it can only be compared against using
32
+ # `UNDEFINED.equal?(x)`. Used in places where `nil` already has meaning, and
33
+ # thus cannot be used to mean the presence of nothing.
34
+ UNDEFINED = Object.new
30
35
  end
31
36
 
32
37
  # Load general requirements
@@ -51,7 +51,15 @@ module Nanoc::Int
51
51
 
52
52
  def respond_to_missing?(method, include_all)
53
53
  ivar_name = '@' + method.to_s
54
- instance_variable_defined?(ivar_name) || super
54
+
55
+ valid_ivar_name =
56
+ if defined?(Contracts)
57
+ ivar_name =~ /\A@[A-Za-z_]+\z/
58
+ else
59
+ true # probably good enough
60
+ end
61
+
62
+ (valid_ivar_name && instance_variable_defined?(ivar_name)) || super
55
63
  end
56
64
 
57
65
  def include(mod)
@@ -98,7 +98,7 @@ module Nanoc::Int
98
98
  StringUpdateBehavior
99
99
  when Nanoc::View
100
100
  UnwrapUpdateBehavior
101
- when Nanoc::RuleDSL::RuleContext
101
+ when Nanoc::RuleDSL::CompilationRuleContext
102
102
  RuleContextUpdateBehavior
103
103
  when Nanoc::Int::Context
104
104
  ContextUpdateBehavior
@@ -379,114 +379,13 @@ module Nanoc::DataSources
379
379
  end
380
380
  end
381
381
 
382
- # @return [ParseResult]
383
382
  def parse(content_filename, meta_filename)
384
- if meta_filename
385
- parse_with_separate_meta_filename(content_filename, meta_filename)
386
- else
387
- parse_with_frontmatter(content_filename)
388
- end
389
- end
390
-
391
- # @return [ParseResult]
392
- def parse_with_separate_meta_filename(content_filename, meta_filename)
393
- content = content_filename ? read(content_filename) : ''
394
- meta_raw = read(meta_filename)
395
- meta = parse_metadata(meta_raw, meta_filename)
396
- ParseResult.new(content: content, attributes: meta, attributes_data: meta_raw)
397
- end
398
-
399
- SEPARATOR = /(-{5}|-{3})/.source
400
-
401
- # @return [ParseResult]
402
- def parse_with_frontmatter(content_filename)
403
- data = read(content_filename)
404
-
405
- if data !~ /\A#{SEPARATOR}\s*$/
406
- return ParseResult.new(content: data, attributes: {}, attributes_data: '')
407
- end
408
-
409
- pieces = data.split(/^#{SEPARATOR}[ \t]*\r?\n?/, 3)
410
- if pieces.size < 4
411
- raise Errors::InvalidFormat.new(content_filename)
412
- end
413
-
414
- meta = parse_metadata(pieces[2], content_filename)
415
- content = pieces[4]
416
-
417
- ParseResult.new(content: content, attributes: meta, attributes_data: pieces[2])
418
- end
419
-
420
- # @return [Hash]
421
- def parse_metadata(data, filename)
422
- begin
423
- meta = YAML.load(data) || {}
424
- rescue => e
425
- raise Errors::UnparseableMetadata.new(filename, e)
426
- end
427
-
428
- verify_meta(meta, filename)
429
-
430
- meta
431
- end
432
-
433
- class ParseResult
434
- attr_reader :content
435
- attr_reader :attributes
436
- attr_reader :attributes_data
437
-
438
- def initialize(content:, attributes:, attributes_data:)
439
- @content = content
440
- @attributes = attributes
441
- @attributes_data = attributes_data
442
- end
443
- end
444
-
445
- def verify_meta(meta, filename)
446
- return if meta.is_a?(Hash)
447
-
448
- raise Errors::InvalidMetadata.new(filename, meta.class)
449
- end
450
-
451
- # Reads the content of the file with the given name and returns a string
452
- # in UTF-8 encoding. The original encoding of the string is derived from
453
- # the default external encoding, but this can be overridden by the
454
- # “encoding” configuration attribute in the data source configuration.
455
- def read(filename)
456
- # Read
457
- begin
458
- data = File.read(filename)
459
- rescue => e
460
- raise Errors::FileUnreadable.new(filename, e)
461
- end
462
-
463
- # Set original encoding, if any
464
- if @config && @config[:encoding]
465
- original_encoding = Encoding.find(@config[:encoding])
466
- data.force_encoding(@config[:encoding])
467
- else
468
- original_encoding = data.encoding
469
- end
470
-
471
- # Set encoding to UTF-8
472
- begin
473
- data.encode!('UTF-8')
474
- rescue
475
- raise Errors::InvalidEncoding.new(filename, original_encoding)
476
- end
477
-
478
- # Verify
479
- unless data.valid_encoding?
480
- raise Errors::InvalidEncoding.new(filename, original_encoding)
481
- end
482
-
483
- # Remove UTF-8 BOM (ugly)
484
- data.delete!("\xEF\xBB\xBF")
485
-
486
- data
383
+ parser = Parser.new(config: @config)
384
+ parser.call(content_filename, meta_filename)
487
385
  end
488
386
  end
489
387
  end
490
388
 
491
389
  require_relative 'filesystem/tools'
492
390
  require_relative 'filesystem/errors'
391
+ require_relative 'filesystem/parser'
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ class Nanoc::DataSources::Filesystem
5
+ class Parser
6
+ SEPARATOR = /(-{5}|-{3})/.source
7
+
8
+ class ParseResult
9
+ attr_reader :content
10
+ attr_reader :attributes
11
+ attr_reader :attributes_data
12
+
13
+ def initialize(content:, attributes:, attributes_data:)
14
+ @content = content
15
+ @attributes = attributes
16
+ @attributes_data = attributes_data
17
+ end
18
+ end
19
+
20
+ def initialize(config:)
21
+ @config = config
22
+ end
23
+
24
+ # @return [ParseResult]
25
+ def call(content_filename, meta_filename)
26
+ if meta_filename
27
+ parse_with_separate_meta_filename(content_filename, meta_filename)
28
+ else
29
+ parse_with_frontmatter(content_filename)
30
+ end
31
+ end
32
+
33
+ # @return [ParseResult]
34
+ def parse_with_separate_meta_filename(content_filename, meta_filename)
35
+ content = content_filename ? Tools.read_file(content_filename, config: @config) : ''
36
+ meta_raw = Tools.read_file(meta_filename, config: @config)
37
+ meta = parse_metadata(meta_raw, meta_filename)
38
+ ParseResult.new(content: content, attributes: meta, attributes_data: meta_raw)
39
+ end
40
+
41
+ # @return [ParseResult]
42
+ def parse_with_frontmatter(content_filename)
43
+ data = Tools.read_file(content_filename, config: @config)
44
+
45
+ if data !~ /\A#{SEPARATOR}\s*$/
46
+ return ParseResult.new(content: data, attributes: {}, attributes_data: '')
47
+ end
48
+
49
+ pieces = data.split(/^#{SEPARATOR}[ \t]*\r?\n?/, 3)
50
+ if pieces.size < 4
51
+ raise Errors::InvalidFormat.new(content_filename)
52
+ end
53
+
54
+ meta = parse_metadata(pieces[2], content_filename)
55
+ content = pieces[4]
56
+
57
+ ParseResult.new(content: content, attributes: meta, attributes_data: pieces[2])
58
+ end
59
+
60
+ # @return [Hash]
61
+ def parse_metadata(data, filename)
62
+ begin
63
+ meta = YAML.load(data) || {}
64
+ rescue => e
65
+ raise Errors::UnparseableMetadata.new(filename, e)
66
+ end
67
+
68
+ verify_meta(meta, filename)
69
+
70
+ meta
71
+ end
72
+
73
+ def verify_meta(meta, filename)
74
+ return if meta.is_a?(Hash)
75
+ raise Errors::InvalidMetadata.new(filename, meta.class)
76
+ end
77
+ end
78
+ end
@@ -148,5 +148,44 @@ class Nanoc::DataSources::Filesystem < Nanoc::DataSource
148
148
  end
149
149
  end
150
150
  module_function :resolve_symlink
151
+
152
+ # Reads the content of the file with the given name and returns a string
153
+ # in UTF-8 encoding. The original encoding of the string is derived from
154
+ # the default external encoding, but this can be overridden by the
155
+ # “encoding” configuration attribute in the data source configuration.
156
+ def read_file(filename, config:)
157
+ # Read
158
+ begin
159
+ data = File.read(filename)
160
+ rescue => e
161
+ raise Errors::FileUnreadable.new(filename, e)
162
+ end
163
+
164
+ # Set original encoding, if any
165
+ if config && config[:encoding]
166
+ original_encoding = Encoding.find(config[:encoding])
167
+ data.force_encoding(config[:encoding])
168
+ else
169
+ original_encoding = data.encoding
170
+ end
171
+
172
+ # Set encoding to UTF-8
173
+ begin
174
+ data.encode!('UTF-8')
175
+ rescue
176
+ raise Errors::InvalidEncoding.new(filename, original_encoding)
177
+ end
178
+
179
+ # Verify
180
+ unless data.valid_encoding?
181
+ raise Errors::InvalidEncoding.new(filename, original_encoding)
182
+ end
183
+
184
+ # Remove UTF-8 BOM (ugly)
185
+ data.delete!("\xEF\xBB\xBF")
186
+
187
+ data
188
+ end
189
+ module_function :read_file
151
190
  end
152
191
  end
@@ -1,10 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ module Nanoc
4
+ # @api private
5
+ module RuleDSL
6
+ end
7
+ end
8
+
3
9
  require_relative 'rule_dsl/compiler_dsl'
4
10
  require_relative 'rule_dsl/action_provider'
5
- require_relative 'rule_dsl/recording_executor'
6
- require_relative 'rule_dsl/rule_context'
11
+ require_relative 'rule_dsl/action_recorder'
7
12
  require_relative 'rule_dsl/action_sequence_calculator'
8
- require_relative 'rule_dsl/rule'
9
13
  require_relative 'rule_dsl/rules_collection'
10
14
  require_relative 'rule_dsl/rules_loader'
15
+
16
+ require_relative 'rule_dsl/rule_context'
17
+ require_relative 'rule_dsl/compilation_rule_context'
18
+ require_relative 'rule_dsl/routing_rule_context'
19
+
20
+ require_relative 'rule_dsl/rule'
21
+ require_relative 'rule_dsl/compilation_rule'
22
+ require_relative 'rule_dsl/routing_rule'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Nanoc
4
4
  module RuleDSL
5
- class RecordingExecutor
5
+ class ActionRecorder
6
6
  include Nanoc::Int::ContractsSupport
7
7
 
8
8
  contract Nanoc::Int::ItemRep => C::Any
@@ -12,6 +12,7 @@ module Nanoc
12
12
  @any_layouts = false
13
13
  @last_snapshot = false
14
14
  @pre_snapshot = false
15
+ @skip_routing_rule = false
15
16
  end
16
17
 
17
18
  def inspect
@@ -36,10 +37,19 @@ module Nanoc
36
37
  @any_layouts = true
37
38
  end
38
39
 
39
- Pathlike = C::Maybe[C::Or[String, Nanoc::Identifier]]
40
- contract Symbol, C::KeywordArgs[path: C::Optional[Pathlike]] => nil
41
- def snapshot(snapshot_name, path: nil)
42
- @action_sequence_builder.add_snapshot(snapshot_name, path&.to_s)
40
+ MaybePathlike = C::Or[nil, Nanoc::UNDEFINED, String, Nanoc::Identifier]
41
+ contract Symbol, C::KeywordArgs[path: C::Optional[MaybePathlike]] => nil
42
+ def snapshot(snapshot_name, path: Nanoc::UNDEFINED)
43
+ @skip_routing_rule = path.nil?
44
+
45
+ path =
46
+ if Nanoc::UNDEFINED.equal?(path) || path.nil?
47
+ nil
48
+ else
49
+ path.to_s
50
+ end
51
+
52
+ @action_sequence_builder.add_snapshot(snapshot_name, path)
43
53
  case snapshot_name
44
54
  when :last
45
55
  @last_snapshot = true
@@ -59,6 +69,11 @@ module Nanoc
59
69
  @any_layouts
60
70
  end
61
71
 
72
+ contract C::None => C::Bool
73
+ def skip_routing_rule?
74
+ @skip_routing_rule
75
+ end
76
+
62
77
  contract C::None => C::Bool
63
78
  def last_snapshot?
64
79
  @last_snapshot
@@ -1,10 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::RuleDSL
4
- # Calculates action sequences for objects that can be run through a rule (item
5
- # representations and layouts).
6
- #
7
- # @api private
8
4
  class ActionSequenceCalculator
9
5
  DDMemoize.activate(self)
10
6
 
@@ -60,20 +56,20 @@ module Nanoc::RuleDSL
60
56
  view_context =
61
57
  Nanoc::ViewContextForPreCompilation.new(items: @site.items)
62
58
 
63
- executor = Nanoc::RuleDSL::RecordingExecutor.new(rep)
59
+ recorder = Nanoc::RuleDSL::ActionRecorder.new(rep)
64
60
  rule = @rules_collection.compilation_rule_for(rep)
65
61
 
66
62
  unless rule
67
63
  raise NoActionSequenceForItemRepException.new(rep)
68
64
  end
69
65
 
70
- executor.snapshot(:raw)
71
- rule.apply_to(rep, executor: executor, site: @site, view_context: view_context)
72
- executor.snapshot(:post) if executor.any_layouts?
73
- executor.snapshot(:last) unless executor.last_snapshot?
74
- executor.snapshot(:pre) unless executor.pre_snapshot?
66
+ recorder.snapshot(:raw)
67
+ rule.apply_to(rep, recorder: recorder, site: @site, view_context: view_context)
68
+ recorder.snapshot(:post) if recorder.any_layouts?
69
+ recorder.snapshot(:last) unless recorder.last_snapshot?
70
+ recorder.snapshot(:pre) unless recorder.pre_snapshot?
75
71
 
76
- copy_paths_from_routing_rules(compact_snapshots(executor.action_sequence), rep: rep)
72
+ copy_paths_from_routing_rules(compact_snapshots(recorder.action_sequence), rep: rep)
77
73
  end
78
74
 
79
75
  # @param [Nanoc::Int::Layout] layout
@@ -138,7 +134,6 @@ module Nanoc::RuleDSL
138
134
  basic_path =
139
135
  routing_rule.apply_to(
140
136
  rep,
141
- executor: nil,
142
137
  site: @site,
143
138
  view_context: view_context,
144
139
  )
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc::RuleDSL
4
+ class CompilationRule < Rule
5
+ include Nanoc::Int::ContractsSupport
6
+
7
+ contract Nanoc::Int::ItemRep, C::KeywordArgs[
8
+ site: Nanoc::Int::Site,
9
+ recorder: Nanoc::RuleDSL::ActionRecorder,
10
+ view_context: Nanoc::ViewContextForPreCompilation,
11
+ ] => C::Any
12
+ def apply_to(rep, site:, recorder:, view_context:)
13
+ context = Nanoc::RuleDSL::CompilationRuleContext.new(
14
+ rep: rep,
15
+ recorder: recorder,
16
+ site: site,
17
+ view_context: view_context,
18
+ )
19
+
20
+ context.instance_exec(matches(rep.item.identifier), &@block)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc::RuleDSL
4
+ class CompilationRuleContext < RuleContext
5
+ include Nanoc::Int::ContractsSupport
6
+
7
+ contract C::KeywordArgs[
8
+ rep: Nanoc::Int::ItemRep,
9
+ site: Nanoc::Int::Site,
10
+ recorder: Nanoc::RuleDSL::ActionRecorder,
11
+ view_context: Nanoc::ViewContextForPreCompilation,
12
+ ] => C::Any
13
+ def initialize(rep:, site:, recorder:, view_context:)
14
+ @_recorder = recorder
15
+
16
+ super(rep: rep, site: site, view_context: view_context)
17
+ end
18
+
19
+ # Filters the current representation (calls {Nanoc::Int::ItemRep#filter} with
20
+ # the given arguments on the rep).
21
+ #
22
+ # @see Nanoc::Int::ItemRep#filter
23
+ #
24
+ # @param [Symbol] filter_name The name of the filter to run the item
25
+ # representations' content through
26
+ #
27
+ # @param [Hash] filter_args The filter arguments that should be passed to
28
+ # the filter's #run method
29
+ #
30
+ # @return [void]
31
+ def filter(filter_name, filter_args = {})
32
+ @_recorder.filter(filter_name, filter_args)
33
+ end
34
+
35
+ # Layouts the current representation (calls {Nanoc::Int::ItemRep#layout} with
36
+ # the given arguments on the rep).
37
+ #
38
+ # @see Nanoc::Int::ItemRep#layout
39
+ #
40
+ # @param [String] layout_identifier The identifier of the layout the item
41
+ # should be laid out with
42
+ #
43
+ # @return [void]
44
+ def layout(layout_identifier, extra_filter_args = nil)
45
+ @_recorder.layout(layout_identifier, extra_filter_args)
46
+ end
47
+
48
+ # Creates a snapshot of the current compiled item content. Calls
49
+ # {Nanoc::Int::ItemRep#snapshot} with the given arguments on the rep.
50
+ #
51
+ # @see Nanoc::Int::ItemRep#snapshot
52
+ #
53
+ # @param [Symbol] snapshot_name The name of the snapshot to create
54
+ #
55
+ # @param [String, nil] path
56
+ #
57
+ # @return [void]
58
+ def snapshot(snapshot_name, path: Nanoc::UNDEFINED)
59
+ @_recorder.snapshot(snapshot_name, path: path)
60
+ end
61
+
62
+ # Creates a snapshot named :last the current compiled item content, with
63
+ # the given path. This is a convenience method for {#snapshot}.
64
+ #
65
+ # @see #snapshot
66
+ #
67
+ # @param [String] path
68
+ #
69
+ # @return [void]
70
+ def write(arg)
71
+ @_write_snapshot_counter ||= 0
72
+ snapshot_name = "_#{@_write_snapshot_counter}".to_sym
73
+ @_write_snapshot_counter += 1
74
+
75
+ case arg
76
+ when String, Nanoc::Identifier, nil
77
+ snapshot(snapshot_name, path: arg)
78
+ when Hash
79
+ if arg.key?(:ext)
80
+ ext = arg[:ext].sub(/\A\./, '')
81
+ path = @item.identifier.without_exts + '.' + ext
82
+ snapshot(snapshot_name, path: path)
83
+ else
84
+ raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
85
+ end
86
+ else
87
+ raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::RuleDSL
4
- # Contains methods that will be executed by the site’s `Rules` file.
5
- #
6
- # @api private
7
4
  class CompilerDSL < Nanoc::Int::Context
8
5
  # The current rules filename.
9
6
  #
@@ -74,7 +71,7 @@ module Nanoc::RuleDSL
74
71
  def compile(identifier, rep: :default, &block)
75
72
  raise ArgumentError.new('#compile requires a block') unless block_given?
76
73
 
77
- rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, block)
74
+ rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, block)
78
75
  @rules_collection.add_item_compilation_rule(rule)
79
76
  end
80
77
 
@@ -114,7 +111,7 @@ module Nanoc::RuleDSL
114
111
  def route(identifier, rep: :default, snapshot: :last, &block)
115
112
  raise ArgumentError.new('#route requires a block') unless block_given?
116
113
 
117
- rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, block, snapshot_name: snapshot)
114
+ rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, block, snapshot_name: snapshot)
118
115
  @rules_collection.add_item_routing_rule(rule)
119
116
  end
120
117
 
@@ -173,7 +170,7 @@ module Nanoc::RuleDSL
173
170
  raise ArgumentError.new('#passthrough does not require a block') if block_given?
174
171
 
175
172
  compilation_block = proc {}
176
- compilation_rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, compilation_block)
173
+ compilation_rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, compilation_block)
177
174
  @rules_collection.add_item_compilation_rule(compilation_rule)
178
175
 
179
176
  # Create routing rule
@@ -188,7 +185,7 @@ module Nanoc::RuleDSL
188
185
  item[:extension].nil? || (item[:content_filename].nil? && item.identifier =~ %r{#{item[:extension]}/$}) ? item.identifier.chop : item.identifier.chop + '.' + item[:extension]
189
186
  end
190
187
  end
191
- routing_rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, routing_block, snapshot_name: :last)
188
+ routing_rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, routing_block, snapshot_name: :last)
192
189
  @rules_collection.add_item_routing_rule(routing_rule)
193
190
  end
194
191
 
@@ -213,10 +210,10 @@ module Nanoc::RuleDSL
213
210
  def ignore(identifier, rep: :default)
214
211
  raise ArgumentError.new('#ignore does not require a block') if block_given?
215
212
 
216
- compilation_rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, proc {})
213
+ compilation_rule = Nanoc::RuleDSL::CompilationRule.new(create_pattern(identifier), rep, proc {})
217
214
  @rules_collection.add_item_compilation_rule(compilation_rule)
218
215
 
219
- routing_rule = Nanoc::RuleDSL::Rule.new(create_pattern(identifier), rep, proc {}, snapshot_name: :last)
216
+ routing_rule = Nanoc::RuleDSL::RoutingRule.new(create_pattern(identifier), rep, proc {}, snapshot_name: :last)
220
217
  @rules_collection.add_item_routing_rule(routing_rule)
221
218
  end
222
219
 
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc::RuleDSL
4
+ class RoutingRule < Rule
5
+ include Nanoc::Int::ContractsSupport
6
+
7
+ contract C::None => C::Maybe[Symbol]
8
+ attr_reader :snapshot_name
9
+
10
+ contract Nanoc::Int::Pattern, Symbol, Proc, C::KeywordArgs[snapshot_name: C::Optional[Symbol]] => C::Any
11
+ def initialize(pattern, rep_name, block, snapshot_name: nil)
12
+ super(pattern, rep_name, block)
13
+
14
+ @snapshot_name = snapshot_name
15
+ end
16
+
17
+ contract Nanoc::Int::ItemRep, C::KeywordArgs[
18
+ site: Nanoc::Int::Site,
19
+ view_context: Nanoc::ViewContextForPreCompilation,
20
+ ] => C::Any
21
+ def apply_to(rep, site:, view_context:)
22
+ context = Nanoc::RuleDSL::RoutingRuleContext.new(
23
+ rep: rep, site: site, view_context: view_context,
24
+ )
25
+
26
+ context.instance_exec(matches(rep.item.identifier), &@block)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc::RuleDSL
4
+ class RoutingRuleContext < RuleContext
5
+ end
6
+ end
@@ -1,77 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::RuleDSL
4
- # Contains the processing information for a item.
5
- #
6
- # @api private
7
4
  class Rule
8
5
  include Nanoc::Int::ContractsSupport
9
6
 
10
- # @return [Symbol] The name of the representation that will be compiled
11
- # using this rule
7
+ contract C::None => Symbol
12
8
  attr_reader :rep_name
13
9
 
14
- # @return [Symbol] The name of the snapshot this rule will apply to.
15
- # Ignored for compilation rules, but used for routing rules.
16
- attr_reader :snapshot_name
17
-
10
+ contract C::None => Nanoc::Int::Pattern
18
11
  attr_reader :pattern
19
12
 
20
- # Creates a new item compilation rule with the given identifier regex,
21
- # compiler and block. The block will be called during compilation with the
22
- # item rep as its argument.
23
- #
24
- # @param [Nanoc::Int::Pattern] pattern
25
- #
26
- # @param [String, Symbol] rep_name The name of the item representation
27
- # where this rule can be applied to
28
- #
29
- # @param [Proc] block A block that will be called when matching items are
30
- # compiled
31
- #
32
- # @param [Symbol, nil] snapshot_name The name of the snapshot this rule will
33
- # apply to. Ignored for compilation rules, but used for routing rules.
34
- def initialize(pattern, rep_name, block, snapshot_name: nil)
13
+ contract Nanoc::Int::Pattern, Symbol, Proc => C::Any
14
+ def initialize(pattern, rep_name, block)
35
15
  @pattern = pattern
36
16
  @rep_name = rep_name.to_sym
37
- @snapshot_name = snapshot_name
38
17
  @block = block
39
18
  end
40
19
 
41
- # @param [Nanoc::Int::Item] item The item to check
42
- #
43
- # @return [Boolean] true if this rule can be applied to the given item
44
- # rep, false otherwise
20
+ contract Nanoc::Int::Item => C::Bool
45
21
  def applicable_to?(item)
46
22
  @pattern.match?(item.identifier)
47
23
  end
48
24
 
49
- contract Nanoc::Int::ItemRep, C::KeywordArgs[
50
- site: Nanoc::Int::Site,
51
- executor: C::Or[nil, Nanoc::Int::Executor, Nanoc::RuleDSL::RecordingExecutor],
52
- view_context: Nanoc::ViewContextForPreCompilation,
53
- ] => C::Any
54
- def apply_to(rep, site:, executor:, view_context:)
55
- # FIXME: allowing executor to be nil is ugly
56
-
57
- context = Nanoc::RuleDSL::RuleContext.new(
58
- rep: rep,
59
- executor: executor,
60
- site: site,
61
- view_context: view_context,
62
- )
63
-
64
- context.instance_exec(matches(rep.item.identifier), &@block)
65
- end
66
-
67
- protected
68
-
69
- # Matches the rule regexp against items identifier and gives back group
70
- # captures if any
71
- #
72
- # @param [String] identifier Identifier to capture groups for
73
- #
74
- # @return [nil, Array] Captured groups, if any
25
+ # @api private
26
+ contract Nanoc::Identifier => C::Or[nil, C::ArrayOf[String]]
75
27
  def matches(identifier)
76
28
  @pattern.captures(identifier)
77
29
  end
@@ -1,19 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::RuleDSL
4
- # Provides a context in which compilation and routing rules can be executed.
5
- # It provides access to the item representation that is being compiled or
6
- # routed.
7
- #
8
- # @api private
9
4
  class RuleContext < Nanoc::Int::Context
10
- # @param [Nanoc::Int::ItemRep] rep
11
- # @param [Nanoc::Int::Site] site
12
- # @param [Nanoc::Int::Executor, Nanoc::RuleDSL::RecordingExecutor] executor
13
- # @param [Nanoc::ViewContextForCompilation] view_context
14
- def initialize(rep:, site:, executor:, view_context:)
15
- @_executor = executor
5
+ include Nanoc::Int::ContractsSupport
16
6
 
7
+ contract C::KeywordArgs[
8
+ rep: Nanoc::Int::ItemRep,
9
+ site: Nanoc::Int::Site,
10
+ view_context: Nanoc::ViewContextForPreCompilation,
11
+ ] => C::Any
12
+ def initialize(rep:, site:, view_context:)
17
13
  super({
18
14
  item: Nanoc::BasicItemView.new(rep.item, view_context),
19
15
  rep: Nanoc::BasicItemRepView.new(rep, view_context),
@@ -23,77 +19,5 @@ module Nanoc::RuleDSL
23
19
  config: Nanoc::ConfigView.new(site.config, view_context),
24
20
  })
25
21
  end
26
-
27
- # Filters the current representation (calls {Nanoc::Int::ItemRep#filter} with
28
- # the given arguments on the rep).
29
- #
30
- # @see Nanoc::Int::ItemRep#filter
31
- #
32
- # @param [Symbol] filter_name The name of the filter to run the item
33
- # representations' content through
34
- #
35
- # @param [Hash] filter_args The filter arguments that should be passed to
36
- # the filter's #run method
37
- #
38
- # @return [void]
39
- def filter(filter_name, filter_args = {})
40
- @_executor.filter(filter_name, filter_args)
41
- end
42
-
43
- # Layouts the current representation (calls {Nanoc::Int::ItemRep#layout} with
44
- # the given arguments on the rep).
45
- #
46
- # @see Nanoc::Int::ItemRep#layout
47
- #
48
- # @param [String] layout_identifier The identifier of the layout the item
49
- # should be laid out with
50
- #
51
- # @return [void]
52
- def layout(layout_identifier, extra_filter_args = nil)
53
- @_executor.layout(layout_identifier, extra_filter_args)
54
- end
55
-
56
- # Creates a snapshot of the current compiled item content. Calls
57
- # {Nanoc::Int::ItemRep#snapshot} with the given arguments on the rep.
58
- #
59
- # @see Nanoc::Int::ItemRep#snapshot
60
- #
61
- # @param [Symbol] snapshot_name The name of the snapshot to create
62
- #
63
- # @param [String, nil] path
64
- #
65
- # @return [void]
66
- def snapshot(snapshot_name, path: nil)
67
- @_executor.snapshot(snapshot_name, path: path)
68
- end
69
-
70
- # Creates a snapshot named :last the current compiled item content, with
71
- # the given path. This is a convenience method for {#snapshot}.
72
- #
73
- # @see #snapshot
74
- #
75
- # @param [String] path
76
- #
77
- # @return [void]
78
- def write(arg)
79
- @_write_snapshot_counter ||= 0
80
- snapshot_name = "_#{@_write_snapshot_counter}".to_sym
81
- @_write_snapshot_counter += 1
82
-
83
- case arg
84
- when String, Nanoc::Identifier
85
- snapshot(snapshot_name, path: arg)
86
- when Hash
87
- if arg.key?(:ext)
88
- ext = arg[:ext].sub(/\A\./, '')
89
- path = @item.identifier.without_exts + '.' + ext
90
- snapshot(snapshot_name, path: path)
91
- else
92
- raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
93
- end
94
- else
95
- raise ArgumentError, 'Cannot call #write this way (need path or :ext)'
96
- end
97
- end
98
22
  end
99
23
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nanoc::RuleDSL
4
- # @api private
5
4
  class RulesLoader
6
5
  def initialize(config, rules_collection)
7
6
  @dsl = Nanoc::RuleDSL::CompilerDSL.new(rules_collection, config)
@@ -24,6 +24,20 @@ module Nanoc
24
24
  def skip_unless_have_command(cmd)
25
25
  skip "Could not find external command \"#{cmd}\"" unless command?(cmd)
26
26
  end
27
+
28
+ def sleep_until(max: 3.0)
29
+ start = Time.now
30
+ loop do
31
+ diff = (Time.now - start).to_f
32
+ if diff > max
33
+ raise "Waited for #{diff}s for condition to become true, but it never did"
34
+ end
35
+
36
+ break if yield
37
+
38
+ sleep 0.1
39
+ end
40
+ end
27
41
  end
28
42
 
29
43
  class HelperContext
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nanoc
4
4
  # The current Nanoc version.
5
- VERSION = '4.8.18'
5
+ VERSION = '4.8.19'
6
6
  end
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.8.18
4
+ version: 4.8.19
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-12-28 00:00:00.000000000 Z
11
+ date: 2018-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -314,6 +314,7 @@ files:
314
314
  - lib/nanoc/data_sources.rb
315
315
  - lib/nanoc/data_sources/filesystem.rb
316
316
  - lib/nanoc/data_sources/filesystem/errors.rb
317
+ - lib/nanoc/data_sources/filesystem/parser.rb
317
318
  - lib/nanoc/data_sources/filesystem/tools.rb
318
319
  - lib/nanoc/deploying.rb
319
320
  - lib/nanoc/deploying/deployer.rb
@@ -375,9 +376,13 @@ files:
375
376
  - lib/nanoc/helpers/xml_sitemap.rb
376
377
  - lib/nanoc/rule_dsl.rb
377
378
  - lib/nanoc/rule_dsl/action_provider.rb
379
+ - lib/nanoc/rule_dsl/action_recorder.rb
378
380
  - lib/nanoc/rule_dsl/action_sequence_calculator.rb
381
+ - lib/nanoc/rule_dsl/compilation_rule.rb
382
+ - lib/nanoc/rule_dsl/compilation_rule_context.rb
379
383
  - lib/nanoc/rule_dsl/compiler_dsl.rb
380
- - lib/nanoc/rule_dsl/recording_executor.rb
384
+ - lib/nanoc/rule_dsl/routing_rule.rb
385
+ - lib/nanoc/rule_dsl/routing_rule_context.rb
381
386
  - lib/nanoc/rule_dsl/rule.rb
382
387
  - lib/nanoc/rule_dsl/rule_context.rb
383
388
  - lib/nanoc/rule_dsl/rules_collection.rb