FIlter question

13 views
Skip to first unread message

Pito Salas

unread,
Feb 26, 2021, 12:12:56 PM2/26/21
to na...@googlegroups.com
Hi!

I have this filter:

Nanoc::Filter.define(:handle_shortcodes) do |content, _params = {}|
result = ""
if content =~ /\$\$INCLUDE_TOPIC/
result = content.gsub(/^\$\$INCLUDE_TOPIC :(\w+)$/) { "<%= include_topic(#{$1}) %>" }
elsif content =~ /\$\$NEWSLIDE/
puts "1"
result = content.gsub(/^\$\$NEWSLIDE (\w+)$/) { "<slide_break></slide_break>\n\n####{$1}" }
else
result= content
end
result
end


I want it to match `$$INCLUDE_TOPIC :abc` and replace it with `<%= include_topic :abc %>`
and to match `$$NEWSLIDE this and that` and replace it with `<slide_break></slide_break #### this and that`

The weird stuff with result = "" is my ongoing attempts to make it work. What happens is that the filtered output includes the $$NEWSLIDE text which should have been excluded.

I tried it with a case vs. an if and that didn't help.

Help?


Pito Salas
Faculty, Computer Science
Brandeis University

Thomas Hochstein

unread,
Feb 27, 2021, 7:47:58 AM2/27/21
to na...@googlegroups.com
Pito Salas wrote:

> Nanoc::Filter.define(:handle_shortcodes) do |content, _params = {}|
> result = ""
> if content =~ /\$\$INCLUDE_TOPIC/
> result = content.gsub(/^\$\$INCLUDE_TOPIC :(\w+)$/) { "<%= include_topic(#{$1}) %>" }
> elsif content =~ /\$\$NEWSLIDE/
> puts "1"
> result = content.gsub(/^\$\$NEWSLIDE (\w+)$/) { "<slide_break></slide_break>\n\n####{$1}" }

That will replace $$INCLUDE_TOPIC if it is present in your content,
but will replace $$NEWSLIDE only if $$INCLUDE_TOPIC is _not_ present.

If you have both in your source file, your code will find
$$INCLUDE_TOPIC and do the replacement and then exit. If you want to
check for and replace both, "elsif" is the wrong way.

> It took a bit of struggle because until late I didn't realize that content wasn't a simple variable.

It is a "simple" variable containing all the content of your source
file.

> Could you give me an idea on how to clean it up?

You want to apply a list of substitutions to the content, i.e.
repeatedly do the same with different content; that's what a loop
does. So you could use a hash with the shorthand (i.e.
"$$INCLUDE_TOPIC") as key and the substitution as value and iterate
over it.

-thh

Pito Salas

unread,
Feb 27, 2021, 7:51:14 AM2/27/21
to na...@googlegroups.com
Thanks!

> It is a "simple" variable containing all the content of your source
> file.

It sure looked like it was one line at a time to me not the whole source file. Because in getting it to work I added a print statement under one of the ifs and it printed once for each occurrence of the matching string.

THanks,

Pito

Denis Defreyne

unread,
Feb 27, 2021, 9:14:49 AM2/27/21
to noreply-spamdigest via nanoc
Hey there,

Here’s my first iteration on the implementation:

Nanoc::Filter.define(:handle_shortcodes) do |content, _params = {}|
content
.gsub(/^\$\$INCLUDE_TOPIC :(\w+)$/) { "<%= include_topic(#{$1}) %>" }
.gsub(/^\$\$NEWSLIDE (\w+)$/) { "<slide_break></slide_break>\n\n####{$1}" }
end

This removes the check whether the content matches: if the content doesn’t match, `#gsub` will return the unmodified string anyway.

Depending on your personal preference, you could use `#gsub` with a second argument containing a string, rather than using the block:

Nanoc::Filter.define(:handle_shortcodes) do |content, _params = {}|
content
.gsub(/^\$\$INCLUDE_TOPIC :(\w+)$/, "<%= include_topic(\\1) %>")
.gsub(/^\$\$NEWSLIDE (\w+)$/, "<slide_break></slide_break>\n\n###\\1")
end

It’s slightly shorter. But both versions will do the trick.

Hope this helps,

Denis Defreyne
[dəˈni] • pronouns: he/him

-- 
You received this message because you are subscribed to the Google Groups "nanoc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nanoc+un...@googlegroups.com.


Pito Salas

unread,
Feb 27, 2021, 10:41:35 AM2/27/21
to na...@googlegroups.com
Thanks everyone for the great suggestions and clarifications.

Denis, one question, how often is the filter called and at what point in the pipeline? THanks,

Pito Salas
Faculty, Computer Science
Brandeis University

> To view this discussion on the web visit https://groups.google.com/d/msgid/nanoc/321057bf-e07a-4e1f-952d-3cf91fc4f0cd%40www.fastmail.com.

Thomas Hochstein

unread,
Feb 27, 2021, 11:40:06 AM2/27/21
to na...@googlegroups.com
Pito Salas wrote:

> Denis, one question, how often is the filter called and at what point in the pipeline? THanks,

That's up to your Rules file. You call you new filter like any other
filter that is bundled with Nanoc, i.e. erb or kramdown.

You include it everywhere you want in your rules with
| filter :handle_shortcodes

Please see <https://nanoc.ws/doc/rules/#filtering> for the relevant
documentation.

-thh

Pito Salas

unread,
Feb 27, 2021, 11:49:53 AM2/27/21
to na...@googlegroups.com
Yes, I got that. What I meant was, is the filter called once per file (per compile block), or once per line in a each file processed through each compile block filter clause?

Pito Salas
Faculty, Computer Science
Brandeis University

> --
> You received this message because you are subscribed to the Google Groups "nanoc" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to nanoc+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/nanoc/a5tk3gpgpvaol13vsl44mcc4p953ltdb7g%40scatha.ancalagon.de.

Thomas Hochstein

unread,
Feb 27, 2021, 12:54:14 PM2/27/21
to na...@googlegroups.com
Pito Salas wrote:

> Yes, I got that. What I meant was, is the filter called once per file
> (per compile block), or once per line in a each file processed
> through each compile block filter clause?

The former.

The filter is called once for each source file and will get the
content of that file in the content variable.

You can easily test that by using a filter like
| module Nanoc::Filters
| class Testfilter < Nanoc::Filter
| identifier :testfilt
| type :text
|
| def run(content, params={})
| puts content
| puts "=====\n"
| return content
| end
| end
| end

Call it with
| filter :testfilt

It will output the content of each file and a trailing "=====", but
not each line of each file followed by "=====".

-thh

Pito Salas

unread,
Feb 27, 2021, 12:56:32 PM2/27/21
to na...@googlegroups.com
Thanks a lot, that explains one thing that was confusing me :)

Pito Salas
Faculty, Computer Science
Brandeis University

> --
> You received this message because you are subscribed to the Google Groups "nanoc" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to nanoc+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/nanoc/pl1l3g153grvh7l45kl05rcli410lilmk1%40scatha.ancalagon.de.

Reply all
Reply to author
Forward
0 new messages