bridgetown-core 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +42 -0
  3. data/bridgetown-core.gemspec +46 -0
  4. data/lib/bridgetown-core.rb +202 -0
  5. data/lib/bridgetown-core/cache.rb +190 -0
  6. data/lib/bridgetown-core/cleaner.rb +111 -0
  7. data/lib/bridgetown-core/collection.rb +279 -0
  8. data/lib/bridgetown-core/command.rb +106 -0
  9. data/lib/bridgetown-core/commands/build.rb +96 -0
  10. data/lib/bridgetown-core/commands/clean.rb +43 -0
  11. data/lib/bridgetown-core/commands/console.rb +56 -0
  12. data/lib/bridgetown-core/commands/doctor.rb +172 -0
  13. data/lib/bridgetown-core/commands/help.rb +34 -0
  14. data/lib/bridgetown-core/commands/new.rb +148 -0
  15. data/lib/bridgetown-core/commands/serve.rb +273 -0
  16. data/lib/bridgetown-core/commands/serve/servlet.rb +68 -0
  17. data/lib/bridgetown-core/configuration.rb +323 -0
  18. data/lib/bridgetown-core/converter.rb +54 -0
  19. data/lib/bridgetown-core/converters/identity.rb +39 -0
  20. data/lib/bridgetown-core/converters/markdown.rb +108 -0
  21. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +132 -0
  22. data/lib/bridgetown-core/converters/smartypants.rb +69 -0
  23. data/lib/bridgetown-core/convertible.rb +237 -0
  24. data/lib/bridgetown-core/deprecator.rb +50 -0
  25. data/lib/bridgetown-core/document.rb +475 -0
  26. data/lib/bridgetown-core/drops/bridgetown_drop.rb +32 -0
  27. data/lib/bridgetown-core/drops/collection_drop.rb +20 -0
  28. data/lib/bridgetown-core/drops/document_drop.rb +69 -0
  29. data/lib/bridgetown-core/drops/drop.rb +215 -0
  30. data/lib/bridgetown-core/drops/excerpt_drop.rb +19 -0
  31. data/lib/bridgetown-core/drops/page_drop.rb +14 -0
  32. data/lib/bridgetown-core/drops/site_drop.rb +62 -0
  33. data/lib/bridgetown-core/drops/static_file_drop.rb +14 -0
  34. data/lib/bridgetown-core/drops/unified_payload_drop.rb +26 -0
  35. data/lib/bridgetown-core/drops/url_drop.rb +132 -0
  36. data/lib/bridgetown-core/entry_filter.rb +108 -0
  37. data/lib/bridgetown-core/errors.rb +20 -0
  38. data/lib/bridgetown-core/excerpt.rb +202 -0
  39. data/lib/bridgetown-core/external.rb +62 -0
  40. data/lib/bridgetown-core/filters.rb +467 -0
  41. data/lib/bridgetown-core/filters/date_filters.rb +110 -0
  42. data/lib/bridgetown-core/filters/grouping_filters.rb +64 -0
  43. data/lib/bridgetown-core/filters/url_filters.rb +79 -0
  44. data/lib/bridgetown-core/frontmatter_defaults.rb +238 -0
  45. data/lib/bridgetown-core/generator.rb +5 -0
  46. data/lib/bridgetown-core/hooks.rb +103 -0
  47. data/lib/bridgetown-core/layout.rb +57 -0
  48. data/lib/bridgetown-core/liquid_extensions.rb +22 -0
  49. data/lib/bridgetown-core/liquid_renderer.rb +71 -0
  50. data/lib/bridgetown-core/liquid_renderer/file.rb +67 -0
  51. data/lib/bridgetown-core/liquid_renderer/table.rb +75 -0
  52. data/lib/bridgetown-core/log_adapter.rb +151 -0
  53. data/lib/bridgetown-core/log_writer.rb +60 -0
  54. data/lib/bridgetown-core/mime.types +867 -0
  55. data/lib/bridgetown-core/page.rb +214 -0
  56. data/lib/bridgetown-core/page_without_a_file.rb +14 -0
  57. data/lib/bridgetown-core/path_manager.rb +31 -0
  58. data/lib/bridgetown-core/plugin.rb +80 -0
  59. data/lib/bridgetown-core/plugin_manager.rb +60 -0
  60. data/lib/bridgetown-core/publisher.rb +23 -0
  61. data/lib/bridgetown-core/reader.rb +185 -0
  62. data/lib/bridgetown-core/readers/collection_reader.rb +22 -0
  63. data/lib/bridgetown-core/readers/data_reader.rb +75 -0
  64. data/lib/bridgetown-core/readers/layout_reader.rb +48 -0
  65. data/lib/bridgetown-core/readers/page_reader.rb +24 -0
  66. data/lib/bridgetown-core/readers/post_reader.rb +74 -0
  67. data/lib/bridgetown-core/readers/static_file_reader.rb +24 -0
  68. data/lib/bridgetown-core/regenerator.rb +195 -0
  69. data/lib/bridgetown-core/related_posts.rb +52 -0
  70. data/lib/bridgetown-core/renderer.rb +261 -0
  71. data/lib/bridgetown-core/site.rb +469 -0
  72. data/lib/bridgetown-core/static_file.rb +205 -0
  73. data/lib/bridgetown-core/tags/component.rb +34 -0
  74. data/lib/bridgetown-core/tags/highlight.rb +111 -0
  75. data/lib/bridgetown-core/tags/include.rb +220 -0
  76. data/lib/bridgetown-core/tags/link.rb +41 -0
  77. data/lib/bridgetown-core/tags/post_url.rb +107 -0
  78. data/lib/bridgetown-core/url.rb +164 -0
  79. data/lib/bridgetown-core/utils.rb +367 -0
  80. data/lib/bridgetown-core/utils/ansi.rb +57 -0
  81. data/lib/bridgetown-core/utils/exec.rb +26 -0
  82. data/lib/bridgetown-core/utils/internet.rb +37 -0
  83. data/lib/bridgetown-core/utils/platforms.rb +80 -0
  84. data/lib/bridgetown-core/utils/thread_event.rb +31 -0
  85. data/lib/bridgetown-core/utils/win_tz.rb +75 -0
  86. data/lib/bridgetown-core/version.rb +5 -0
  87. data/lib/bridgetown-core/watcher.rb +139 -0
  88. data/lib/site_template/.gitignore +6 -0
  89. data/lib/site_template/bridgetown.config.yml +21 -0
  90. data/lib/site_template/frontend/javascript/index.js +3 -0
  91. data/lib/site_template/frontend/styles/index.scss +17 -0
  92. data/lib/site_template/package.json +23 -0
  93. data/lib/site_template/src/404.html +9 -0
  94. data/lib/site_template/src/_data/site_metadata.yml +11 -0
  95. data/lib/site_template/src/_includes/footer.html +3 -0
  96. data/lib/site_template/src/_includes/head.html +9 -0
  97. data/lib/site_template/src/_includes/navbar.html +4 -0
  98. data/lib/site_template/src/_layouts/default.html +15 -0
  99. data/lib/site_template/src/_layouts/home.html +7 -0
  100. data/lib/site_template/src/_layouts/page.html +7 -0
  101. data/lib/site_template/src/_layouts/post.html +7 -0
  102. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +26 -0
  103. data/lib/site_template/src/about.md +11 -0
  104. data/lib/site_template/src/index.md +7 -0
  105. data/lib/site_template/webpack.config.js +60 -0
  106. data/rake/release.rake +30 -0
  107. metadata +106 -1
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Deprecator
5
+ extend self
6
+
7
+ def process(args)
8
+ arg_is_present? args, "--server", "The --server command has been replaced by the \
9
+ 'serve' subcommand."
10
+ arg_is_present? args, "--serve", "The --serve command has been replaced by the \
11
+ 'serve' subcommand."
12
+ arg_is_present? args, "--no-server", "To build Bridgetown without launching a server, \
13
+ use the 'build' subcommand."
14
+ arg_is_present? args, "--auto", "The switch '--auto' has been replaced with \
15
+ '--watch'."
16
+ arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \
17
+ the '--watch' switch."
18
+ arg_is_present? args, "--pygments", "The 'pygments'settings has been removed in \
19
+ favour of 'highlighter'."
20
+ arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in \
21
+ your config files."
22
+ arg_is_present? args, "--url", "The 'url' setting can only be set in your \
23
+ config files."
24
+ no_subcommand(args)
25
+ end
26
+
27
+ def no_subcommand(args)
28
+ unless args.empty? ||
29
+ args.first !~ %r(!/^--/!) || %w(--help --version).include?(args.first)
30
+ deprecation_message "Bridgetown now uses subcommands instead of just switches. \
31
+ Run `bridgetown help` to find out more."
32
+ abort
33
+ end
34
+ end
35
+
36
+ def arg_is_present?(args, deprecated_argument, message)
37
+ deprecation_message(message) if args.include?(deprecated_argument)
38
+ end
39
+
40
+ def deprecation_message(message)
41
+ Bridgetown.logger.warn "Deprecation:", message
42
+ end
43
+
44
+ def defaults_deprecate_type(old, current)
45
+ Bridgetown.logger.warn "Defaults:", "The '#{old}' type has become '#{current}'."
46
+ Bridgetown.logger.warn "Defaults:", "Please update your front-matter defaults to use \
47
+ 'type: #{current}'."
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,475 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ class Document
5
+ include Comparable
6
+ extend Forwardable
7
+
8
+ attr_reader :path, :site, :extname, :collection, :type
9
+ attr_accessor :content, :output
10
+
11
+ def_delegator :self, :read_post_data, :post_read
12
+
13
+ YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m.freeze
14
+ DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
15
+ DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze
16
+
17
+ YAML_FILE_EXTS = %w(.yaml .yml).freeze
18
+
19
+ #
20
+
21
+ # Class-wide cache to stash and retrieve regexp to detect "super-directories"
22
+ # of a particular Bridgetown::Document object.
23
+ #
24
+ # dirname - The *special directory* for the Document.
25
+ # e.g. "_posts" for Documents from the `site.posts` collection.
26
+ def self.superdirs_regex(dirname)
27
+ @superdirs_regex ||= {}
28
+ @superdirs_regex[dirname] ||= %r!#{dirname}.*!
29
+ end
30
+
31
+ #
32
+
33
+ # Create a new Document.
34
+ #
35
+ # path - the path to the file
36
+ # relations - a hash with keys :site and :collection, the values of which
37
+ # are the Bridgetown::Site and Bridgetown::Collection to which this
38
+ # Document belong.
39
+ #
40
+ # Returns nothing.
41
+ def initialize(path, relations = {})
42
+ @site = relations[:site]
43
+ @path = path
44
+ @extname = File.extname(path)
45
+ @collection = relations[:collection]
46
+ @type = @collection.label.to_sym
47
+
48
+ @has_yaml_header = nil
49
+
50
+ data.default_proc = proc do |_, key|
51
+ site.frontmatter_defaults.find(relative_path, type, key)
52
+ end
53
+
54
+ trigger_hooks(:post_init)
55
+ end
56
+
57
+ # Fetch the Document's data.
58
+ #
59
+ # Returns a Hash containing the data. An empty hash is returned if
60
+ # no data was read.
61
+ def data
62
+ @data ||= {}
63
+ end
64
+
65
+ # Merge some data in with this document's data.
66
+ #
67
+ # Returns the merged data.
68
+ def merge_data!(other, source: "YAML front matter")
69
+ merge_categories!(other)
70
+ Utils.deep_merge_hashes!(data, other)
71
+ merge_date!(source)
72
+ data
73
+ end
74
+
75
+ # Returns the document date. If metadata is not present then calculates it
76
+ # based on Bridgetown::Site#time or the document file modification time.
77
+ #
78
+ # Return document date string.
79
+ def date
80
+ data["date"] ||= site.time
81
+ end
82
+
83
+ # Return document file modification time in the form of a Time object.
84
+ #
85
+ # Return document file modification Time object.
86
+ def source_file_mtime
87
+ File.mtime(path)
88
+ end
89
+
90
+ # The path to the document, relative to the collections_dir.
91
+ #
92
+ # Returns a String path which represents the relative path from the collections_dir
93
+ # to this document.
94
+ def relative_path
95
+ @relative_path ||= path.sub("#{site.collections_path}/", "")
96
+ end
97
+
98
+ # The output extension of the document.
99
+ #
100
+ # Returns the output extension
101
+ def output_ext
102
+ @output_ext ||= Bridgetown::Renderer.new(site, self).output_ext
103
+ end
104
+
105
+ # The base filename of the document, without the file extname.
106
+ #
107
+ # Returns the basename without the file extname.
108
+ def basename_without_ext
109
+ @basename_without_ext ||= File.basename(path, ".*")
110
+ end
111
+
112
+ # The base filename of the document.
113
+ #
114
+ # Returns the base filename of the document.
115
+ def basename
116
+ @basename ||= File.basename(path)
117
+ end
118
+
119
+ # Produces a "cleaned" relative path.
120
+ # The "cleaned" relative path is the relative path without the extname
121
+ # and with the collection's directory removed as well.
122
+ # This method is useful when building the URL of the document.
123
+ #
124
+ # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`)
125
+ #
126
+ # Examples:
127
+ # When relative_path is "_methods/site/generate...md":
128
+ # cleaned_relative_path
129
+ # # => "/site/generate"
130
+ #
131
+ # Returns the cleaned relative path of the document.
132
+ def cleaned_relative_path
133
+ @cleaned_relative_path ||=
134
+ relative_path[0..-extname.length - 1]
135
+ .sub(collection.relative_directory, "")
136
+ .gsub(%r!\.*\z!, "")
137
+ end
138
+
139
+ # Determine whether the document is a YAML file.
140
+ #
141
+ # Returns true if the extname is either .yml or .yaml, false otherwise.
142
+ def yaml_file?
143
+ YAML_FILE_EXTS.include?(extname)
144
+ end
145
+
146
+ # TODO: Depricated
147
+ # Used to determine CoffeeScript and Sass/SCSS files.
148
+ def asset_file?
149
+ false
150
+ end
151
+
152
+ # Determine whether the file should be rendered with Liquid.
153
+ #
154
+ # Returns false if the document is either an asset file or a yaml file,
155
+ # or if the document doesn't contain any Liquid Tags or Variables,
156
+ # true otherwise.
157
+ def render_with_liquid?
158
+ return false if data["render_with_liquid"] == false
159
+
160
+ !(yaml_file? || !Utils.has_liquid_construct?(content))
161
+ end
162
+
163
+ # Determine whether the file should be rendered with a layout.
164
+ #
165
+ # Returns true if the Front Matter specifies that `layout` is set to `none`.
166
+ def no_layout?
167
+ data["layout"] == "none"
168
+ end
169
+
170
+ # Determine whether the file should be placed into layouts.
171
+ #
172
+ # Returns false if the document is set to `layouts: none`, or is either an
173
+ # asset file or a yaml file. Returns true otherwise.
174
+ def place_in_layout?
175
+ !(asset_file? || yaml_file? || no_layout?)
176
+ end
177
+
178
+ # The URL template where the document would be accessible.
179
+ #
180
+ # Returns the URL template for the document.
181
+ def url_template
182
+ collection.url_template
183
+ end
184
+
185
+ # Construct a Hash of key-value pairs which contain a mapping between
186
+ # a key in the URL template and the corresponding value for this document.
187
+ #
188
+ # Returns the Hash of key-value pairs for replacement in the URL.
189
+ def url_placeholders
190
+ @url_placeholders ||= Drops::UrlDrop.new(self)
191
+ end
192
+
193
+ # The permalink for this Document.
194
+ # Permalink is set via the data Hash.
195
+ #
196
+ # Returns the permalink or nil if no permalink was set in the data.
197
+ def permalink
198
+ data && data.is_a?(Hash) && data["permalink"]
199
+ end
200
+
201
+ # The computed URL for the document. See `Bridgetown::URL#to_s` for more details.
202
+ #
203
+ # Returns the computed URL for the document.
204
+ def url
205
+ @url ||= URL.new(
206
+ :template => url_template,
207
+ :placeholders => url_placeholders,
208
+ :permalink => permalink
209
+ ).to_s
210
+ end
211
+
212
+ def [](key)
213
+ data[key]
214
+ end
215
+
216
+ # The full path to the output file.
217
+ #
218
+ # base_directory - the base path of the output directory
219
+ #
220
+ # Returns the full path to the output file of this document.
221
+ def destination(base_directory)
222
+ dest = site.in_dest_dir(base_directory)
223
+ path = site.in_dest_dir(dest, URL.unescape_path(url))
224
+ if url.end_with? "/"
225
+ path = File.join(path, "index.html")
226
+ else
227
+ path << output_ext unless path.end_with? output_ext
228
+ end
229
+ path
230
+ end
231
+
232
+ # Write the generated Document file to the destination directory.
233
+ #
234
+ # dest - The String path to the destination dir.
235
+ #
236
+ # Returns nothing.
237
+ def write(dest)
238
+ path = destination(dest)
239
+ FileUtils.mkdir_p(File.dirname(path))
240
+ Bridgetown.logger.debug "Writing:", path
241
+ File.write(path, output, :mode => "wb")
242
+
243
+ trigger_hooks(:post_write)
244
+ end
245
+
246
+ # Whether the file is published or not, as indicated in YAML front-matter
247
+ #
248
+ # Returns 'false' if the 'published' key is specified in the
249
+ # YAML front-matter and is 'false'. Otherwise returns 'true'.
250
+ def published?
251
+ !(data.key?("published") && data["published"] == false)
252
+ end
253
+
254
+ # Read in the file and assign the content and data based on the file contents.
255
+ # Merge the frontmatter of the file with the frontmatter default
256
+ # values
257
+ #
258
+ # Returns nothing.
259
+ def read(opts = {})
260
+ Bridgetown.logger.debug "Reading:", relative_path
261
+
262
+ if yaml_file?
263
+ @data = SafeYAML.load_file(path)
264
+ else
265
+ begin
266
+ merge_defaults
267
+ read_content(**opts)
268
+ read_post_data
269
+ rescue StandardError => e
270
+ handle_read_error(e)
271
+ end
272
+ end
273
+ end
274
+
275
+ # Create a Liquid-understandable version of this Document.
276
+ #
277
+ # Returns a Hash representing this Document's data.
278
+ def to_liquid
279
+ @to_liquid ||= Drops::DocumentDrop.new(self)
280
+ end
281
+
282
+ # The inspect string for this document.
283
+ # Includes the relative path and the collection label.
284
+ #
285
+ # Returns the inspect string for this document.
286
+ def inspect
287
+ "#<#{self.class} #{relative_path} collection=#{collection.label}>"
288
+ end
289
+
290
+ # The string representation for this document.
291
+ #
292
+ # Returns the content of the document
293
+ def to_s
294
+ output || content || "NO CONTENT"
295
+ end
296
+
297
+ # Compare this document against another document.
298
+ # Comparison is a comparison between the 2 paths of the documents.
299
+ #
300
+ # Returns -1, 0, +1 or nil depending on whether this doc's path is less than,
301
+ # equal or greater than the other doc's path. See String#<=> for more details.
302
+ def <=>(other)
303
+ return nil unless other.respond_to?(:data)
304
+
305
+ cmp = data["date"] <=> other.data["date"]
306
+ cmp = path <=> other.path if cmp.nil? || cmp.zero?
307
+ cmp
308
+ end
309
+
310
+ # Determine whether this document should be written.
311
+ # Based on the Collection to which it belongs.
312
+ #
313
+ # True if the document has a collection and if that collection's #write?
314
+ # method returns true, and if the site's Publisher will publish the document.
315
+ # False otherwise.
316
+ def write?
317
+ collection&.write? && site.publisher.publish?(self)
318
+ end
319
+
320
+ # The Document excerpt_separator, from the YAML Front-Matter or site
321
+ # default excerpt_separator value
322
+ #
323
+ # Returns the document excerpt_separator
324
+ def excerpt_separator
325
+ @excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s
326
+ end
327
+
328
+ # Whether to generate an excerpt
329
+ #
330
+ # Returns true if the excerpt separator is configured.
331
+ def generate_excerpt?
332
+ !excerpt_separator.empty?
333
+ end
334
+
335
+ def next_doc
336
+ pos = collection.docs.index { |post| post.equal?(self) }
337
+ collection.docs[pos + 1] if pos && pos < collection.docs.length - 1
338
+ end
339
+
340
+ def previous_doc
341
+ pos = collection.docs.index { |post| post.equal?(self) }
342
+ collection.docs[pos - 1] if pos && pos.positive?
343
+ end
344
+
345
+ def trigger_hooks(hook_name, *args)
346
+ Bridgetown::Hooks.trigger collection.label.to_sym, hook_name, self, *args if collection
347
+ Bridgetown::Hooks.trigger :documents, hook_name, self, *args
348
+ end
349
+
350
+ def id
351
+ @id ||= File.join(File.dirname(url), (data["slug"] || basename_without_ext).to_s)
352
+ end
353
+
354
+ # Calculate related posts.
355
+ #
356
+ # Returns an Array of related Posts.
357
+ def related_posts
358
+ @related_posts ||= Bridgetown::RelatedPosts.new(self).build
359
+ end
360
+
361
+ # Override of method_missing to check in @data for the key.
362
+ def method_missing(method, *args, &blck)
363
+ if data.key?(method.to_s)
364
+ Bridgetown::Deprecator.deprecation_message "Document##{method} is now a key "\
365
+ "in the #data hash."
366
+ Bridgetown::Deprecator.deprecation_message "Called by #{caller(0..0)}."
367
+ data[method.to_s]
368
+ else
369
+ super
370
+ end
371
+ end
372
+
373
+ def respond_to_missing?(method, *)
374
+ data.key?(method.to_s) || super
375
+ end
376
+
377
+ def populate_categories
378
+ categories = Array(data["categories"]) + Utils.pluralized_array_from_hash(
379
+ data, "category", "categories"
380
+ )
381
+ categories.map!(&:to_s)
382
+ categories.flatten!
383
+ categories.uniq!
384
+
385
+ merge_data!({ "categories" => categories })
386
+ end
387
+
388
+ def populate_tags
389
+ tags = Utils.pluralized_array_from_hash(data, "tag", "tags")
390
+ tags.flatten!
391
+
392
+ merge_data!({ "tags" => tags })
393
+ end
394
+
395
+ private
396
+
397
+ def merge_categories!(other)
398
+ if other.key?("categories") && !other["categories"].nil?
399
+ other["categories"] = other["categories"].split if other["categories"].is_a?(String)
400
+ other["categories"] = (data["categories"] || []) | other["categories"]
401
+ end
402
+ end
403
+
404
+ def merge_date!(source)
405
+ if data.key?("date")
406
+ data["date"] = Utils.parse_date(
407
+ data["date"].to_s,
408
+ "Document '#{relative_path}' does not have a valid date in the #{source}."
409
+ )
410
+ end
411
+ end
412
+
413
+ def merge_defaults
414
+ defaults = @site.frontmatter_defaults.all(relative_path, type)
415
+ merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
416
+ end
417
+
418
+ def read_content(**opts)
419
+ self.content = File.read(path, **Utils.merged_file_read_opts(site, opts))
420
+ if content =~ YAML_FRONT_MATTER_REGEXP
421
+ self.content = $POSTMATCH
422
+ data_file = SafeYAML.load(Regexp.last_match(1))
423
+ merge_data!(data_file, :source => "YAML front matter") if data_file
424
+ end
425
+ end
426
+
427
+ def read_post_data
428
+ populate_title
429
+ populate_categories
430
+ populate_tags
431
+ generate_excerpt
432
+ end
433
+
434
+ def handle_read_error(error)
435
+ if error.is_a? Psych::SyntaxError
436
+ Bridgetown.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}"
437
+ else
438
+ Bridgetown.logger.error "Error:", "could not read file #{path}: #{error.message}"
439
+ end
440
+
441
+ if site.config["strict_front_matter"] || error.is_a?(Bridgetown::Errors::FatalException)
442
+ raise error
443
+ end
444
+ end
445
+
446
+ def populate_title
447
+ if relative_path =~ DATE_FILENAME_MATCHER
448
+ date, slug, ext = Regexp.last_match.captures
449
+ modify_date(date)
450
+ elsif relative_path =~ DATELESS_FILENAME_MATCHER
451
+ slug, ext = Regexp.last_match.captures
452
+ end
453
+
454
+ # slugs shouldn't end with a period
455
+ # `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
456
+ slug.gsub!(%r!\.*\z!, "")
457
+
458
+ # Try to ensure the user gets a title.
459
+ data["title"] ||= Utils.titleize_slug(slug)
460
+ # Only overwrite slug & ext if they aren't specified.
461
+ data["slug"] ||= slug
462
+ data["ext"] ||= ext
463
+ end
464
+
465
+ def modify_date(date)
466
+ if !data["date"] || data["date"].to_i == site.time.to_i
467
+ merge_data!({ "date" => date }, :source => "filename")
468
+ end
469
+ end
470
+
471
+ def generate_excerpt
472
+ data["excerpt"] ||= Bridgetown::Excerpt.new(self) if generate_excerpt?
473
+ end
474
+ end
475
+ end