Skip to content

Commit 6f51e52

Browse files
committed
Let Convert/Node filters to use context at calltime
1 parent 5b16b24 commit 6f51e52

File tree

7 files changed

+83
-8
lines changed

7 files changed

+83
-8
lines changed

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,15 @@ results tothe next filter. A pipeline has several kinds of filters available to
6060

6161
You can assemble each sequence into a single pipeline, or choose to call each filter individually.
6262

63-
As an example, suppose we want to transform Commonmark source text into Markdown HTML. With the content, we also want to:
63+
As an example, suppose we want to transform Commonmark source text into Markdown HTML:
6464

65-
- change every instance of `$NAME` to "`Johnny"
65+
```
66+
Hey there, @gjtorikian
67+
```
68+
69+
With the content, we also want to:
70+
71+
- change every instance of `Hey` to `Hello`
6672
- strip undesired HTML
6773
- linkify @mention
6874

@@ -73,7 +79,7 @@ require 'html_pipeline'
7379

7480
class HelloJohnnyFilter < HTMLPipelineFilter
7581
def call
76-
text.gsub("$NAME", "Johnny")
82+
text.gsub("Hey", "Hello")
7783
end
7884
end
7985

@@ -104,11 +110,21 @@ used to pass around arguments and metadata between filters in a pipeline. For
104110
example, if you want to disable footnotes in the `MarkdownFilter`, you can pass an option in the context hash:
105111

106112
```ruby
107-
context = { markdown: { extensions: { footnotes: false } } }
113+
context = { markdown: { extensions: { footnotes: false } } }
108114
filter = HTMLPipeline::ConvertFilter::MarkdownFilter.new(context: context)
109115
filter.call("Hi **world**!")
110116
```
111117

118+
Alternatively, you can construct a pipeline, and pass in a context during the call:
119+
120+
```ruby
121+
pipeline = HTMLPipeline.new(
122+
convert_filter: HTMLPipeline::ConvertFilter::MarkdownFilter.new,
123+
node_filters: [HTMLPipeline::NodeFilter::MentionFilter.new]
124+
)
125+
pipeline.call(user_supplied_text, context: { markdown: { extensions: { footnotes: false } } })
126+
```
127+
112128
Please refer to the documentation for each filter to understand what configuration options are available.
113129

114130
### More Examples

lib/html_pipeline.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,13 @@ def call(text, context: {}, result: {})
171171
text
172172
else
173173
instrument("call_convert_filter.html_pipeline", payload) do
174-
html = @convert_filter.call(text)
174+
html = @convert_filter.call(text, context: context)
175175
end
176176
end
177177

178178
unless @node_filters.empty?
179179
instrument("call_node_filters.html_pipeline", payload) do
180+
@node_filters.each { |filter| filter.context = (filter.context || {}).merge(context) }
180181
result[:output] = Selma::Rewriter.new(sanitizer: @sanitization_config, handlers: @node_filters).rewrite(html)
181182
html = result[:output]
182183
payload = default_payload({

lib/html_pipeline/convert_filter/markdown_filter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ def initialize(context: {}, result: {})
1616
end
1717

1818
# Convert Commonmark to HTML using the best available implementation.
19-
def call(text)
20-
options = @context.fetch(:markdown, {})
19+
def call(text, context: @context)
20+
options = context.fetch(:markdown, {})
2121
plugins = options.fetch(:plugins, {})
2222
Commonmarker.to_html(text, options: options, plugins: plugins).rstrip!
2323
end

lib/html_pipeline/node_filter.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
class HTMLPipeline
66
class NodeFilter < Filter
7+
attr_accessor :context
8+
79
def initialize(context: {}, result: {})
810
super(context: context, result: {})
911
send(:after_initialize) if respond_to?(:after_initialize)

test/html_pipeline_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,34 @@ def test_kitchen_sink
116116

117117
assert_equal("<p>!&gt;eeuqram/eeuqram&lt; ees ot evoL .yllib@ ,ereht <strong>yeH</strong></p>", result)
118118
end
119+
120+
def test_context_is_carried_over_in_call
121+
text = "yeH! I _think_ <marquee>@gjtorikian is ~great~</marquee>!"
122+
123+
pipeline = HTMLPipeline.new(
124+
text_filters: [YehBolderFilter.new],
125+
convert_filter: HTMLPipeline::ConvertFilter::MarkdownFilter.new,
126+
node_filters: [HTMLPipeline::NodeFilter::MentionFilter.new],
127+
)
128+
result = pipeline.call(text)[:output]
129+
130+
# note:
131+
# - yeH is bolded
132+
# - strikethroughs are rendered
133+
# - mentions are not linked
134+
assert_equal("<p><strong>yeH</strong>! I <em>think</em> <a href=\"/gjtorikian\">@gjtorikian</a> is <del>great</del>!</p>", result)
135+
136+
context = {
137+
no_bolding: false,
138+
markdown: { extension: { strikethrough: false } },
139+
base_url: "http://your-domain.com",
140+
}
141+
result_with_context = pipeline.call(text, context: context)[:output]
142+
143+
# note:
144+
# - yeH is not bolded
145+
# - strikethroughs are not rendered
146+
# - mentions are linked
147+
assert_equal("<p>yeH! I <em>think</em> <a href=\"http://your-domain.com/gjtorikian\">@gjtorikian</a> is ~great~!</p>", result_with_context)
148+
end
119149
end

test/sanitization_filter_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,5 +263,31 @@ def test_sanitization_pipeline_can_be_removed
263263

264264
assert_equal(result[:output].to_s, expected.chomp)
265265
end
266+
267+
def test_sanitization_pipeline_does_not_need_node_filters
268+
config = {
269+
elements: ["p", "pre", "code"],
270+
}
271+
272+
pipeline = HTMLPipeline.new(
273+
convert_filter:
274+
HTMLPipeline::ConvertFilter::MarkdownFilter.new,
275+
sanitization_config: config,
276+
)
277+
278+
result = pipeline.call(<<~CODE)
279+
This is *great*, @birdcar:
280+
281+
some_code(:first)
282+
CODE
283+
284+
expected = <<~HTML
285+
<p>This is great, @birdcar:</p>
286+
<pre><code>some_code(:first)
287+
</code></pre>
288+
HTML
289+
290+
assert_equal(result[:output].to_s, expected.chomp)
291+
end
266292
end
267293
end

test/test_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ def call(input, context: {}, result: {})
2525
# bolds any instance of the word yeH
2626
class YehBolderFilter < HTMLPipeline::TextFilter
2727
def call(input, context: {}, result: {})
28-
input.gsub("yeH", "**yeH**")
28+
input.gsub("yeH", "**yeH**") unless context[:no_bolding] == false
2929
end
3030
end

0 commit comments

Comments
 (0)