bridgetown-core 0.16.0 → 0.18.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/bridgetown-core.gemspec +2 -1
  4. data/lib/bridgetown-core.rb +45 -29
  5. data/lib/bridgetown-core/collection.rb +5 -1
  6. data/lib/bridgetown-core/commands/apply.rb +2 -2
  7. data/lib/bridgetown-core/commands/console.rb +4 -4
  8. data/lib/bridgetown-core/commands/new.rb +1 -1
  9. data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
  10. data/lib/bridgetown-core/concerns/liquid_renderable.rb +10 -0
  11. data/lib/bridgetown-core/concerns/site/configurable.rb +24 -22
  12. data/lib/bridgetown-core/concerns/site/content.rb +46 -33
  13. data/lib/bridgetown-core/concerns/site/extensible.rb +14 -13
  14. data/lib/bridgetown-core/concerns/site/localizable.rb +24 -0
  15. data/lib/bridgetown-core/concerns/site/processable.rb +12 -15
  16. data/lib/bridgetown-core/concerns/site/renderable.rb +35 -28
  17. data/lib/bridgetown-core/concerns/site/writable.rb +7 -15
  18. data/lib/bridgetown-core/concerns/validatable.rb +2 -2
  19. data/lib/bridgetown-core/configuration.rb +14 -6
  20. data/lib/bridgetown-core/converter.rb +0 -42
  21. data/lib/bridgetown-core/converters/erb_templates.rb +75 -16
  22. data/lib/bridgetown-core/converters/liquid_templates.rb +96 -0
  23. data/lib/bridgetown-core/converters/markdown.rb +0 -3
  24. data/lib/bridgetown-core/document.rb +34 -21
  25. data/lib/bridgetown-core/drops/site_drop.rb +5 -1
  26. data/lib/bridgetown-core/drops/unified_payload_drop.rb +0 -1
  27. data/lib/bridgetown-core/drops/url_drop.rb +19 -3
  28. data/lib/bridgetown-core/excerpt.rb +1 -1
  29. data/lib/bridgetown-core/filters.rb +37 -55
  30. data/lib/bridgetown-core/filters/condition_helpers.rb +56 -0
  31. data/lib/bridgetown-core/frontmatter_defaults.rb +17 -0
  32. data/lib/bridgetown-core/generators/prototype_generator.rb +42 -25
  33. data/lib/bridgetown-core/helpers.rb +84 -0
  34. data/lib/bridgetown-core/liquid_renderer.rb +1 -1
  35. data/lib/bridgetown-core/log_writer.rb +2 -2
  36. data/lib/bridgetown-core/page.rb +8 -2
  37. data/lib/bridgetown-core/plugin_manager.rb +34 -1
  38. data/lib/bridgetown-core/reader.rb +2 -4
  39. data/lib/bridgetown-core/readers/collection_reader.rb +1 -0
  40. data/lib/bridgetown-core/readers/data_reader.rb +4 -3
  41. data/lib/bridgetown-core/readers/defaults_reader.rb +27 -0
  42. data/lib/bridgetown-core/readers/layout_reader.rb +1 -0
  43. data/lib/bridgetown-core/readers/page_reader.rb +1 -0
  44. data/lib/bridgetown-core/readers/post_reader.rb +29 -15
  45. data/lib/bridgetown-core/readers/static_file_reader.rb +1 -0
  46. data/lib/bridgetown-core/renderer.rb +42 -162
  47. data/lib/bridgetown-core/ruby_template_view.rb +26 -22
  48. data/lib/bridgetown-core/site.rb +14 -2
  49. data/lib/bridgetown-core/tags/find.rb +86 -0
  50. data/lib/bridgetown-core/tags/render_content.rb +2 -2
  51. data/lib/bridgetown-core/tags/t.rb +14 -0
  52. data/lib/bridgetown-core/utils.rb +16 -2
  53. data/lib/bridgetown-core/utils/ruby_exec.rb +1 -1
  54. data/lib/bridgetown-core/version.rb +2 -2
  55. data/lib/bridgetown-core/watcher.rb +1 -0
  56. data/lib/site_template/src/images/.keep +1 -0
  57. metadata +29 -6
@@ -1,20 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bridgetown
4
- module Site::Extensible
3
+ class Bridgetown::Site
4
+ module Extensible
5
5
  # Load necessary libraries, plugins, converters, and generators.
6
- # @see Bridgetown::Converter
7
- # @see Bridgetown::Generator
6
+ # @see Converter
7
+ # @see Generator
8
8
  # @see PluginManager
9
9
  # @return [void]
10
10
  def setup
11
11
  plugin_manager.require_plugin_files
12
+ plugin_manager.setup_component_loaders
12
13
  self.converters = instantiate_subclasses(Bridgetown::Converter)
13
14
  self.generators = instantiate_subclasses(Bridgetown::Generator)
14
15
  end
15
16
 
16
17
  # Run all Generators.
17
- # @see Bridgetown::Generator
18
+ # @see Generator
18
19
  # @return [void]
19
20
  def generate
20
21
  generators.each do |generator|
@@ -33,10 +34,10 @@ module Bridgetown
33
34
  end
34
35
  end
35
36
 
36
- # Get the implementation class for the given Converter.
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
+ # Get the implementation for the given Converter class.
38
+ # @param klass [Class] The Class of the Converter to fetch.
39
+ # @return [Converter] Returns the {Converter}
40
+ # instance implementing the given `Converter` class.
40
41
  def find_converter_instance(klass)
41
42
  @find_converter_instance ||= {}
42
43
  @find_converter_instance[klass] ||= begin
@@ -45,11 +46,11 @@ module Bridgetown
45
46
  end
46
47
  end
47
48
 
48
- # Create an array of instances of the subclasses of the class or module
49
+ # Create an array of instances of the subclasses of the class
49
50
  # 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+.
51
+ # @param klass [Class] - class which is the parent of the subclasses.
52
+ # @return [Array<Converter, Generator>] Returns an array of instances of
53
+ # subclasses of `klass`.
53
54
  def instantiate_subclasses(klass)
54
55
  klass.descendants.sort.map do |c|
55
56
  c.new(config)
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bridgetown::Site
4
+ module Localizable
5
+ # Returns the current and/or default configured locale
6
+ # @return String
7
+ def locale
8
+ if @locale
9
+ @locale
10
+ else
11
+ @locale = ENV.fetch("BRIDGETOWN_LOCALE", config[:default_locale]).to_sym
12
+ I18n.load_path << Dir[in_source_dir("_locales") + "/*.yml"]
13
+ I18n.available_locales = config[:available_locales]
14
+ I18n.default_locale = @locale
15
+ end
16
+ end
17
+
18
+ # Sets the current locale for the site
19
+ # @param new_locale [String] for example: "en" for English, "es" for Spanish
20
+ def locale=(new_locale)
21
+ I18n.locale = @locale = new_locale.to_sym
22
+ end
23
+ end
24
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bridgetown
4
- module Site::Processable
3
+ class Bridgetown::Site
4
+ module Processable
5
5
  # Reset, Read, Generate, Render, Cleanup, Process, and Write this Site to output.
6
6
  # @return [void]
7
7
  # @see #reset
@@ -20,20 +20,19 @@ module Bridgetown
20
20
  print_stats if config["profile"]
21
21
  end
22
22
 
23
- # rubocop:disable Metrics/AbcSize
24
-
25
- # Reset Site details.
23
+ # Reset all in-memory data and content.
26
24
  # @return [void]
27
25
  def reset
28
- self.time = if config["time"]
29
- Utils.parse_date(config["time"].to_s, "Invalid time in bridgetown.config.yml.")
30
- else
31
- Time.now
32
- end
33
- self.layouts = ActiveSupport::HashWithIndifferentAccess.new
26
+ self.time = Time.now
27
+ if config["time"]
28
+ self.time = Bridgetown::Utils.parse_date(
29
+ config["time"].to_s, "Invalid time in bridgetown.config.yml."
30
+ )
31
+ end
32
+ self.layouts = HashWithDotAccess::Hash.new
34
33
  self.pages = []
35
34
  self.static_files = []
36
- self.data = ActiveSupport::HashWithIndifferentAccess.new
35
+ self.data = HashWithDotAccess::Hash.new
37
36
  @post_attr_hash = {}
38
37
  @collections = nil
39
38
  @documents = nil
@@ -48,9 +47,7 @@ module Bridgetown
48
47
  Bridgetown::Hooks.trigger :site, :after_reset, self
49
48
  end
50
49
 
51
- # rubocop:enable Metrics/AbcSize
52
-
53
- # Read Site data from disk and load it into internal data structures.
50
+ # Read data from disk and load it into internal memory.
54
51
  # @return [void]
55
52
  def read
56
53
  Bridgetown::Hooks.trigger :site, :pre_read, self
@@ -1,24 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bridgetown
4
- module Site::Renderable
5
- # Render the site to the destination.
3
+ class Bridgetown::Site
4
+ module Renderable
5
+ # Render all pages & documents so they're ready to be written out to disk.
6
6
  # @return [void]
7
+ # @see Page
8
+ # @see Document
7
9
  def render
8
- payload = site_payload
9
-
10
- Bridgetown::Hooks.trigger :site, :pre_render, self, payload
11
-
10
+ Bridgetown::Hooks.trigger :site, :pre_render, self
12
11
  execute_inline_ruby_for_layouts!
13
-
14
- render_docs(payload)
15
- render_pages(payload)
16
-
17
- Bridgetown::Hooks.trigger :site, :post_render, self, payload
12
+ render_docs
13
+ render_pages
14
+ Bridgetown::Hooks.trigger :site, :post_render, self
18
15
  end
19
16
 
20
- # Executes inline Ruby frontmatter if
21
- # +ENV+["BRIDGETOWN_RUBY_IN_FRONTMATTER"] equals "true"
17
+ # Executes inline Ruby frontmatter
22
18
  #
23
19
  # @example
24
20
  # calculation: !ruby/string:Rb |
@@ -34,36 +30,47 @@ module Bridgetown
34
30
  end
35
31
 
36
32
  # Renders all documents
37
- # @param payload [Hash] A hash of site data.
38
33
  # @return [void]
39
- # @see Bridgetown::Site::Content#site_payload
40
- def render_docs(payload)
34
+ def render_docs
41
35
  collections.each_value do |collection|
42
36
  collection.docs.each do |document|
43
- render_regenerated(document, payload)
37
+ render_with_locale(document) do
38
+ render_regenerated document
39
+ end
44
40
  end
45
41
  end
46
42
  end
47
43
 
48
44
  # Renders all pages
49
- # @param payload [Hash] A hash of site data.
50
45
  # @return [void]
51
- # @see Bridgetown::Site::Content#site_payload
52
- def render_pages(payload)
46
+ def render_pages
53
47
  pages.each do |page|
54
- render_regenerated(page, payload)
48
+ render_regenerated page
49
+ end
50
+ end
51
+
52
+ # Renders a document while ensuring site locale is set if the data is available.
53
+ # @param document [Document] The document to render
54
+ # @yield Runs the block in between locale setting and resetting
55
+ # @return [void]
56
+ def render_with_locale(document)
57
+ if document.data["locale"]
58
+ previous_locale = locale
59
+ self.locale = document.data["locale"]
60
+ yield
61
+ self.locale = previous_locale
62
+ else
63
+ yield
55
64
  end
56
65
  end
57
66
 
58
- # Regenerates a site using {Bridgetown::Renderer}
59
- # @param document [Post] The document to regenerate.
60
- # @param payload [Hash] A hash of site data.
67
+ # Regenerates a site using {Renderer}
68
+ # @param document [Document] The document to regenerate.
61
69
  # @return [void]
62
- # @see Bridgetown::Renderer
63
- def render_regenerated(document, payload)
70
+ def render_regenerated(document)
64
71
  return unless regenerator.regenerate?(document)
65
72
 
66
- Bridgetown::Renderer.new(self, document, payload).run
73
+ Bridgetown::Renderer.new(self, document).run
67
74
  end
68
75
  end
69
76
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Bridgetown
4
- module Site::Writable
3
+ class Bridgetown::Site
4
+ module Writable
5
5
  # Remove orphaned files and empty directories in destination.
6
6
  #
7
7
  # @return [void]
@@ -9,7 +9,7 @@ module Bridgetown
9
9
  @cleaner.cleanup!
10
10
  end
11
11
 
12
- # Write static files, pages, and posts.
12
+ # Write static files, pages, and documents to the destination folder.
13
13
  #
14
14
  # @return [void]
15
15
  def write
@@ -20,22 +20,14 @@ 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}.
23
+ # Yields all content objects while looping through {#pages},
24
+ # {#static_files_to_write}, and {#docs_to_write}.
24
25
  #
25
- # @yieldparam item [Document, Page, StaticFile] Yields a
26
- # {#Bridgetown::Page}, {#Bridgetown::StaticFile}, or
27
- # {#Bridgetown::Document} object.
26
+ # @yieldparam item [Document, Page, StaticFile]
28
27
  #
29
28
  # @return [void]
30
- #
31
- # @see #pages
32
- # @see #static_files
33
- # @see #docs_to_write
34
- # @see Page
35
- # @see StaticFile
36
- # @see Document
37
29
  def each_site_file
38
- %w(pages static_files docs_to_write).each do |type|
30
+ %w(pages static_files_to_write docs_to_write).each do |type|
39
31
  send(type).each do |item|
40
32
  yield item
41
33
  end
@@ -22,7 +22,7 @@ module Bridgetown
22
22
  **Utils.merged_file_read_opts(site, opts))
23
23
  if content =~ Document::YAML_FRONT_MATTER_REGEXP
24
24
  self.content = $POSTMATCH
25
- self.data = SafeYAML.load(Regexp.last_match(1))&.with_indifferent_access
25
+ self.data = SafeYAML.load(Regexp.last_match(1))&.with_dot_access
26
26
  end
27
27
  rescue Psych::SyntaxError => e
28
28
  Bridgetown.logger.warn "YAML Exception reading #{filename}: #{e.message}"
@@ -32,7 +32,7 @@ module Bridgetown
32
32
  raise e if site.config["strict_front_matter"]
33
33
  end
34
34
 
35
- self.data ||= ActiveSupport::HashWithIndifferentAccess.new
35
+ self.data ||= HashWithDotAccess::Hash.new
36
36
 
37
37
  validate_data! filename
38
38
  validate_permalink! filename
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- # TODO: refactor this whole object! Already had to fix obscure
5
- # bugs just making minor changes, and all the indirection is
6
- # quite hard to decipher. -JW
7
- class Configuration < ActiveSupport::HashWithIndifferentAccess
4
+ # Holds the processed configuration loaded from the YAML config file.
5
+ #
6
+ # @todo refactor this whole object! Already had to fix obscure
7
+ # bugs just making minor changes, and all the indirection is
8
+ # quite hard to decipher. -JW
9
+ class Configuration < HashWithDotAccess::Hash
8
10
  # Default options. Overridden by values in bridgetown.config.yml.
9
11
  # Strings rather than symbols are used for compatibility with YAML.
10
12
  DEFAULTS = {
@@ -35,7 +37,7 @@ module Bridgetown
35
37
  "limit_posts" => 0,
36
38
  "future" => false,
37
39
  "unpublished" => false,
38
- "ruby_in_front_matter" => true, # requires BRIDGETOWN_RUBY_IN_FRONT_MATTER == "true"
40
+ "ruby_in_front_matter" => true,
39
41
 
40
42
  # Conversion
41
43
  "markdown" => "kramdown",
@@ -52,6 +54,8 @@ module Bridgetown
52
54
  "show_dir_listing" => false,
53
55
 
54
56
  # Output Configuration
57
+ "available_locales" => ["en"],
58
+ "default_locale" => "en",
55
59
  "permalink" => "date",
56
60
  "timezone" => nil, # use the local timezone
57
61
 
@@ -276,7 +280,7 @@ module Bridgetown
276
280
  end
277
281
 
278
282
  def should_execute_inline_ruby?
279
- ENV["BRIDGETOWN_RUBY_IN_FRONT_MATTER"] == "true" &&
283
+ ENV["BRIDGETOWN_RUBY_IN_FRONT_MATTER"] != "false" &&
280
284
  self["ruby_in_front_matter"]
281
285
  end
282
286
 
@@ -309,6 +313,10 @@ module Bridgetown
309
313
  raise Bridgetown::Errors::InvalidConfigurationError,
310
314
  "'#{option}' should be set as an array, but was: #{self[option].inspect}."
311
315
  end
316
+
317
+ # add _pages to includes set
318
+ self[:include] << "_pages"
319
+
312
320
  self
313
321
  end
314
322
  end
@@ -16,34 +16,6 @@ module Bridgetown
16
16
  end
17
17
  end
18
18
 
19
- # Public: Get or set the highlighter prefix. When an argument is specified,
20
- # the prefix will be set. If no argument is specified, the current prefix
21
- # will be returned.
22
- #
23
- # highlighter_prefix - The String prefix (default: nil).
24
- #
25
- # Returns the String prefix.
26
- def self.highlighter_prefix(highlighter_prefix = nil)
27
- unless defined?(@highlighter_prefix) && highlighter_prefix.nil?
28
- @highlighter_prefix = highlighter_prefix
29
- end
30
- @highlighter_prefix
31
- end
32
-
33
- # Public: Get or set the highlighter suffix. When an argument is specified,
34
- # the suffix will be set. If no argument is specified, the current suffix
35
- # will be returned.
36
- #
37
- # highlighter_suffix - The String suffix (default: nil).
38
- #
39
- # Returns the String suffix.
40
- def self.highlighter_suffix(highlighter_suffix = nil)
41
- unless defined?(@highlighter_suffix) && highlighter_suffix.nil?
42
- @highlighter_suffix = highlighter_suffix
43
- end
44
- @highlighter_suffix
45
- end
46
-
47
19
  # Initialize the converter.
48
20
  #
49
21
  # Returns an initialized Converter.
@@ -70,19 +42,5 @@ module Bridgetown
70
42
  def output_ext(_ext)
71
43
  ".html"
72
44
  end
73
-
74
- # Get the highlighter prefix.
75
- #
76
- # Returns the String prefix.
77
- def highlighter_prefix
78
- self.class.highlighter_prefix
79
- end
80
-
81
- # Get the highlighter suffix.
82
- #
83
- # Returns the String suffix.
84
- def highlighter_suffix
85
- self.class.highlighter_suffix
86
- end
87
45
  end
88
46
  end
@@ -1,9 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "tilt/erubi"
4
- require "erubi/capture_end"
5
4
 
6
5
  module Bridgetown
6
+ class ERBBuffer < String
7
+ def concat_to_s(input)
8
+ concat input.to_s
9
+ end
10
+
11
+ alias_method :safe_append=, :concat_to_s
12
+ alias_method :append=, :concat_to_s
13
+ alias_method :safe_expr_append=, :concat_to_s
14
+ end
15
+
16
+ class ERBEngine < Erubi::Engine
17
+ private
18
+
19
+ def add_code(code)
20
+ @src << code
21
+ @src << ";#{@bufvar};" if code.strip.split(".").first == "end"
22
+ @src << ";" unless code[Erubi::RANGE_LAST] == "\n"
23
+ end
24
+
25
+ # pulled from Rails' ActionView
26
+ BLOCK_EXPR = %r!\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z!.freeze
27
+
28
+ def add_expression(indicator, code)
29
+ if BLOCK_EXPR.match?(code)
30
+ src << "#{@bufvar}.append= " << code
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ # Don't allow == to output escaped strings, as that's the opposite of Rails
37
+ def add_expression_result_escaped(code)
38
+ add_expression_result(code)
39
+ end
40
+ end
41
+
7
42
  class ERBView < RubyTemplateView
8
43
  def h(input)
9
44
  Erubi.h(input)
@@ -11,6 +46,7 @@ module Bridgetown
11
46
 
12
47
  def partial(partial_name, options = {})
13
48
  options.merge!(options[:locals]) if options[:locals]
49
+ options[:content] = yield if block_given?
14
50
 
15
51
  partial_segments = partial_name.split("/")
16
52
  partial_segments.last.sub!(%r!^!, "_")
@@ -19,34 +55,42 @@ module Bridgetown
19
55
  Tilt::ErubiTemplate.new(
20
56
  site.in_source_dir(site.config[:partials_dir], "#{partial_name}.erb"),
21
57
  outvar: "@_erbout",
22
- engine_class: Erubi::CaptureEndEngine
58
+ bufval: "Bridgetown::ERBBuffer.new",
59
+ engine_class: ERBEngine
23
60
  ).render(self, options)
24
61
  end
25
62
 
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)
63
+ def markdownify(input = nil, &block)
64
+ content = Bridgetown::Utils.reindent_for_markdown(
65
+ block.nil? ? input.to_s : capture(&block)
66
+ )
33
67
  converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
34
- md_output = converter.convert(content).strip
35
- @_erbout << md_output
68
+ converter.convert(content).strip
36
69
  end
37
70
 
38
- def capture
71
+ def capture(obj = nil, &block)
39
72
  previous_buffer_state = @_erbout
40
- @_erbout = +""
41
- result = yield
73
+ @_erbout = ERBBuffer.new
74
+
75
+ # For compatibility with ActionView, not used by Bridgetown normally
76
+ previous_ob_state = @output_buffer
77
+ @output_buffer = ERBBuffer.new
78
+
79
+ result = instance_exec(obj, &block)
80
+ if @output_buffer != ""
81
+ # use Rails' ActionView buffer if present
82
+ result = @output_buffer
83
+ end
42
84
  @_erbout = previous_buffer_state
85
+ @output_buffer = previous_ob_state
43
86
 
44
- result
87
+ result.respond_to?(:html_safe) ? result.html_safe : result
45
88
  end
46
89
  end
47
90
 
48
91
  module Converters
49
92
  class ERBTemplates < Converter
93
+ priority :highest
50
94
  input :erb
51
95
 
52
96
  # Logic to do the ERB content conversion.
@@ -62,7 +106,8 @@ module Bridgetown
62
106
  erb_renderer = Tilt::ErubiTemplate.new(
63
107
  convertible.relative_path,
64
108
  outvar: "@_erbout",
65
- engine_class: Erubi::CaptureEndEngine
109
+ bufval: "Bridgetown::ERBBuffer.new",
110
+ engine_class: ERBEngine
66
111
  ) { content }
67
112
 
68
113
  if convertible.is_a?(Bridgetown::Layout)
@@ -73,6 +118,20 @@ module Bridgetown
73
118
  erb_renderer.render(erb_view)
74
119
  end
75
120
  end
121
+
122
+ def matches(ext, convertible)
123
+ if convertible.data[:template_engine] == "erb" ||
124
+ (convertible.data[:template_engine].nil? &&
125
+ @config[:template_engine] == "erb")
126
+ return true
127
+ end
128
+
129
+ super(ext)
130
+ end
131
+
132
+ def output_ext(ext)
133
+ ext == ".erb" ? ".html" : ext
134
+ end
76
135
  end
77
136
  end
78
137
  end