bridgetown-core 0.16.0.beta1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/bridgetown-core.gemspec +3 -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/concerns/actions.rb +2 -1
  8. data/lib/bridgetown-core/commands/console.rb +4 -4
  9. data/lib/bridgetown-core/commands/new.rb +1 -1
  10. data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
  11. data/lib/bridgetown-core/concerns/liquid_renderable.rb +10 -0
  12. data/lib/bridgetown-core/concerns/site/configurable.rb +24 -22
  13. data/lib/bridgetown-core/concerns/site/content.rb +46 -33
  14. data/lib/bridgetown-core/concerns/site/extensible.rb +14 -13
  15. data/lib/bridgetown-core/concerns/site/localizable.rb +24 -0
  16. data/lib/bridgetown-core/concerns/site/processable.rb +12 -11
  17. data/lib/bridgetown-core/concerns/site/renderable.rb +35 -28
  18. data/lib/bridgetown-core/concerns/site/writable.rb +7 -15
  19. data/lib/bridgetown-core/concerns/validatable.rb +2 -2
  20. data/lib/bridgetown-core/configuration.rb +14 -6
  21. data/lib/bridgetown-core/converter.rb +0 -42
  22. data/lib/bridgetown-core/converters/erb_templates.rb +93 -17
  23. data/lib/bridgetown-core/converters/liquid_templates.rb +96 -0
  24. data/lib/bridgetown-core/converters/markdown.rb +0 -3
  25. data/lib/bridgetown-core/document.rb +34 -21
  26. data/lib/bridgetown-core/drops/site_drop.rb +5 -1
  27. data/lib/bridgetown-core/drops/unified_payload_drop.rb +0 -1
  28. data/lib/bridgetown-core/drops/url_drop.rb +19 -3
  29. data/lib/bridgetown-core/excerpt.rb +1 -1
  30. data/lib/bridgetown-core/filters.rb +37 -55
  31. data/lib/bridgetown-core/filters/condition_helpers.rb +56 -0
  32. data/lib/bridgetown-core/frontmatter_defaults.rb +17 -0
  33. data/lib/bridgetown-core/generators/prototype_generator.rb +42 -25
  34. data/lib/bridgetown-core/helpers.rb +84 -0
  35. data/lib/bridgetown-core/liquid_renderer.rb +1 -1
  36. data/lib/bridgetown-core/log_writer.rb +2 -2
  37. data/lib/bridgetown-core/page.rb +8 -2
  38. data/lib/bridgetown-core/plugin_manager.rb +44 -3
  39. data/lib/bridgetown-core/reader.rb +2 -4
  40. data/lib/bridgetown-core/readers/collection_reader.rb +1 -0
  41. data/lib/bridgetown-core/readers/data_reader.rb +4 -3
  42. data/lib/bridgetown-core/readers/defaults_reader.rb +27 -0
  43. data/lib/bridgetown-core/readers/layout_reader.rb +1 -0
  44. data/lib/bridgetown-core/readers/page_reader.rb +1 -0
  45. data/lib/bridgetown-core/readers/post_reader.rb +29 -15
  46. data/lib/bridgetown-core/readers/static_file_reader.rb +1 -0
  47. data/lib/bridgetown-core/renderer.rb +42 -160
  48. data/lib/bridgetown-core/ruby_template_view.rb +26 -8
  49. data/lib/bridgetown-core/site.rb +14 -2
  50. data/lib/bridgetown-core/tags/find.rb +86 -0
  51. data/lib/bridgetown-core/tags/t.rb +14 -0
  52. data/lib/bridgetown-core/tags/webpack_path.rb +6 -41
  53. data/lib/bridgetown-core/utils.rb +69 -2
  54. data/lib/bridgetown-core/utils/ruby_exec.rb +1 -1
  55. data/lib/bridgetown-core/version.rb +2 -2
  56. data/lib/bridgetown-core/watcher.rb +1 -0
  57. data/lib/site_template/src/_layouts/{default.html → default.liquid} +0 -0
  58. data/lib/site_template/src/_layouts/{home.html → home.liquid} +0 -0
  59. data/lib/site_template/src/_layouts/{page.html → page.liquid} +0 -0
  60. data/lib/site_template/src/_layouts/{post.html → post.liquid} +0 -0
  61. data/lib/site_template/src/images/.keep +1 -0
  62. metadata +47 -10
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ class DefaultsReader
5
+ attr_reader :site, :path_defaults
6
+
7
+ def initialize(site)
8
+ @site = site
9
+ @path_defaults = HashWithDotAccess::Hash.new
10
+ end
11
+
12
+ def read
13
+ return unless File.directory?(site.source)
14
+
15
+ entries = Dir.chdir(site.source) do
16
+ Dir["**/_defaults.{yaml,yml,json}"]
17
+ end
18
+
19
+ entries.each do |entry|
20
+ path = @site.in_source_dir(entry)
21
+ @path_defaults[File.dirname(path) + File::SEPARATOR] = SafeYAML.load_file(path)
22
+ end
23
+
24
+ @path_defaults
25
+ end
26
+ end
27
+ end
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class LayoutReader
5
5
  attr_reader :site
6
+
6
7
  def initialize(site)
7
8
  @site = site
8
9
  @layouts = {}
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class PageReader
5
5
  attr_reader :site, :dir, :unfiltered_content
6
+
6
7
  def initialize(site, dir)
7
8
  @site = site
8
9
  @dir = dir
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class PostReader
5
5
  attr_reader :site, :unfiltered_content
6
+
6
7
  def initialize(site)
7
8
  @site = site
8
9
  end
@@ -20,13 +21,13 @@ module Bridgetown
20
21
  # Read all the files in <source>/<dir>/<magic_dir> and create a new
21
22
  # Document object with each one insofar as it matches the regexp matcher.
22
23
  #
23
- # dir - The String relative path of the directory to read.
24
+ # @param dir [String] relative path of the directory to read.
24
25
  #
25
- # Returns nothing.
26
+ # @return [Array<Document, StaticFile>]
26
27
  def read_publishable(dir, magic_dir, matcher)
27
28
  read_content(dir, magic_dir, matcher)
28
- .tap { |entries| entries.select { |entry| entry.respond_to?(:read) }.each(&:read) }
29
- .select { |entry| processable?(entry) }
29
+ .tap { |items| items.select { |item| item.respond_to?(:read) }.each(&:read) }
30
+ .select { |item| item_added_to_site?(item) }
30
31
  end
31
32
 
32
33
  # Read all the content files from <source>/<dir>/magic_dir
@@ -69,26 +70,39 @@ module Bridgetown
69
70
  )
70
71
  end
71
72
 
72
- def processable?(doc)
73
- return true if doc.is_a?(StaticFile)
73
+ def processable?(item)
74
+ return true if item.is_a?(StaticFile)
74
75
 
75
- if doc.content.nil?
76
- Bridgetown.logger.debug "Skipping:", "Content in #{doc.relative_path} is nil"
76
+ if item.content.nil?
77
+ Bridgetown.logger.debug "Skipping:", "Content in #{item.relative_path} is nil"
77
78
  false
78
- elsif !doc.content.valid_encoding?
79
- Bridgetown.logger.debug "Skipping:", "#{doc.relative_path} is not valid UTF-8"
79
+ elsif !item.content.valid_encoding?
80
+ Bridgetown.logger.debug "Skipping:", "#{item.relative_path} is not valid UTF-8"
80
81
  false
81
82
  else
82
- publishable?(doc)
83
+ publishable?(item)
83
84
  end
84
85
  end
85
86
 
86
- def publishable?(doc)
87
- site.publisher.publish?(doc).tap do |will_publish|
88
- if !will_publish && site.publisher.hidden_in_the_future?(doc)
89
- Bridgetown.logger.warn "Skipping:", "#{doc.relative_path} has a future date"
87
+ def publishable?(item)
88
+ site.publisher.publish?(item).tap do |will_publish|
89
+ if !will_publish && site.publisher.hidden_in_the_future?(item)
90
+ Bridgetown.logger.warn "Skipping:", "#{item.relative_path} has a future date"
90
91
  end
91
92
  end
92
93
  end
94
+
95
+ def item_added_to_site?(item)
96
+ return false unless processable?(item)
97
+
98
+ if item.is_a?(Document)
99
+ site.posts.docs << item
100
+ elsif item.is_a?(StaticFile)
101
+ site.posts.files << item
102
+ site.static_files << item
103
+ end
104
+
105
+ true
106
+ end
93
107
  end
94
108
  end
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class StaticFileReader
5
5
  attr_reader :site, :dir, :unfiltered_content
6
+
6
7
  def initialize(site, dir)
7
8
  @site = site
8
9
  @dir = dir
@@ -3,37 +3,10 @@
3
3
  module Bridgetown
4
4
  class Renderer
5
5
  attr_reader :document, :site
6
- attr_writer :layouts, :payload
7
6
 
8
- class << self
9
- attr_accessor :cached_partials
10
- end
11
-
12
- def initialize(site, document, site_payload = nil)
7
+ def initialize(site, document)
13
8
  @site = site
14
9
  @document = document
15
- @payload = site_payload
16
- @layouts = nil
17
- self.class.cached_partials ||= {}
18
- end
19
-
20
- # Fetches the payload used in Liquid rendering.
21
- # It can be written with #payload=(new_payload)
22
- # Falls back to site.site_payload if no payload is set.
23
- #
24
- # Returns a Bridgetown::Drops::UnifiedPayloadDrop
25
- def payload
26
- @payload ||= site.site_payload
27
- end
28
-
29
- # The list of layouts registered for this Renderer.
30
- # It can be written with #layouts=(new_layouts)
31
- # Falls back to site.layouts if no layouts are registered.
32
- #
33
- # Returns a Hash of String => Bridgetown::Layout identified
34
- # as basename without the extension name.
35
- def layouts
36
- @layouts || site.layouts
37
10
  end
38
11
 
39
12
  # Determine which converters to use based on this document's
@@ -41,7 +14,13 @@ module Bridgetown
41
14
  #
42
15
  # Returns Array of Converter instances.
43
16
  def converters
44
- @converters ||= site.converters.select { |c| c.matches(document.extname) }.sort
17
+ @converters ||= site.converters.select do |converter|
18
+ if converter.method(:matches).arity == 1
19
+ converter.matches(document.extname)
20
+ else
21
+ converter.matches(document.extname, document)
22
+ end
23
+ end.sort
45
24
  end
46
25
 
47
26
  # Determine the extname the outputted file should have
@@ -51,93 +30,42 @@ module Bridgetown
51
30
  @output_ext ||= (permalink_ext || converter_output_ext)
52
31
  end
53
32
 
54
- # Prepare payload and render the document
33
+ # Run hooks and render the document
55
34
  #
56
35
  # Returns nothing
57
36
  def run
58
37
  Bridgetown.logger.debug "Rendering:", document.relative_path
59
38
 
60
- assign_pages!
61
- # TODO: this can be eliminated I think:
62
- assign_current_document!
63
- assign_highlighter_options!
64
- assign_layout_data!
65
-
66
- document.trigger_hooks(:pre_render, payload)
39
+ document.trigger_hooks :pre_render
67
40
  document.output = render_document
68
- document.trigger_hooks(:post_render)
41
+ document.trigger_hooks :post_render
69
42
  end
70
43
 
71
44
  # Render the document.
72
45
  #
73
46
  # Returns String rendered document output
74
- # rubocop: disable Metrics/AbcSize
75
47
  def render_document
76
- liquid_context = provide_liquid_context
77
-
78
48
  execute_inline_ruby!
79
49
 
80
50
  output = document.content
81
- if document.render_with_liquid?
82
- Bridgetown.logger.debug "Rendering Liquid:", document.relative_path
83
- output = render_liquid(output, payload, liquid_context, document.path)
84
- end
85
-
86
51
  Bridgetown.logger.debug "Rendering Markup:", document.relative_path
87
52
  output = convert(output.to_s, document)
88
53
  document.content = output
89
54
 
90
55
  if document.place_in_layout?
91
56
  Bridgetown.logger.debug "Rendering Layout:", document.relative_path
92
- output = place_in_layouts(output, payload, liquid_context)
57
+ output = place_in_layouts(output)
93
58
  end
94
59
 
95
60
  output
96
61
  end
97
62
 
98
- def provide_liquid_context
99
- {
100
- registers: {
101
- site: site,
102
- page: payload["page"],
103
- cached_partials: self.class.cached_partials,
104
- },
105
- strict_filters: liquid_options["strict_filters"],
106
- strict_variables: liquid_options["strict_variables"],
107
- }
108
- end
109
-
110
63
  def execute_inline_ruby!
111
64
  return unless site.config.should_execute_inline_ruby?
112
65
 
113
66
  Bridgetown::Utils::RubyExec.search_data_for_ruby_code(document, self)
114
67
  end
115
68
 
116
- # rubocop: enable Metrics/AbcSize
117
-
118
- # Render the given content with the payload and context
119
- #
120
- # content -
121
- # payload -
122
- # context -
123
- # path - (optional) the path to the file, for use in ex
124
- #
125
- # Returns String the content, rendered by Liquid.
126
- def render_liquid(content, payload, liquid_context, path = nil)
127
- template = site.liquid_renderer.file(path).parse(content)
128
- template.warnings.each do |e|
129
- Bridgetown.logger.warn "Liquid Warning:",
130
- LiquidRenderer.format_error(e, path || document.relative_path)
131
- end
132
- template.render!(payload, liquid_context)
133
- # rubocop: disable Lint/RescueException
134
- rescue Exception => e
135
- Bridgetown.logger.error "Liquid Exception:",
136
- LiquidRenderer.format_error(e, path || document.relative_path)
137
- raise e
138
- end
139
- # rubocop: enable Lint/RescueException
140
-
141
69
  # Convert the document using the converters which match this renderer's document.
142
70
  #
143
71
  # Returns String the converted content.
@@ -157,30 +85,18 @@ module Bridgetown
157
85
  end
158
86
  end
159
87
 
160
- # Checks if the layout specified in the document actually exists
161
- #
162
- # layout - the layout to check
163
- #
164
- # Returns Boolean true if the layout is invalid, false if otherwise
165
- def invalid_layout?(layout)
166
- !document.data["layout"].nil? && layout.nil? && !(document.is_a? Bridgetown::Excerpt)
167
- end
168
-
169
88
  # Render layouts and place document content inside.
170
89
  #
171
90
  # Returns String rendered content
172
- def place_in_layouts(content, payload, liquid_context)
91
+ def place_in_layouts(content)
173
92
  output = content.dup
174
- layout = layouts[document.data["layout"].to_s]
93
+ layout = site.layouts[document.data["layout"]]
175
94
  validate_layout(layout)
176
95
 
177
96
  used = Set.new([layout])
178
97
 
179
- # Reset the payload layout data to ensure it starts fresh for each page.
180
- payload["layout"] = nil
181
-
182
98
  while layout
183
- output = render_layout(output, layout, liquid_context)
99
+ output = render_layout(output, layout)
184
100
  add_regenerator_dependencies(layout)
185
101
 
186
102
  next unless (layout = site.layouts[layout.data["layout"]])
@@ -198,47 +114,45 @@ module Bridgetown
198
114
  # layout - the layout to check
199
115
  # Returns nothing
200
116
  def validate_layout(layout)
201
- return unless invalid_layout?(layout)
117
+ return unless document.data["layout"].present? &&
118
+ layout.nil? &&
119
+ !(document.is_a? Bridgetown::Excerpt)
202
120
 
203
121
  Bridgetown.logger.warn "Build Warning:", "Layout '#{document.data["layout"]}' requested " \
204
122
  "in #{document.relative_path} does not exist."
205
123
  end
206
124
 
125
+ def converters_for_layout(layout)
126
+ site.converters.select do |converter|
127
+ if converter.method(:matches).arity == 1
128
+ converter.matches(layout.ext)
129
+ else
130
+ converter.matches(layout.ext, layout)
131
+ end
132
+ end.sort
133
+ end
134
+
207
135
  # Render layout content into document.output
208
136
  #
209
137
  # Returns String rendered content
210
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
211
- def render_layout(output, layout, liquid_context)
212
- if layout.render_with_liquid?
213
- payload["content"] = output
214
- payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
138
+ def render_layout(output, layout)
139
+ layout_converters = converters_for_layout(layout)
215
140
 
216
- render_liquid(
217
- layout.content,
218
- payload,
219
- liquid_context,
220
- layout.path
221
- )
222
- else
223
- layout_converters ||= site.converters.select { |c| c.matches(layout.ext) }.sort
224
-
225
- layout_content = layout.content.dup
226
- layout_converters.reduce(layout_content) do |layout_output, converter|
227
- next(layout_output) unless converter.method(:convert).arity == 2
141
+ layout_content = layout.content.dup
142
+ layout_converters.reduce(layout_content) do |layout_output, converter|
143
+ next(layout_output) unless converter.method(:convert).arity == 2
228
144
 
229
- layout.current_document = document
230
- layout.current_document_output = output
231
- converter.convert layout_output, layout
232
- rescue StandardError => e
233
- Bridgetown.logger.error "Conversion error:",
234
- "#{converter.class} encountered an error while "\
235
- "converting '#{document.relative_path}':"
236
- Bridgetown.logger.error("", e.to_s)
237
- raise e
238
- end
145
+ layout.current_document = document
146
+ layout.current_document_output = output
147
+ converter.convert layout_output, layout
239
148
  end
149
+ rescue StandardError => e
150
+ Bridgetown.logger.error "Conversion error:",
151
+ "#{converter.class} encountered an error while "\
152
+ "converting '#{document.relative_path}':"
153
+ Bridgetown.logger.error("", e.to_s)
154
+ raise e
240
155
  end
241
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
242
156
 
243
157
  def add_regenerator_dependencies(layout)
244
158
  return unless document.write?
@@ -249,34 +163,6 @@ module Bridgetown
249
163
  )
250
164
  end
251
165
 
252
- # Set page content to payload and assign pager if document has one.
253
- #
254
- # Returns nothing
255
- def assign_pages!
256
- payload["page"] = document.to_liquid
257
- payload["paginator"] = (document.pager.to_liquid if document.respond_to?(:pager))
258
- end
259
-
260
- # Set related posts to payload if document is a post.
261
- #
262
- # Returns nothing
263
- def assign_current_document!
264
- payload["site"].current_document = document
265
- end
266
-
267
- # Set highlighter prefix and suffix
268
- #
269
- # Returns nothing
270
- def assign_highlighter_options!
271
- payload["highlighter_prefix"] = converters.first.highlighter_prefix
272
- payload["highlighter_suffix"] = converters.first.highlighter_suffix
273
- end
274
-
275
- def assign_layout_data!
276
- layout = layouts[document.data["layout"]]
277
- payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) if layout
278
- end
279
-
280
166
  def permalink_ext
281
167
  document_permalink = document.permalink
282
168
  if document_permalink && !document_permalink.end_with?("/")
@@ -298,9 +184,5 @@ module Bridgetown
298
184
  c.output_ext(document.extname)
299
185
  end.compact
300
186
  end
301
-
302
- def liquid_options
303
- @liquid_options ||= site.config["liquid"]
304
- end
305
187
  end
306
188
  end
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "digest"
4
+ require "active_support/core_ext/hash/keys"
4
5
 
5
6
  module Bridgetown
6
7
  class RubyTemplateView
7
- class Helpers
8
- include Bridgetown::Filters
9
- end
8
+ require "bridgetown-core/helpers"
10
9
 
11
- attr_reader :layout, :page, :site, :content
10
+ attr_reader :layout, :page, :paginator, :site, :content
12
11
 
13
12
  def initialize(convertible)
14
13
  if convertible.is_a?(Layout)
@@ -16,8 +15,10 @@ module Bridgetown
16
15
  @page = layout.current_document
17
16
  @content = layout.current_document_output
18
17
  else
18
+ @layout = convertible.site.layouts[convertible.data["layout"]]
19
19
  @page = convertible
20
20
  end
21
+ @paginator = page.paginator if page.respond_to?(:paginator)
21
22
  @site = page.site
22
23
  end
23
24
 
@@ -25,11 +26,20 @@ module Bridgetown
25
26
  raise "Must be implemented in a subclass"
26
27
  end
27
28
 
29
+ def render(item, options = {}, &block)
30
+ if item.respond_to?(:render_in)
31
+ item.render_in(self, &block)
32
+ else
33
+ partial(item, options, &block)
34
+ end
35
+ end
36
+
28
37
  def site_drop
29
38
  site.site_payload.site
30
39
  end
31
40
 
32
41
  def liquid_render(component, options = {})
42
+ options[:_block_content] = yield if block_given?
33
43
  render_statement = _render_statement(component, options)
34
44
 
35
45
  template = site.liquid_renderer.file(
@@ -43,7 +53,7 @@ module Bridgetown
43
53
  end
44
54
 
45
55
  def helpers
46
- @helpers ||= Helpers.new
56
+ @helpers ||= Helpers.new(self, site)
47
57
  end
48
58
 
49
59
  def method_missing(method, *args, &block)
@@ -61,11 +71,19 @@ module Bridgetown
61
71
  private
62
72
 
63
73
  def _render_statement(component, options)
64
- render_statement = ["{% render \"#{component}\""]
74
+ render_statement = if options[:_block_content]
75
+ ["{% rendercontent \"#{component}\""]
76
+ else
77
+ ["{% render \"#{component}\""]
78
+ end
65
79
  unless options.empty?
66
80
  render_statement << ", " + options.keys.map { |k| "#{k}: #{k}" }.join(", ")
67
81
  end
68
82
  render_statement << " %}"
83
+ if options[:_block_content]
84
+ render_statement << options[:_block_content]
85
+ render_statement << "{% endrendercontent %}"
86
+ end
69
87
  render_statement.join
70
88
  end
71
89
 
@@ -73,8 +91,8 @@ module Bridgetown
73
91
  {
74
92
  registers: {
75
93
  site: site,
76
- page: page,
77
- cached_partials: Bridgetown::Renderer.cached_partials,
94
+ page: page.to_liquid,
95
+ cached_partials: Bridgetown::Converters::LiquidTemplates.cached_partials,
78
96
  },
79
97
  strict_filters: site.config["liquid"]["strict_filters"],
80
98
  strict_variables: site.config["liquid"]["strict_variables"],