bridgetown-core 0.20.0 → 0.21.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bridgetown-core.rb +3 -0
  3. data/lib/bridgetown-core/collection.rb +13 -10
  4. data/lib/bridgetown-core/component.rb +178 -0
  5. data/lib/bridgetown-core/concerns/front_matter_importer.rb +52 -0
  6. data/lib/bridgetown-core/concerns/site/content.rb +2 -3
  7. data/lib/bridgetown-core/concerns/site/writable.rb +1 -1
  8. data/lib/bridgetown-core/concerns/validatable.rb +0 -4
  9. data/lib/bridgetown-core/configuration.rb +10 -9
  10. data/lib/bridgetown-core/converter.rb +9 -0
  11. data/lib/bridgetown-core/converters/erb_templates.rb +50 -34
  12. data/lib/bridgetown-core/converters/markdown.rb +1 -1
  13. data/lib/bridgetown-core/converters/ruby_templates.rb +17 -0
  14. data/lib/bridgetown-core/drops/relations_drop.rb +23 -0
  15. data/lib/bridgetown-core/drops/resource_drop.rb +3 -1
  16. data/lib/bridgetown-core/drops/unified_payload_drop.rb +1 -0
  17. data/lib/bridgetown-core/filters/from_liquid.rb +23 -0
  18. data/lib/bridgetown-core/helpers.rb +48 -9
  19. data/lib/bridgetown-core/layout.rb +27 -12
  20. data/lib/bridgetown-core/model/origin.rb +1 -1
  21. data/lib/bridgetown-core/model/{file_origin.rb → repo_origin.rb} +32 -25
  22. data/lib/bridgetown-core/reader.rb +2 -2
  23. data/lib/bridgetown-core/renderer.rb +1 -1
  24. data/lib/bridgetown-core/resource/base.rb +69 -27
  25. data/lib/bridgetown-core/resource/relations.rb +132 -0
  26. data/lib/bridgetown-core/resource/taxonomy_term.rb +10 -1
  27. data/lib/bridgetown-core/resource/taxonomy_type.rb +9 -0
  28. data/lib/bridgetown-core/resource/transformer.rb +14 -12
  29. data/lib/bridgetown-core/ruby_template_view.rb +7 -11
  30. data/lib/bridgetown-core/utils.rb +8 -1
  31. data/lib/bridgetown-core/utils/ruby_exec.rb +6 -9
  32. data/lib/bridgetown-core/utils/ruby_front_matter.rb +39 -0
  33. data/lib/bridgetown-core/version.rb +2 -2
  34. data/lib/bridgetown-core/watcher.rb +1 -1
  35. data/lib/site_template/package.json.erb +2 -2
  36. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +1 -1
  37. data/lib/site_template/webpack.config.js.erb +3 -1
  38. metadata +10 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c58653595832ef2fb9e6bbea3f147a0b3be9edae554d169e974570b84565a507
4
- data.tar.gz: 7af409e9a01570321171cf1afc562c00cacdcc6e0dce98f2b8eac4988a60e8d6
3
+ metadata.gz: 02c8827143ec0abe2adfa081ef1fe7723d8d000c4ecec5c6da1ddaa2ef9a8cdf
4
+ data.tar.gz: 2c81ef34075b80ce956f43b57b01b400852d4a30e3eca8587785febc5c82a850
5
5
  SHA512:
6
- metadata.gz: b21d9c304dd99dd306b70e97e172d1ec172f0d1fa48034610cc3d9e6bc9c40b98e7fe10479226103cb2ff501c22c7c2841f20630235262cc7214661be62bcf3e
7
- data.tar.gz: cab7afb0f441e412850ce648d6e7ca9a3996f106b0800c31ef24a0cf63af9db770498f307da275860c0572d6d6f2a5f1e56570d10349bb11cd4f17f96b3266ee
6
+ metadata.gz: f86157dcd3f2fb1139e490fcc1341e2508f4811bda806171e2374e4753cf14c6c121abbb2ceeb6536a925bfd1d1ecba44c6d35fb6ebd6c0bcad3b4ace8d73912
7
+ data.tar.gz: 9262363b23785be1ad111a611d7660201dd3e948e331fdcf5395afd8fde91f1cb075ba13d1729fcd537cd15e3d209c8016145af04c13f054f87bb37d46406617
@@ -38,6 +38,7 @@ require "active_support/core_ext/object/deep_dup"
38
38
  require "active_support/core_ext/object/inclusion"
39
39
  require "active_support/core_ext/string/inflections"
40
40
  require "active_support/core_ext/string/inquiry"
41
+ require "active_support/core_ext/string/output_safety"
41
42
  require "active_support/core_ext/string/starts_ends_with"
42
43
  require "active_support/current_attributes"
43
44
  require "active_support/descendants_tracker"
@@ -80,6 +81,7 @@ end
80
81
  module Bridgetown
81
82
  autoload :Cleaner, "bridgetown-core/cleaner"
82
83
  autoload :Collection, "bridgetown-core/collection"
84
+ autoload :Component, "bridgetown-core/component"
83
85
  autoload :Configuration, "bridgetown-core/configuration"
84
86
  autoload :DataAccessible, "bridgetown-core/concerns/data_accessible"
85
87
  autoload :Deprecator, "bridgetown-core/deprecator"
@@ -91,6 +93,7 @@ module Bridgetown
91
93
  # TODO: this is a poorly named, unclear class. Relocate to Utils:
92
94
  autoload :External, "bridgetown-core/external"
93
95
  autoload :FrontmatterDefaults, "bridgetown-core/frontmatter_defaults"
96
+ autoload :FrontMatterImporter, "bridgetown-core/concerns/front_matter_importer"
94
97
  autoload :Hooks, "bridgetown-core/hooks"
95
98
  autoload :Layout, "bridgetown-core/layout"
96
99
  autoload :LayoutPlaceable, "bridgetown-core/concerns/layout_placeable"
@@ -78,7 +78,8 @@ module Bridgetown
78
78
  if site.uses_resource?
79
79
  next if File.basename(file_path).starts_with?("_")
80
80
 
81
- if label == "data" || Utils.has_yaml_header?(full_path)
81
+ if label == "data" || Utils.has_yaml_header?(full_path) ||
82
+ Utils.has_rbfm_header?(full_path)
82
83
  read_resource(full_path)
83
84
  else
84
85
  read_static_file(file_path, full_path)
@@ -256,7 +257,7 @@ module Bridgetown
256
257
  sanitized_segment = sanitize_filename.(File.basename(segment, ".*"))
257
258
  hsh = nested.empty? ? data_contents : data_contents.dig(*nested)
258
259
  hsh[sanitized_segment] = if index == segments.length - 1
259
- data_resource.data.array || data_resource.data
260
+ data_resource.data.rows || data_resource.data
260
261
  else
261
262
  {}
262
263
  end
@@ -279,6 +280,16 @@ module Bridgetown
279
280
  data_contents
280
281
  end
281
282
 
283
+ # Read in resource from repo path
284
+ # @param full_path [String]
285
+ def read_resource(full_path)
286
+ id = "repo://#{label}.collection/" + Addressable::URI.escape(
287
+ Pathname(full_path).relative_path_from(Pathname(site.source)).to_s
288
+ )
289
+ resource = Bridgetown::Model::Base.find(id).to_resource.read!
290
+ resources << resource if site.unpublished || resource.published?
291
+ end
292
+
282
293
  private
283
294
 
284
295
  def container
@@ -290,14 +301,6 @@ module Bridgetown
290
301
  docs << doc if site.unpublished || doc.published?
291
302
  end
292
303
 
293
- def read_resource(full_path)
294
- id = "file://#{label}.collection/" + Addressable::URI.escape(
295
- Pathname(full_path).relative_path_from(Pathname(site.source)).to_s
296
- )
297
- resource = Bridgetown::Model::Base.find(id).to_resource.read!
298
- resources << resource if site.unpublished || resource.published?
299
- end
300
-
301
304
  def sort_docs!
302
305
  if metadata["sort_by"].is_a?(String)
303
306
  sort_docs_by_key!
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ class Component
5
+ extend Forwardable
6
+
7
+ def_delegators :@view_context, :helpers, :liquid_render, :partial
8
+
9
+ # @return [Bridgetown::Site]
10
+ attr_reader :site # will be nil unless you explicitly set a `@site` ivar
11
+
12
+ # @return [Bridgetown::RubyTemplateView, Bridgetown::Component]
13
+ attr_reader :view_context
14
+
15
+ class << self
16
+ attr_accessor :source_location
17
+
18
+ def inherited(child)
19
+ # Code cribbed from ViewComponent by GitHub:
20
+ # Derive the source location of the component Ruby file from the call stack
21
+ child.source_location = caller_locations(1, 10).reject do |l|
22
+ l.label == "inherited"
23
+ end[0].absolute_path
24
+
25
+ super
26
+ end
27
+
28
+ # Return the appropriate template renderer for a given extension.
29
+ # TODO: make this extensible
30
+ #
31
+ # @param ext [String] erb, slim, etc.
32
+ def renderer_for_ext(ext, &block)
33
+ case ext
34
+ when "erb"
35
+ include ERBCapture
36
+ Tilt::ErubiTemplate.new(component_template_path,
37
+ outvar: "@_erbout",
38
+ bufval: "Bridgetown::OutputBuffer.new",
39
+ engine_class: Bridgetown::ERBEngine,
40
+ &block)
41
+ when "serb" # requires serbea
42
+ include Serbea::Helpers
43
+ Tilt::SerbeaTemplate.new(component_template_path, &block)
44
+ when "slim" # requires bridgetown-slim
45
+ Slim::Template.new(component_template_path, &block)
46
+ when "haml" # requires bridgetown-haml
47
+ Tilt::HamlTemplate.new(component_template_path, &block)
48
+ else
49
+ raise NameError
50
+ end
51
+ rescue NameError, LoadError
52
+ raise "No component rendering engine could be found for .#{ext} templates"
53
+ end
54
+
55
+ # Find the first matching template path based on source location and extension.
56
+ #
57
+ # @return [String]
58
+ def component_template_path
59
+ stripped_path = File.join(
60
+ File.dirname(source_location),
61
+ File.basename(source_location, ".*")
62
+ )
63
+ supported_template_extensions.each do |ext|
64
+ test_path = "#{stripped_path}.#{ext}"
65
+ return test_path if File.exist?(test_path)
66
+
67
+ test_path = "#{stripped_path}.html.#{ext}"
68
+ return test_path if File.exist?(test_path)
69
+ end
70
+
71
+ raise "No matching templates could be found in #{File.dirname(source_location)}"
72
+ end
73
+
74
+ # Read the template file.
75
+ #
76
+ # @return [String]
77
+ def component_template_content
78
+ File.read(component_template_path)
79
+ end
80
+
81
+ # A list of extensions supported by the renderer
82
+ # TODO: make this extensible
83
+ #
84
+ # @return [Array<String>]
85
+ def supported_template_extensions
86
+ %w(erb serb slim haml)
87
+ end
88
+ end
89
+
90
+ # If a content block was originally passed into via `render`, capture its output.
91
+ #
92
+ # @return [String] or nil
93
+ def content
94
+ @_content ||= begin
95
+ view_context.capture(self, &@_content_block) if @_content_block
96
+ end
97
+ end
98
+
99
+ # Provide a render helper for evaluation within the component context.
100
+ #
101
+ # @param item [Object] a component supporting `render_in` or a partial name
102
+ # @param options [Hash] passed to the `partial` helper if needed
103
+ # @return [String]
104
+ def render(item, options = {}, &block)
105
+ if item.respond_to?(:render_in)
106
+ result = ""
107
+ capture do # this ensures no leaky interactions between BT<=>VC blocks
108
+ result = item.render_in(self, &block)
109
+ end
110
+ result&.html_safe
111
+ else
112
+ partial(item, options, &block)&.html_safe
113
+ end
114
+ end
115
+
116
+ # This is where the magic happens. Render the component within a view context.
117
+ #
118
+ # @param view_context [Bridgetown::RubyTemplateView]
119
+ def render_in(view_context, &block)
120
+ @view_context = view_context
121
+ @_content_block = block
122
+
123
+ if render?
124
+ before_render
125
+ template
126
+ else
127
+ ""
128
+ end
129
+ rescue StandardError => e
130
+ Bridgetown.logger.error "Component error:",
131
+ "#{self.class} encountered an error while "\
132
+ "rendering `#{self.class.component_template_path}'"
133
+ raise e
134
+ end
135
+
136
+ # Subclasses can override this method to return a string from their own
137
+ # template handling.
138
+ def template
139
+ call || _renderer.render(self)
140
+ end
141
+
142
+ # Typically not used but here as a compatibility nod toward ViewComponent.
143
+ def call
144
+ nil
145
+ end
146
+
147
+ # Subclasses can override this method to perform tasks before a render.
148
+ def before_render; end
149
+
150
+ # Subclasses can override this method to determine if the component should
151
+ # be rendered based on initialized data or other logic.
152
+ def render?
153
+ true
154
+ end
155
+
156
+ def _renderer
157
+ # TODO: figure out a way to compile templates for increased performance
158
+ @_renderer ||= begin
159
+ ext = File.extname(self.class.component_template_path).delete_prefix(".")
160
+ self.class.renderer_for_ext(ext) { self.class.component_template_content }
161
+ end
162
+ end
163
+
164
+ # rubocop:disable Style/MissingRespondToMissing
165
+ ruby2_keywords def method_missing(method, *args, &block)
166
+ if helpers.respond_to?(method.to_sym)
167
+ helpers.send method.to_sym, *args, &block
168
+ else
169
+ super
170
+ end
171
+ end
172
+
173
+ def respond_to_missing?(method, include_private = false)
174
+ helpers.respond_to?(method.to_sym, include_private) || super
175
+ end
176
+ # rubocop:enable Style/MissingRespondToMissing
177
+ end
178
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module FrontMatterImporter
5
+ # Requires klass#content and klass#front_matter_line_count accessors
6
+ def self.included(klass)
7
+ klass.include Bridgetown::Utils::RubyFrontMatterDSL
8
+ end
9
+
10
+ YAML_HEADER = %r!\A---\s*\n!.freeze
11
+ YAML_BLOCK = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m.freeze
12
+ RUBY_HEADER = %r!\A[~`#\-]{3,}(?:ruby|<%|{%)\s*\n!.freeze
13
+ RUBY_BLOCK =
14
+ %r!#{RUBY_HEADER.source}(.*?\n?)^((?:%>|%})?[~`#\-]{3,}\s*$\n?)!m.freeze
15
+
16
+ def read_front_matter(file_path) # rubocop:todo Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
17
+ file_contents = File.read(
18
+ file_path, **Bridgetown::Utils.merged_file_read_opts(Bridgetown::Current.site, {})
19
+ )
20
+ yaml_content = file_contents.match(YAML_BLOCK)
21
+ if !yaml_content && Bridgetown::Current.site.config.should_execute_inline_ruby?
22
+ ruby_content = file_contents.match(RUBY_BLOCK)
23
+ end
24
+
25
+ if yaml_content
26
+ self.content = yaml_content.post_match
27
+ self.front_matter_line_count = yaml_content[1].lines.size - 1
28
+ SafeYAML.load(yaml_content[1])
29
+ elsif ruby_content
30
+ # rbfm header + content underneath
31
+ self.content = ruby_content.post_match
32
+ self.front_matter_line_count = ruby_content[1].lines.size
33
+ process_ruby_data(ruby_content[1], file_path, 2)
34
+ elsif Bridgetown::Utils.has_rbfm_header?(file_path)
35
+ process_ruby_data(File.read(file_path).lines[1..-1].join("\n"), file_path, 2)
36
+ elsif is_a?(Layout)
37
+ self.content = file_contents
38
+ {}
39
+ else
40
+ yaml_data = SafeYAML.load_file(file_path)
41
+ yaml_data.is_a?(Array) ? { rows: yaml_data } : yaml_data
42
+ end
43
+ end
44
+
45
+ def process_ruby_data(rubycode, file_path, starting_line)
46
+ ruby_data = instance_eval(rubycode, file_path.to_s, starting_line)
47
+ ruby_data.is_a?(Array) ? { rows: ruby_data } : ruby_data.to_h
48
+ rescue StandardError => e
49
+ raise "Ruby code isn't returning an array, or object which responds to `to_h' (#{e.message})"
50
+ end
51
+ end
52
+ end
@@ -173,9 +173,8 @@ class Bridgetown::Site
173
173
  documents.select(&:write?)
174
174
  end
175
175
 
176
- # Get all documents.
177
- # @return [Array<Document>] an array of documents from the
178
- # configuration
176
+ # Get all loaded resources.
177
+ # @return [Array<Bridgetown::Resource::Base>] an array of resources
179
178
  def resources
180
179
  collections.each_with_object(Set.new) do |(_, collection), set|
181
180
  set.merge(collection.resources)
@@ -21,7 +21,7 @@ class Bridgetown::Site
21
21
  end
22
22
 
23
23
  # Yields all content objects while looping through {#pages},
24
- # {#static_files_to_write}, and {#docs_to_write}.
24
+ # {#static_files_to_write}, {#docs_to_write}, {#resources_to_write}.
25
25
  #
26
26
  # @yieldparam item [Document, Page, StaticFile]
27
27
  #
@@ -3,10 +3,6 @@
3
3
  module Bridgetown
4
4
  # TODO: to be retired once the Resource engine is made official
5
5
  module Validatable
6
- # FIXME: there should be ONE TRUE METHOD to read the YAML frontmatter
7
- # in the entire project. Both this and the equivalent Document method
8
- # should be extracted and generalized.
9
- #
10
6
  # Read the YAML frontmatter.
11
7
  #
12
8
  # base - The String path to the dir containing the file.
@@ -74,15 +74,16 @@ module Bridgetown
74
74
  },
75
75
 
76
76
  "kramdown" => {
77
- "auto_ids" => true,
78
- "toc_levels" => (1..6).to_a,
79
- "entity_output" => "as_char",
80
- "smart_quotes" => "lsquo,rsquo,ldquo,rdquo",
81
- "input" => "GFM",
82
- "hard_wrap" => false,
83
- "guess_lang" => true,
84
- "footnote_nr" => 1,
85
- "show_warnings" => false,
77
+ "auto_ids" => true,
78
+ "toc_levels" => (1..6).to_a,
79
+ "entity_output" => "as_char",
80
+ "smart_quotes" => "lsquo,rsquo,ldquo,rdquo",
81
+ "input" => "GFM",
82
+ "hard_wrap" => false,
83
+ "guess_lang" => true,
84
+ "footnote_nr" => 1,
85
+ "show_warnings" => false,
86
+ "include_extraction_tags" => false,
86
87
  },
87
88
  }.each_with_object(Configuration.new) { |(k, v), hsh| hsh[k] = v.freeze }.freeze
88
89
 
@@ -53,6 +53,15 @@ module Bridgetown
53
53
  ".html"
54
54
  end
55
55
 
56
+ def line_start(convertible)
57
+ if convertible.is_a?(Bridgetown::Resource::Base) &&
58
+ convertible.model.origin.respond_to?(:front_matter_line_count)
59
+ convertible.model.origin.front_matter_line_count + 4
60
+ else
61
+ 1
62
+ end
63
+ end
64
+
56
65
  def inspect
57
66
  "#<#{self.class}#{self.class.extname_list ? " #{self.class.extname_list.join(", ")}" : nil}>"
58
67
  end
@@ -3,14 +3,26 @@
3
3
  require "tilt/erubi"
4
4
 
5
5
  module Bridgetown
6
- class ERBBuffer < String
7
- def concat_to_s(input)
8
- concat input.to_s
6
+ class OutputBuffer < ActiveSupport::SafeBuffer
7
+ def initialize(*)
8
+ super
9
+ encode!
9
10
  end
10
11
 
11
- alias_method :safe_append=, :concat_to_s
12
- alias_method :append=, :concat_to_s
13
- alias_method :safe_expr_append=, :concat_to_s
12
+ def <<(value)
13
+ return self if value.nil?
14
+
15
+ super(value.to_s)
16
+ end
17
+ alias_method :append=, :<<
18
+
19
+ def safe_expr_append=(val)
20
+ return self if val.nil? # rubocop:disable Lint/ReturnInVoidContext
21
+
22
+ safe_concat val.to_s
23
+ end
24
+
25
+ alias_method :safe_append=, :safe_concat
14
26
  end
15
27
 
16
28
  class ERBEngine < Erubi::Engine
@@ -22,24 +34,47 @@ module Bridgetown
22
34
  @src << ";" unless code[Erubi::RANGE_LAST] == "\n"
23
35
  end
24
36
 
37
+ def add_text(text)
38
+ return if text.empty?
39
+
40
+ src << bufvar << ".safe_append='"
41
+ src << text.gsub(%r{['\\]}, '\\\\\&')
42
+ src << "'.freeze;"
43
+ end
44
+
25
45
  # pulled from Rails' ActionView
26
46
  BLOCK_EXPR = %r!\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z!.freeze
27
47
 
28
48
  def add_expression(indicator, code)
49
+ src << bufvar << if (indicator == "==") || @escape
50
+ ".safe_expr_append="
51
+ else
52
+ ".append="
53
+ end
54
+
29
55
  if BLOCK_EXPR.match?(code)
30
- src << "#{@bufvar}.append= " << code
56
+ src << " " << code
31
57
  else
32
- super
58
+ src << "(" << code << ");"
33
59
  end
34
60
  end
61
+ end
35
62
 
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)
63
+ module ERBCapture
64
+ def capture(*args)
65
+ previous_buffer_state = @_erbout
66
+ @_erbout = OutputBuffer.new
67
+ result = yield(*args)
68
+ result = @_erbout.presence || result
69
+ @_erbout = previous_buffer_state
70
+
71
+ result.is_a?(String) ? ERB::Util.h(result) : result
39
72
  end
40
73
  end
41
74
 
42
75
  class ERBView < RubyTemplateView
76
+ include ERBCapture
77
+
43
78
  def h(input)
44
79
  Erubi.h(input)
45
80
  end
@@ -55,30 +90,10 @@ module Bridgetown
55
90
  Tilt::ErubiTemplate.new(
56
91
  site.in_source_dir(site.config[:partials_dir], "#{partial_name}.erb"),
57
92
  outvar: "@_erbout",
58
- bufval: "Bridgetown::ERBBuffer.new",
93
+ bufval: "Bridgetown::OutputBuffer.new",
59
94
  engine_class: ERBEngine
60
95
  ).render(self, options)
61
96
  end
62
-
63
- def markdownify(input = nil, &block)
64
- content = Bridgetown::Utils.reindent_for_markdown(
65
- block.nil? ? input.to_s : capture(&block)
66
- )
67
- converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
68
- result = converter.convert(content).strip
69
- result.respond_to?(:html_safe) ? result.html_safe : result
70
- end
71
-
72
- def capture(*args, &block)
73
- return capture_in_view_component(*args, &block) if @in_view_component
74
-
75
- previous_buffer_state = @_erbout
76
- @_erbout = ERBBuffer.new
77
- result = yield(*args)
78
- @_erbout = previous_buffer_state
79
-
80
- result.respond_to?(:html_safe) ? result.html_safe : result
81
- end
82
97
  end
83
98
 
84
99
  module Converters
@@ -100,14 +115,15 @@ module Bridgetown
100
115
 
101
116
  erb_renderer = Tilt::ErubiTemplate.new(
102
117
  convertible.relative_path,
118
+ line_start(convertible),
103
119
  outvar: "@_erbout",
104
- bufval: "Bridgetown::ERBBuffer.new",
120
+ bufval: "Bridgetown::OutputBuffer.new",
105
121
  engine_class: ERBEngine
106
122
  ) { content }
107
123
 
108
124
  if convertible.is_a?(Bridgetown::Layout)
109
125
  erb_renderer.render(erb_view) do
110
- convertible.current_document_output
126
+ convertible.current_document_output.html_safe
111
127
  end
112
128
  else
113
129
  erb_renderer.render(erb_view)