bridgetown-core 0.19.3 → 0.21.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/bridgetown-core.gemspec +1 -2
  3. data/lib/bridgetown-core.rb +37 -29
  4. data/lib/bridgetown-core/cleaner.rb +9 -3
  5. data/lib/bridgetown-core/collection.rb +177 -78
  6. data/lib/bridgetown-core/commands/base.rb +9 -0
  7. data/lib/bridgetown-core/commands/build.rb +0 -11
  8. data/lib/bridgetown-core/commands/concerns/git_helpers.rb +20 -0
  9. data/lib/bridgetown-core/commands/configure.rb +8 -3
  10. data/lib/bridgetown-core/commands/console.rb +4 -0
  11. data/lib/bridgetown-core/commands/doctor.rb +1 -19
  12. data/lib/bridgetown-core/commands/new.rb +6 -6
  13. data/lib/bridgetown-core/commands/plugins.rb +14 -13
  14. data/lib/bridgetown-core/commands/serve.rb +0 -14
  15. data/lib/bridgetown-core/commands/webpack.rb +75 -0
  16. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +12 -0
  17. data/lib/bridgetown-core/commands/webpack/setup.rb +4 -0
  18. data/lib/bridgetown-core/commands/webpack/update.rb +3 -0
  19. data/lib/bridgetown-core/commands/webpack/webpack.config.js +18 -0
  20. data/lib/{site_template/webpack.config.js.erb → bridgetown-core/commands/webpack/webpack.defaults.js.erb} +32 -16
  21. data/lib/bridgetown-core/component.rb +183 -0
  22. data/lib/bridgetown-core/concerns/data_accessible.rb +1 -0
  23. data/lib/bridgetown-core/concerns/front_matter_importer.rb +52 -0
  24. data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
  25. data/lib/bridgetown-core/concerns/site/configurable.rb +10 -10
  26. data/lib/bridgetown-core/concerns/site/content.rb +56 -15
  27. data/lib/bridgetown-core/concerns/site/localizable.rb +3 -5
  28. data/lib/bridgetown-core/concerns/site/processable.rb +6 -4
  29. data/lib/bridgetown-core/concerns/site/renderable.rb +26 -0
  30. data/lib/bridgetown-core/concerns/site/writable.rb +12 -2
  31. data/lib/bridgetown-core/concerns/validatable.rb +2 -5
  32. data/lib/bridgetown-core/configuration.rb +61 -33
  33. data/lib/bridgetown-core/configurations/bt-postcss.rb +6 -6
  34. data/lib/bridgetown-core/configurations/netlify.rb +1 -0
  35. data/lib/bridgetown-core/configurations/tailwindcss.rb +6 -6
  36. data/lib/bridgetown-core/converter.rb +23 -0
  37. data/lib/bridgetown-core/converters/erb_templates.rb +51 -35
  38. data/lib/bridgetown-core/converters/identity.rb +0 -9
  39. data/lib/bridgetown-core/converters/liquid_templates.rb +1 -1
  40. data/lib/bridgetown-core/converters/markdown.rb +14 -4
  41. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +5 -38
  42. data/lib/bridgetown-core/converters/ruby_templates.rb +17 -0
  43. data/lib/bridgetown-core/converters/smartypants.rb +3 -1
  44. data/lib/bridgetown-core/core_ext/psych.rb +19 -0
  45. data/lib/bridgetown-core/current.rb +10 -0
  46. data/lib/bridgetown-core/document.rb +9 -16
  47. data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
  48. data/lib/bridgetown-core/drops/page_drop.rb +4 -0
  49. data/lib/bridgetown-core/drops/relations_drop.rb +23 -0
  50. data/lib/bridgetown-core/drops/resource_drop.rb +83 -0
  51. data/lib/bridgetown-core/drops/site_drop.rb +33 -8
  52. data/lib/bridgetown-core/drops/unified_payload_drop.rb +5 -0
  53. data/lib/bridgetown-core/entry_filter.rb +17 -28
  54. data/lib/bridgetown-core/errors.rb +0 -2
  55. data/lib/bridgetown-core/filters.rb +3 -26
  56. data/lib/bridgetown-core/filters/from_liquid.rb +23 -0
  57. data/lib/bridgetown-core/filters/url_filters.rb +12 -0
  58. data/lib/bridgetown-core/frontmatter_defaults.rb +1 -1
  59. data/lib/bridgetown-core/generators/prototype_generator.rb +59 -20
  60. data/lib/bridgetown-core/helpers.rb +48 -9
  61. data/lib/bridgetown-core/layout.rb +53 -21
  62. data/lib/bridgetown-core/liquid_renderer/file.rb +1 -0
  63. data/lib/bridgetown-core/liquid_renderer/table.rb +1 -0
  64. data/lib/bridgetown-core/model/base.rb +138 -0
  65. data/lib/bridgetown-core/model/builder_origin.rb +40 -0
  66. data/lib/bridgetown-core/model/origin.rb +38 -0
  67. data/lib/bridgetown-core/model/repo_origin.rb +126 -0
  68. data/lib/bridgetown-core/page.rb +11 -2
  69. data/lib/bridgetown-core/plugin_manager.rb +1 -3
  70. data/lib/bridgetown-core/publisher.rb +8 -2
  71. data/lib/bridgetown-core/reader.rb +37 -22
  72. data/lib/bridgetown-core/readers/data_reader.rb +5 -5
  73. data/lib/bridgetown-core/readers/defaults_reader.rb +1 -1
  74. data/lib/bridgetown-core/readers/layout_reader.rb +1 -1
  75. data/lib/bridgetown-core/readers/page_reader.rb +1 -0
  76. data/lib/bridgetown-core/readers/post_reader.rb +5 -4
  77. data/lib/bridgetown-core/regenerator.rb +9 -2
  78. data/lib/bridgetown-core/related_posts.rb +9 -6
  79. data/lib/bridgetown-core/renderer.rb +6 -13
  80. data/lib/bridgetown-core/resource/base.rb +329 -0
  81. data/lib/bridgetown-core/resource/destination.rb +49 -0
  82. data/lib/bridgetown-core/resource/permalink_processor.rb +179 -0
  83. data/lib/bridgetown-core/resource/relations.rb +132 -0
  84. data/lib/bridgetown-core/resource/taxonomy_term.rb +34 -0
  85. data/lib/bridgetown-core/resource/taxonomy_type.rb +56 -0
  86. data/lib/bridgetown-core/resource/transformer.rb +177 -0
  87. data/lib/bridgetown-core/ruby_template_view.rb +11 -11
  88. data/lib/bridgetown-core/site.rb +13 -6
  89. data/lib/bridgetown-core/static_file.rb +33 -10
  90. data/lib/bridgetown-core/tags/highlight.rb +2 -15
  91. data/lib/bridgetown-core/tags/include.rb +1 -1
  92. data/lib/bridgetown-core/tags/post_url.rb +2 -2
  93. data/lib/bridgetown-core/url.rb +1 -0
  94. data/lib/bridgetown-core/utils.rb +49 -43
  95. data/lib/bridgetown-core/utils/require_gems.rb +60 -0
  96. data/lib/bridgetown-core/utils/ruby_exec.rb +6 -9
  97. data/lib/bridgetown-core/utils/ruby_front_matter.rb +39 -0
  98. data/lib/bridgetown-core/version.rb +2 -2
  99. data/lib/bridgetown-core/watcher.rb +2 -1
  100. data/lib/bridgetown-core/yaml_parser.rb +22 -0
  101. data/lib/site_template/config/.keep +0 -0
  102. data/lib/site_template/package.json.erb +4 -4
  103. data/lib/site_template/plugins/site_builder.rb +1 -1
  104. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +1 -1
  105. metadata +46 -41
  106. data/lib/bridgetown-core/external.rb +0 -58
  107. data/lib/bridgetown-core/page_without_a_file.rb +0 -17
  108. data/lib/bridgetown-core/path_manager.rb +0 -31
  109. data/lib/bridgetown-core/readers/collection_reader.rb +0 -23
  110. data/lib/bridgetown-core/readers/static_file_reader.rb +0 -25
  111. data/lib/bridgetown-core/utils/exec.rb +0 -26
  112. data/lib/bridgetown-core/utils/internet.rb +0 -37
  113. data/lib/bridgetown-core/utils/platforms.rb +0 -80
  114. data/lib/bridgetown-core/utils/thread_event.rb +0 -31
  115. data/lib/bridgetown-core/utils/win_tz.rb +0 -75
@@ -26,12 +26,15 @@ module Bridgetown
26
26
  # @return [Array<Page>]
27
27
  attr_accessor :pages
28
28
 
29
- attr_accessor :exclude, :include, :lsi, :highlighter, :permalink_style,
30
- :time, :future, :unpublished, :limit_posts,
31
- :keep_files, :baseurl, :data, :file_read_opts,
32
- :plugin_manager, :converters, :generators, :reader
29
+ # NOTE: Eventually pages will be deprecated once the Resource content engine
30
+ # is default
31
+ alias_method :generated_pages, :pages
33
32
 
34
- # Public: Initialize a new Site.
33
+ attr_accessor :permalink_style, :time, :baseurl, :data,
34
+ :file_read_opts, :plugin_manager, :converters,
35
+ :generators, :reader
36
+
37
+ # Initialize a new Site.
35
38
  #
36
39
  # config - A Hash containing site configuration details.
37
40
  def initialize(config)
@@ -46,7 +49,7 @@ module Bridgetown
46
49
 
47
50
  ensure_not_in_dest
48
51
 
49
- Bridgetown.sites << self
52
+ Bridgetown::Current.site = self
50
53
  Bridgetown::Hooks.trigger :site, :after_init, self
51
54
 
52
55
  reset # Processable
@@ -64,5 +67,9 @@ module Bridgetown
64
67
  end
65
68
  end
66
69
  end
70
+
71
+ def inspect
72
+ "#<Bridgetown::Site #{metadata.inspect.delete_prefix("{").delete_suffix("}")}>"
73
+ end
67
74
  end
68
75
  end
@@ -4,7 +4,7 @@ module Bridgetown
4
4
  class StaticFile
5
5
  extend Forwardable
6
6
 
7
- attr_reader :relative_path, :extname, :name, :data
7
+ attr_reader :relative_path, :extname, :name, :data, :site, :collection
8
8
 
9
9
  def_delegator :to_liquid, :to_json, :to_json
10
10
 
@@ -25,8 +25,7 @@ module Bridgetown
25
25
  # base - The String path to the <source>.
26
26
  # dir - The String path between <source> and the file.
27
27
  # name - The String filename of the file.
28
- # rubocop: disable Metrics/ParameterLists
29
- def initialize(site, base, dir, name, collection = nil)
28
+ def initialize(site, base, dir, name, collection = nil) # rubocop:disable Metrics/ParameterLists
30
29
  @site = site
31
30
  @base = base
32
31
  @dir = dir
@@ -34,9 +33,15 @@ module Bridgetown
34
33
  @collection = collection
35
34
  @relative_path = File.join(*[@dir, @name].compact)
36
35
  @extname = File.extname(@name)
37
- @data = @site.frontmatter_defaults.all(relative_path, type)
36
+ @data = @site.frontmatter_defaults.all(relative_path, type).with_dot_access
37
+ if site.uses_resource? && !data.permalink
38
+ data.permalink = if collection && !collection.builtin?
39
+ "/:collection/:path.*"
40
+ else
41
+ "/:path.*"
42
+ end
43
+ end
38
44
  end
39
- # rubocop: enable Metrics/ParameterLists
40
45
 
41
46
  # Returns source file path.
42
47
  def path
@@ -51,8 +56,11 @@ module Bridgetown
51
56
  #
52
57
  # Returns destination file path.
53
58
  def destination(dest)
54
- dest = @site.in_dest_dir(dest)
55
- @site.in_dest_dir(dest, Bridgetown::URL.unescape_path(url))
59
+ dest = site.in_dest_dir(dest)
60
+ dest_url = url
61
+ dest_url = dest_url.delete_prefix(site.baseurl) if site.uses_resource? &&
62
+ site.baseurl.present? && collection
63
+ site.in_dest_dir(dest, Bridgetown::URL.unescape_path(dest_url))
56
64
  end
57
65
 
58
66
  def destination_rel_dir
@@ -118,6 +126,15 @@ module Bridgetown
118
126
  @basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "")
119
127
  end
120
128
 
129
+ def relative_path_basename_without_prefix
130
+ return_path = Pathname.new("")
131
+ Pathname.new(cleaned_relative_path).each_filename do |filename|
132
+ return_path += filename unless filename.starts_with?("_")
133
+ end
134
+
135
+ (return_path.dirname + return_path.basename(".*")).to_s
136
+ end
137
+
121
138
  def placeholders
122
139
  {
123
140
  collection: @collection.label,
@@ -154,15 +171,21 @@ module Bridgetown
154
171
  # be overriden in the collection's configuration in bridgetown.config.yml.
155
172
  def url
156
173
  @url ||= begin
157
- base = if @collection.nil? || @collection.label == "posts"
174
+ newly_processed = false
175
+ special_posts_case = @collection&.label == "posts" &&
176
+ site.config.content_engine != "resource"
177
+ base = if @collection.nil? || special_posts_case
158
178
  cleaned_relative_path
179
+ elsif site.uses_resource?
180
+ newly_processed = true
181
+ Bridgetown::Resource::PermalinkProcessor.new(self).transform
159
182
  else
160
183
  Bridgetown::URL.new(
161
184
  template: @collection.url_template,
162
185
  placeholders: placeholders
163
186
  )
164
187
  end.to_s.chomp("/")
165
- base << extname
188
+ newly_processed ? base : "#{base}#{extname}"
166
189
  end
167
190
  end
168
191
 
@@ -174,7 +197,7 @@ module Bridgetown
174
197
  # Returns the front matter defaults defined for the file's URL and/or type
175
198
  # as defined in bridgetown.config.yml.
176
199
  def defaults
177
- @defaults ||= @site.frontmatter_defaults.all url, type
200
+ @defaults ||= site.frontmatter_defaults.all url, type
178
201
  end
179
202
 
180
203
  # Returns a debug string on inspecting the static file.
@@ -36,13 +36,11 @@ module Bridgetown
36
36
  code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, "")
37
37
 
38
38
  output =
39
- case context.registers[:site].highlighter
39
+ case context.registers[:site].config.highlighter
40
40
  when "rouge"
41
41
  render_rouge(code)
42
- when "pygments"
43
- render_pygments(code, context)
44
42
  else
45
- render_codehighlighter(code)
43
+ h(code).strip
46
44
  end
47
45
 
48
46
  rendered_output = add_code_tag(output)
@@ -72,13 +70,6 @@ module Bridgetown
72
70
  options
73
71
  end
74
72
 
75
- def render_pygments(code, _context)
76
- Bridgetown.logger.warn "Warning:", "Highlight Tag no longer supports" \
77
- " rendering with Pygments."
78
- Bridgetown.logger.warn "", "Using the default highlighter, Rouge, instead."
79
- render_rouge(code)
80
- end
81
-
82
73
  def render_rouge(code)
83
74
  require "rouge"
84
75
  formatter = ::Rouge::Formatters::HTMLLegacy.new(
@@ -92,10 +83,6 @@ module Bridgetown
92
83
  formatter.format(lexer.lex(code))
93
84
  end
94
85
 
95
- def render_codehighlighter(code)
96
- h(code).strip
97
- end
98
-
99
86
  def add_code_tag(code)
100
87
  code_attributes = [
101
88
  "class=\"language-#{@lang.to_s.tr("+", "-")}\"",
@@ -112,7 +112,7 @@ module Bridgetown
112
112
  def locate_include_file(context, file)
113
113
  includes_dirs = tag_includes_dirs(context)
114
114
  includes_dirs.each do |dir|
115
- path = PathManager.join(dir, file)
115
+ path = File.join(dir, file)
116
116
  return path if valid_include_file?(path, dir.to_s)
117
117
  end
118
118
  raise IOError, could_not_locate_message(file, includes_dirs)
@@ -77,14 +77,14 @@ module Bridgetown
77
77
  @context = context
78
78
  site = context.registers[:site]
79
79
 
80
- site.posts.docs.each do |document|
80
+ site.collections.posts.docs.each do |document|
81
81
  return relative_url(document) if @post == document
82
82
  end
83
83
 
84
84
  # New matching method did not match, fall back to old method
85
85
  # with deprecation warning if this matches
86
86
 
87
- site.posts.docs.each do |document|
87
+ site.collections.posts.docs.each do |document|
88
88
  next unless @post.deprecated_equality document
89
89
 
90
90
  Bridgetown::Deprecator.deprecation_message "A call to "\
@@ -129,6 +129,7 @@ module Bridgetown
129
129
  #
130
130
  # Returns the escaped path.
131
131
  def self.escape_path(path)
132
+ path = path.to_s
132
133
  return path if path.empty? || %r!^[a-zA-Z0-9./-]+$!.match?(path)
133
134
 
134
135
  # Because URI.escape doesn't escape "?", "[" and "]" by default,
@@ -4,12 +4,9 @@ module Bridgetown
4
4
  module Utils
5
5
  extend self
6
6
  autoload :Ansi, "bridgetown-core/utils/ansi"
7
- autoload :Exec, "bridgetown-core/utils/exec"
8
- autoload :Internet, "bridgetown-core/utils/internet"
7
+ autoload :RequireGems, "bridgetown-core/utils/require_gems"
9
8
  autoload :RubyExec, "bridgetown-core/utils/ruby_exec"
10
- autoload :Platforms, "bridgetown-core/utils/platforms"
11
- autoload :ThreadEvent, "bridgetown-core/utils/thread_event"
12
- autoload :WinTZ, "bridgetown-core/utils/win_tz"
9
+ autoload :RubyFrontMatterDSL, "bridgetown-core/utils/ruby_front_matter"
13
10
 
14
11
  # Constants for use in #slugify
15
12
  SLUGIFY_MODES = %w(raw default pretty simple ascii latin).freeze
@@ -74,38 +71,32 @@ module Bridgetown
74
71
  end
75
72
  end
76
73
 
77
- # Read array from the supplied hash favouring the singular key
78
- # and then the plural key, and handling any nil entries.
74
+ # Read array from the supplied hash, merging the singular key with the
75
+ # plural key as needing, and handling any nil or duplicate entries.
79
76
  #
80
- # hash - the hash to read from
81
- # singular_key - the singular key
82
- # plural_key - the plural key
83
- #
84
- # Returns an array
85
- def pluralized_array_from_hash(hash, singular_key, plural_key)
86
- array = []
87
- value = value_from_singular_key(hash, singular_key)
88
- value ||= value_from_plural_key(hash, plural_key)
77
+ # @param hsh [Hash] the hash to read from
78
+ # @param singular_key [Symbol] the singular key
79
+ # @param plural_key [Symbol] the plural key
80
+ # @return [Array]
81
+ def pluralized_array_from_hash(hsh, singular_key, plural_key)
82
+ array = [
83
+ hsh[singular_key],
84
+ value_from_plural_key(hsh, plural_key),
85
+ ]
89
86
 
90
- array << value
91
87
  array.flatten!
92
88
  array.compact!
89
+ array.uniq!
93
90
  array
94
91
  end
95
92
 
96
- def value_from_singular_key(hash, key)
97
- hash[key] if hash.key?(key) || (hash.default_proc && hash[key])
98
- end
99
-
100
- def value_from_plural_key(hash, key)
101
- if hash.key?(key) || (hash.default_proc && hash[key])
102
- val = hash[key]
103
- case val
104
- when String
105
- val.split
106
- when Array
107
- val.compact
108
- end
93
+ def value_from_plural_key(hsh, key)
94
+ val = hsh[key]
95
+ case val
96
+ when String
97
+ val.split
98
+ when Array
99
+ val.compact
109
100
  end
110
101
  end
111
102
 
@@ -124,17 +115,23 @@ module Bridgetown
124
115
 
125
116
  # Determines whether a given file has
126
117
  #
127
- # Returns true if the YAML front matter is present.
118
+ # @return [Boolean] if the YAML front matter is present.
128
119
  # rubocop: disable Naming/PredicateName
129
120
  def has_yaml_header?(file)
130
- File.open(file, "rb", &:readline).match? %r!\A---\s*\r?\n!
121
+ File.open(file, "rb", &:readline).match? Bridgetown::FrontMatterImporter::YAML_HEADER
122
+ rescue EOFError
123
+ false
124
+ end
125
+
126
+ def has_rbfm_header?(file)
127
+ File.open(file, "rb", &:readline).match? Bridgetown::FrontMatterImporter::RUBY_HEADER
131
128
  rescue EOFError
132
129
  false
133
130
  end
134
131
 
135
132
  # Determine whether the given content string contains Liquid Tags or Vaiables
136
133
  #
137
- # Returns true is the string contains sequences of `{%` or `{{`
134
+ # @return [Boolean] if the string contains sequences of `{%` or `{{`
138
135
  def has_liquid_construct?(content)
139
136
  return false if content.nil? || content.empty?
140
137
 
@@ -207,7 +204,7 @@ module Bridgetown
207
204
  slug.gsub!(%r!^\-|\-$!i, "")
208
205
 
209
206
  slug.downcase! unless cased
210
- Bridgetown.logger.warn("Warning:", "Empty `slug` generated for '#{string}'.") if slug.empty?
207
+
211
208
  slug
212
209
  end
213
210
 
@@ -347,7 +344,7 @@ module Bridgetown
347
344
 
348
345
  # Return an asset path based on the Webpack manifest file
349
346
  # @param site [Bridgetown::Site] The current site object
350
- # @param asset_type [String] js or css
347
+ # @param asset_type [String] js or css, or filename in manifest
351
348
  #
352
349
  # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
353
350
  # file isnt found
@@ -363,21 +360,30 @@ module Bridgetown
363
360
  manifest = JSON.parse(File.read(manifest_file))
364
361
 
365
362
  known_assets = %w(js css)
363
+ asset_path = nil
366
364
  if known_assets.include?(asset_type)
367
365
  asset_path = manifest["main.#{asset_type}"]
368
-
369
366
  log_webpack_asset_error(asset_type) && return if asset_path.nil?
370
-
371
- asset_path = asset_path.split("/").last
372
- return [static_frontend_path(site), asset_type, asset_path].join("/")
367
+ else
368
+ asset_path = manifest.find do |item, _|
369
+ item.sub(%r{^../(frontend/|src/)?}, "") == asset_type
370
+ end&.last
373
371
  end
374
372
 
375
- Bridgetown.logger.error("Unknown Webpack asset type", asset_type)
376
- nil
373
+ if asset_path
374
+ static_frontend_path(site, ["js", asset_path])
375
+ else
376
+ Bridgetown.logger.error("Unknown Webpack asset type", asset_type)
377
+ nil
378
+ end
377
379
  end
378
380
 
379
- def static_frontend_path(site)
380
- path_parts = [site.config["baseurl"].to_s.chomp("/"), "_bridgetown/static"]
381
+ def static_frontend_path(site, additional_parts = [])
382
+ path_parts = [
383
+ site.config["baseurl"].to_s.gsub(%r(^/|/$), ""),
384
+ "_bridgetown/static",
385
+ *additional_parts,
386
+ ]
381
387
  path_parts[0] = "/#{path_parts[0]}" unless path_parts[0].empty?
382
388
  Addressable::URI.parse(path_parts.join("/")).normalize.to_s
383
389
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ module RequireGems
6
+ class << self
7
+ #
8
+ # Require a gem or file if it's present, otherwise silently fail.
9
+ #
10
+ # names - a string gem name or array of gem names
11
+ #
12
+ def require_if_present(names)
13
+ Array(names).each do |name|
14
+ require name
15
+ rescue LoadError
16
+ Bridgetown.logger.debug "Couldn't load #{name}. Skipping."
17
+ yield(name, version_constraint(name)) if block_given?
18
+ false
19
+ end
20
+ end
21
+
22
+ #
23
+ # The version constraint required to activate a given gem.
24
+ #
25
+ # Returns a String version constraint in a parseable form for
26
+ # RubyGems.
27
+ def version_constraint
28
+ "> 0"
29
+ end
30
+
31
+ #
32
+ # Require a gem or gems. If it's not present, show a very nice error
33
+ # message that explains everything and is much more helpful than the
34
+ # normal LoadError.
35
+ #
36
+ # names - a string gem name or array of gem names
37
+ #
38
+ def require_with_graceful_fail(names)
39
+ Array(names).each do |name|
40
+ Bridgetown.logger.debug "Requiring:", name.to_s
41
+ require name
42
+ rescue LoadError => e
43
+ Bridgetown.logger.error "Dependency Error:", <<~MSG
44
+ Yikes! It looks like you don't have #{name} or one of its dependencies installed.
45
+ In order to use Bridgetown as currently configured, you'll need to install this gem.
46
+
47
+ If you've run Bridgetown with `bundle exec`, ensure that you have included the #{name}
48
+ gem in your Gemfile as well.
49
+
50
+ The full error message from Ruby is: '#{e.message}'
51
+
52
+ If you run into trouble, you can find helpful resources at https://www.bridgetownrb.com/docs/community/
53
+ MSG
54
+ raise Bridgetown::Errors::MissingDependencyException, name
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -5,8 +5,8 @@ module Bridgetown
5
5
  module RubyExec
6
6
  extend self
7
7
 
8
- # rubocop:disable Metrics/AbcSize
9
- def search_data_for_ruby_code(convertible, renderer)
8
+ # TODO: Deprecate storing Ruby code in YAML, Rb, etc. and just use native Ruby Front Matter
9
+ def search_data_for_ruby_code(convertible, renderer) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
10
10
  return if convertible.data.empty?
11
11
 
12
12
  # Iterate using `keys` here so inline Ruby script can add new data keys
@@ -14,24 +14,21 @@ module Bridgetown
14
14
  data_keys = convertible.data.keys
15
15
  data_keys.each do |k|
16
16
  v = convertible.data[k]
17
- next unless v.is_a?(Rb) || v.is_a?(Hash)
17
+ next unless v.is_a?(Rb) || v.is_a?(Hash) || v.is_a?(Proc)
18
18
 
19
- if v.is_a?(Hash)
19
+ if v.is_a?(Proc)
20
+ convertible.data[k] = convertible.instance_exec(&v)
21
+ elsif v.is_a?(Hash)
20
22
  v.each do |nested_k, nested_v|
21
23
  next unless nested_v.is_a?(Rb)
22
24
 
23
- Bridgetown.logger.debug("Executing inline Ruby…", convertible.relative_path)
24
25
  convertible.data[k][nested_k] = run(nested_v, convertible, renderer)
25
- Bridgetown.logger.debug("Inline Ruby completed!", convertible.relative_path)
26
26
  end
27
27
  else
28
- Bridgetown.logger.debug("Executing inline Ruby…", convertible.relative_path)
29
28
  convertible.data[k] = run(v, convertible, renderer)
30
- Bridgetown.logger.debug("Inline Ruby completed!", convertible.relative_path)
31
29
  end
32
30
  end
33
31
  end
34
- # rubocop:enable Metrics/AbcSize
35
32
 
36
33
  # Sets up a new context in which to eval Ruby coming from front matter.
37
34
  #