bridgetown-core 0.15.0.beta4 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +14 -0
  3. data/bridgetown-core.gemspec +3 -1
  4. data/lib/bridgetown-core.rb +7 -1
  5. data/lib/bridgetown-core/commands/concerns/actions.rb +2 -1
  6. data/lib/bridgetown-core/commands/console.rb +4 -4
  7. data/lib/bridgetown-core/concerns/data_accessible.rb +19 -0
  8. data/lib/bridgetown-core/concerns/layout_placeable.rb +17 -0
  9. data/lib/bridgetown-core/concerns/liquid_renderable.rb +20 -0
  10. data/lib/bridgetown-core/concerns/publishable.rb +10 -0
  11. data/lib/bridgetown-core/concerns/site/configurable.rb +66 -31
  12. data/lib/bridgetown-core/concerns/site/content.rb +88 -29
  13. data/lib/bridgetown-core/concerns/site/extensible.rb +15 -12
  14. data/lib/bridgetown-core/concerns/site/localizable.rb +20 -0
  15. data/lib/bridgetown-core/concerns/site/processable.rb +12 -10
  16. data/lib/bridgetown-core/concerns/site/renderable.rb +21 -2
  17. data/lib/bridgetown-core/concerns/site/writable.rb +16 -2
  18. data/lib/bridgetown-core/concerns/validatable.rb +59 -0
  19. data/lib/bridgetown-core/configuration.rb +5 -2
  20. data/lib/bridgetown-core/converter.rb +34 -0
  21. data/lib/bridgetown-core/converters/erb_templates.rb +78 -0
  22. data/lib/bridgetown-core/converters/markdown.rb +6 -23
  23. data/lib/bridgetown-core/converters/smartypants.rb +0 -10
  24. data/lib/bridgetown-core/document.rb +8 -52
  25. data/lib/bridgetown-core/drops/site_drop.rb +1 -1
  26. data/lib/bridgetown-core/errors.rb +2 -0
  27. data/lib/bridgetown-core/excerpt.rb +1 -6
  28. data/lib/bridgetown-core/filters.rb +3 -48
  29. data/lib/bridgetown-core/filters/condition_helpers.rb +56 -0
  30. data/lib/bridgetown-core/frontmatter_defaults.rb +17 -0
  31. data/lib/bridgetown-core/layout.rb +24 -1
  32. data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
  33. data/lib/bridgetown-core/page.rb +33 -24
  34. data/lib/bridgetown-core/plugin_manager.rb +10 -2
  35. data/lib/bridgetown-core/reader.rb +1 -0
  36. data/lib/bridgetown-core/readers/collection_reader.rb +1 -0
  37. data/lib/bridgetown-core/readers/data_reader.rb +1 -0
  38. data/lib/bridgetown-core/readers/defaults_reader.rb +27 -0
  39. data/lib/bridgetown-core/readers/layout_reader.rb +1 -0
  40. data/lib/bridgetown-core/readers/page_reader.rb +1 -0
  41. data/lib/bridgetown-core/readers/post_reader.rb +1 -0
  42. data/lib/bridgetown-core/readers/static_file_reader.rb +1 -0
  43. data/lib/bridgetown-core/regenerator.rb +1 -1
  44. data/lib/bridgetown-core/renderer.rb +38 -12
  45. data/lib/bridgetown-core/ruby_template_view.rb +102 -0
  46. data/lib/bridgetown-core/site.rb +2 -0
  47. data/lib/bridgetown-core/tags/class_map.rb +90 -0
  48. data/lib/bridgetown-core/tags/find.rb +86 -0
  49. data/lib/bridgetown-core/tags/t.rb +14 -0
  50. data/lib/bridgetown-core/tags/webpack_path.rb +19 -22
  51. data/lib/bridgetown-core/utils.rb +55 -2
  52. data/lib/bridgetown-core/version.rb +2 -2
  53. data/lib/site_template/src/_layouts/{default.html → default.liquid} +0 -0
  54. data/lib/site_template/src/_layouts/{home.html → home.liquid} +0 -0
  55. data/lib/site_template/src/_layouts/{page.html → page.liquid} +0 -0
  56. data/lib/site_template/src/_layouts/{post.html → post.liquid} +0 -0
  57. metadata +50 -10
  58. data/lib/bridgetown-core/concerns/convertible.rb +0 -235
@@ -3,17 +3,19 @@
3
3
  module Bridgetown
4
4
  module Site::Extensible
5
5
  # Load necessary libraries, plugins, converters, and generators.
6
- #
7
- # Returns nothing.
6
+ # @see Bridgetown::Converter
7
+ # @see Bridgetown::Generator
8
+ # @see PluginManager
9
+ # @return [void]
8
10
  def setup
9
11
  plugin_manager.require_plugin_files
10
12
  self.converters = instantiate_subclasses(Bridgetown::Converter)
11
13
  self.generators = instantiate_subclasses(Bridgetown::Generator)
12
14
  end
13
15
 
14
- # Run each of the Generators.
15
- #
16
- # Returns nothing.
16
+ # Run all Generators.
17
+ # @see Bridgetown::Generator
18
+ # @return [void]
17
19
  def generate
18
20
  generators.each do |generator|
19
21
  start = Time.now
@@ -32,8 +34,9 @@ module Bridgetown
32
34
  end
33
35
 
34
36
  # Get the implementation class for the given Converter.
35
- # Returns the Converter instance implementing the given Converter.
36
- # klass - The Class of the Converter to fetch.
37
+ # @param klass [Object] The Class of the Converter to fetch.
38
+ # @return [Bridgetown::Converter] Returns the {Bridgetown::Converter}
39
+ # instance implementing the given +Converter+.
37
40
  def find_converter_instance(klass)
38
41
  @find_converter_instance ||= {}
39
42
  @find_converter_instance[klass] ||= begin
@@ -42,11 +45,11 @@ module Bridgetown
42
45
  end
43
46
  end
44
47
 
45
- # klass - class or module containing the subclasses.
46
- # Returns array of instances of subclasses of parameter.
47
- # Create array of instances of the subclasses of the class or module
48
- # passed in as argument.
49
-
48
+ # Create an array of instances of the subclasses of the class or module
49
+ # passed in as argument.
50
+ # @param klass [Class, Module] - class or module containing the subclasses.
51
+ # @return [Array<Object>] Returns an array of instances of subclasses of
52
+ # +klass+.
50
53
  def instantiate_subclasses(klass)
51
54
  klass.descendants.sort.map do |c|
52
55
  c.new(config)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Site::Localizable
5
+ def locale
6
+ if @locale
7
+ @locale
8
+ else
9
+ @locale = ENV.fetch("BRIDGETOWN_LOCALE", config[:default_locale]).to_sym
10
+ I18n.load_path << Dir[in_source_dir("_locales") + "/*.yml"]
11
+ I18n.available_locales = config[:available_locales]
12
+ I18n.default_locale = @locale
13
+ end
14
+ end
15
+
16
+ def locale=(new_locale)
17
+ I18n.locale = @locale = new_locale.to_sym
18
+ end
19
+ end
20
+ end
@@ -2,9 +2,14 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Site::Processable
5
- # Public: Read, process, and write this Site to output.
6
- #
7
- # Returns nothing.
5
+ # Reset, Read, Generate, Render, Cleanup, Process, and Write this Site to output.
6
+ # @return [void]
7
+ # @see #reset
8
+ # @see #read
9
+ # @see #generate
10
+ # @see #render
11
+ # @see #cleanup
12
+ # @see #write
8
13
  def process
9
14
  reset
10
15
  read
@@ -16,10 +21,9 @@ module Bridgetown
16
21
  end
17
22
 
18
23
  # rubocop:disable Metrics/AbcSize
19
- #
24
+
20
25
  # Reset Site details.
21
- #
22
- # Returns nothing
26
+ # @return [void]
23
27
  def reset
24
28
  self.time = if config["time"]
25
29
  Utils.parse_date(config["time"].to_s, "Invalid time in bridgetown.config.yml.")
@@ -43,11 +47,11 @@ module Bridgetown
43
47
  Bridgetown::Cache.clear_if_config_changed config
44
48
  Bridgetown::Hooks.trigger :site, :after_reset, self
45
49
  end
50
+
46
51
  # rubocop:enable Metrics/AbcSize
47
52
 
48
53
  # Read Site data from disk and load it into internal data structures.
49
- #
50
- # Returns nothing.
54
+ # @return [void]
51
55
  def read
52
56
  Bridgetown::Hooks.trigger :site, :pre_read, self
53
57
  reader.read
@@ -58,8 +62,6 @@ module Bridgetown
58
62
  private
59
63
 
60
64
  # Limits the current posts; removes the posts which exceed the limit_posts
61
- #
62
- # Returns nothing
63
65
  def limit_posts!
64
66
  if limit_posts.positive?
65
67
  limit = posts.docs.length < limit_posts ? posts.docs.length : limit_posts
@@ -3,8 +3,7 @@
3
3
  module Bridgetown
4
4
  module Site::Renderable
5
5
  # Render the site to the destination.
6
- #
7
- # Returns nothing.
6
+ # @return [void]
8
7
  def render
9
8
  payload = site_payload
10
9
 
@@ -18,6 +17,13 @@ module Bridgetown
18
17
  Bridgetown::Hooks.trigger :site, :post_render, self, payload
19
18
  end
20
19
 
20
+ # Executes inline Ruby frontmatter
21
+ #
22
+ # @example
23
+ # calculation: !ruby/string:Rb |
24
+ # [2 * 4, 5 + 2].min
25
+ # @return [void]
26
+ # @see https://www.bridgetownrb.com/docs/front-matter#ruby-front-matter
21
27
  def execute_inline_ruby_for_layouts!
22
28
  return unless config.should_execute_inline_ruby?
23
29
 
@@ -26,6 +32,10 @@ module Bridgetown
26
32
  end
27
33
  end
28
34
 
35
+ # Renders all documents
36
+ # @param payload [Hash] A hash of site data.
37
+ # @return [void]
38
+ # @see Bridgetown::Site::Content#site_payload
29
39
  def render_docs(payload)
30
40
  collections.each_value do |collection|
31
41
  collection.docs.each do |document|
@@ -34,12 +44,21 @@ module Bridgetown
34
44
  end
35
45
  end
36
46
 
47
+ # Renders all pages
48
+ # @param payload [Hash] A hash of site data.
49
+ # @return [void]
50
+ # @see Bridgetown::Site::Content#site_payload
37
51
  def render_pages(payload)
38
52
  pages.each do |page|
39
53
  render_regenerated(page, payload)
40
54
  end
41
55
  end
42
56
 
57
+ # Regenerates a site using {Bridgetown::Renderer}
58
+ # @param document [Post] The document to regenerate.
59
+ # @param payload [Hash] A hash of site data.
60
+ # @return [void]
61
+ # @see Bridgetown::Renderer
43
62
  def render_regenerated(document, payload)
44
63
  return unless regenerator.regenerate?(document)
45
64
 
@@ -4,14 +4,14 @@ module Bridgetown
4
4
  module Site::Writable
5
5
  # Remove orphaned files and empty directories in destination.
6
6
  #
7
- # Returns nothing.
7
+ # @return [void]
8
8
  def cleanup
9
9
  @cleaner.cleanup!
10
10
  end
11
11
 
12
12
  # Write static files, pages, and posts.
13
13
  #
14
- # Returns nothing.
14
+ # @return [void]
15
15
  def write
16
16
  each_site_file do |item|
17
17
  item.write(dest) if regenerator.regenerate?(item)
@@ -20,6 +20,20 @@ module Bridgetown
20
20
  Bridgetown::Hooks.trigger :site, :post_write, self
21
21
  end
22
22
 
23
+ # Yields the pages from {#pages}, {#static_files}, and {#docs_to_write}.
24
+ #
25
+ # @yieldparam item [Document, Page, StaticFile] Yields a
26
+ # {#Bridgetown::Page}, {#Bridgetown::StaticFile}, or
27
+ # {#Bridgetown::Document} object.
28
+ #
29
+ # @return [void]
30
+ #
31
+ # @see #pages
32
+ # @see #static_files
33
+ # @see #docs_to_write
34
+ # @see Page
35
+ # @see StaticFile
36
+ # @see Document
23
37
  def each_site_file
24
38
  %w(pages static_files docs_to_write).each do |type|
25
39
  send(type).each do |item|
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Validatable
5
+ # FIXME: there should be ONE TRUE METHOD to read the YAML frontmatter
6
+ # in the entire project. Both this and the equivalent Document method
7
+ # should be extracted and generalized.
8
+ #
9
+ # Read the YAML frontmatter.
10
+ #
11
+ # base - The String path to the dir containing the file.
12
+ # name - The String filename of the file.
13
+ # opts - optional parameter to File.read, default at site configs
14
+ #
15
+ # Returns nothing.
16
+ # rubocop:disable Metrics/AbcSize
17
+ def read_yaml(base, name, opts = {})
18
+ filename = File.join(base, name)
19
+
20
+ begin
21
+ self.content = File.read(@path || site.in_source_dir(base, name),
22
+ **Utils.merged_file_read_opts(site, opts))
23
+ if content =~ Document::YAML_FRONT_MATTER_REGEXP
24
+ self.content = $POSTMATCH
25
+ self.data = SafeYAML.load(Regexp.last_match(1))&.with_indifferent_access
26
+ end
27
+ rescue Psych::SyntaxError => e
28
+ Bridgetown.logger.warn "YAML Exception reading #{filename}: #{e.message}"
29
+ raise e if site.config["strict_front_matter"]
30
+ rescue StandardError => e
31
+ Bridgetown.logger.warn "Error reading file #{filename}: #{e.message}"
32
+ raise e if site.config["strict_front_matter"]
33
+ end
34
+
35
+ self.data ||= ActiveSupport::HashWithIndifferentAccess.new
36
+
37
+ validate_data! filename
38
+ validate_permalink! filename
39
+
40
+ self.data
41
+ end
42
+ # rubocop:enable Metrics/AbcSize
43
+
44
+ # FIXME: why doesn't Document validate data too?
45
+ def validate_data!(filename)
46
+ unless self.data.is_a?(Hash)
47
+ raise Errors::InvalidYAMLFrontMatterError,
48
+ "Invalid YAML front matter in #{filename}"
49
+ end
50
+ end
51
+
52
+ # FIXME: Layouts don't have permalinks...d'oh
53
+ def validate_permalink!(filename)
54
+ if self.data["permalink"]&.to_s&.empty?
55
+ raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -19,6 +19,7 @@ module Bridgetown
19
19
  "data_dir" => "_data",
20
20
  "components_dir" => "_components",
21
21
  "includes_dir" => "_includes",
22
+ "partials_dir" => "_partials",
22
23
  "collections" => {},
23
24
 
24
25
  # Handling Reading
@@ -34,7 +35,7 @@ module Bridgetown
34
35
  "limit_posts" => 0,
35
36
  "future" => false,
36
37
  "unpublished" => false,
37
- "ruby_in_front_matter" => true, # requires BRIDGETOWN_RUBY_IN_FRONT_MATTER == "true"
38
+ "ruby_in_front_matter" => true,
38
39
 
39
40
  # Conversion
40
41
  "markdown" => "kramdown",
@@ -51,6 +52,8 @@ module Bridgetown
51
52
  "show_dir_listing" => false,
52
53
 
53
54
  # Output Configuration
55
+ "available_locales" => ["en"],
56
+ "default_locale" => "en",
54
57
  "permalink" => "date",
55
58
  "timezone" => nil, # use the local timezone
56
59
 
@@ -275,7 +278,7 @@ module Bridgetown
275
278
  end
276
279
 
277
280
  def should_execute_inline_ruby?
278
- ENV["BRIDGETOWN_RUBY_IN_FRONT_MATTER"] == "true" &&
281
+ ENV["BRIDGETOWN_RUBY_IN_FRONT_MATTER"] != "false" &&
279
282
  self["ruby_in_front_matter"]
280
283
  end
281
284
 
@@ -2,6 +2,20 @@
2
2
 
3
3
  module Bridgetown
4
4
  class Converter < Plugin
5
+ class << self
6
+ attr_accessor :extname_list
7
+
8
+ # Converters can provide one or more extensions they accept. Examples:
9
+ #
10
+ # * `input :erb`
11
+ # * `input %i(xls xlsx)`
12
+ def input(extnames)
13
+ extnames = Array(extnames)
14
+ self.extname_list ||= []
15
+ self.extname_list += extnames.map { |e| ".#{e.to_s.downcase}" }
16
+ end
17
+ end
18
+
5
19
  # Public: Get or set the highlighter prefix. When an argument is specified,
6
20
  # the prefix will be set. If no argument is specified, the current prefix
7
21
  # will be returned.
@@ -37,6 +51,26 @@ module Bridgetown
37
51
  @config = config
38
52
  end
39
53
 
54
+ # Does the given extension match this converter's list of acceptable extensions?
55
+ #
56
+ # @param [String] ext
57
+ # The file's extension (including the dot)
58
+ #
59
+ # @return [Boolean] Whether the extension matches one in the list
60
+ def matches(ext)
61
+ (self.class.extname_list || []).include?(ext.downcase)
62
+ end
63
+
64
+ # You can override this in Converter subclasses as needed. Default is ".html"
65
+ #
66
+ # @param [String] ext
67
+ # The extension of the original file
68
+ #
69
+ # @return [String] The output file extension (including the dot)
70
+ def output_ext(_ext)
71
+ ".html"
72
+ end
73
+
40
74
  # Get the highlighter prefix.
41
75
  #
42
76
  # Returns the String prefix.
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tilt/erubi"
4
+ require "erubi/capture_end"
5
+
6
+ module Bridgetown
7
+ class ERBView < RubyTemplateView
8
+ def h(input)
9
+ Erubi.h(input)
10
+ end
11
+
12
+ def partial(partial_name, options = {})
13
+ options.merge!(options[:locals]) if options[:locals]
14
+
15
+ partial_segments = partial_name.split("/")
16
+ partial_segments.last.sub!(%r!^!, "_")
17
+ partial_name = partial_segments.join("/")
18
+
19
+ Tilt::ErubiTemplate.new(
20
+ site.in_source_dir(site.config[:partials_dir], "#{partial_name}.erb"),
21
+ outvar: "@_erbout",
22
+ engine_class: Erubi::CaptureEndEngine
23
+ ).render(self, options)
24
+ end
25
+
26
+ def markdownify
27
+ previous_buffer_state = @_erbout
28
+ @_erbout = +""
29
+ result = yield
30
+ @_erbout = previous_buffer_state
31
+
32
+ content = Bridgetown::Utils.reindent_for_markdown(result)
33
+ converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
34
+ md_output = converter.convert(content).strip
35
+ @_erbout << md_output
36
+ end
37
+
38
+ def capture
39
+ previous_buffer_state = @_erbout
40
+ @_erbout = +""
41
+ result = yield
42
+ @_erbout = previous_buffer_state
43
+
44
+ result
45
+ end
46
+ end
47
+
48
+ module Converters
49
+ class ERBTemplates < Converter
50
+ input :erb
51
+
52
+ # Logic to do the ERB content conversion.
53
+ #
54
+ # @param content [String] Content of the file (without front matter).
55
+ # @params convertible [Bridgetown::Page, Bridgetown::Document, Bridgetown::Layout]
56
+ # The instantiated object which is processing the file.
57
+ #
58
+ # @return [String] The converted content.
59
+ def convert(content, convertible)
60
+ erb_view = Bridgetown::ERBView.new(convertible)
61
+
62
+ erb_renderer = Tilt::ErubiTemplate.new(
63
+ convertible.relative_path,
64
+ outvar: "@_erbout",
65
+ engine_class: Erubi::CaptureEndEngine
66
+ ) { content }
67
+
68
+ if convertible.is_a?(Bridgetown::Layout)
69
+ erb_renderer.render(erb_view) do
70
+ convertible.current_document_output
71
+ end
72
+ else
73
+ erb_renderer.render(erb_view)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -8,6 +8,12 @@ module Bridgetown
8
8
  highlighter_prefix "\n"
9
9
  highlighter_suffix "\n"
10
10
 
11
+ def initialize(config = {})
12
+ super
13
+
14
+ self.class.input @config["markdown_ext"].split(",")
15
+ end
16
+
11
17
  def setup
12
18
  return if @setup ||= false
13
19
 
@@ -51,25 +57,6 @@ module Bridgetown
51
57
  self.class.constants - [:KramdownParser, :PRIORITIES]
52
58
  end
53
59
 
54
- # Does the given extension match this converter's list of acceptable extensions?
55
- # Takes one argument: the file's extension (including the dot).
56
- #
57
- # ext - The String extension to check.
58
- #
59
- # Returns true if it matches, false otherwise.
60
- def matches(ext)
61
- extname_list.include?(ext.downcase)
62
- end
63
-
64
- # Public: The extension to be given to the output file (including the dot).
65
- #
66
- # ext - The String extension or original file.
67
- #
68
- # Returns The String output file extension.
69
- def output_ext(_ext)
70
- ".html"
71
- end
72
-
73
60
  # Logic to do the content conversion.
74
61
  #
75
62
  # content - String content of file (without front matter).
@@ -82,10 +69,6 @@ module Bridgetown
82
69
  end
83
70
  end
84
71
 
85
- def extname_list
86
- @extname_list ||= @config["markdown_ext"].split(",").map! { |e| ".#{e.downcase}" }
87
- end
88
-
89
72
  private
90
73
 
91
74
  def custom_processor