Note: I don’t use Clapper’s image popup plugin anymore, so the settings below are now gone.
Objective
To set up a user-friendly RSS feeds layout.
Background
I installed Clapper’s image popup plugin two months ago.1
Problem
As can be seen from Clapper’s RSS feed page, each popup image appears three times.
The HTML code provides some information about this problem.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Failed approach: change the CSS
I googled “xml css”, and learned the syntax for customizing the styles of an XML document from a site in Taiwan. Unluckily, this method failed change the display styles of my RSS feed page.
At the top of the source code of source/atom.xml
, I found two
<link>
tags, so I tried inserting an external CSS stylesheet, but it
also failed.
Solution
I searched “octopress rss css”, and found a page that I’ve
visited when I inserted some Ruby code into my Rakefile
to
submit new sitemaps.2
1 2 3 4 5 6 7 |
|
Some Ruby regular expressions learnt (TL;DR)
When it comes to regular expressions, my memory is poor and my efficiency is extremely slow. It’s just for me to recall some Ruby’s regular expression syntax.
Some special characters
\n
: newline/\//
: escaping/
in Ruby’s regular expression
Some metacharacters
For details, view the offical documentation.
/./
: Any character exception\n
\w/
: Any alphanumeric character or underscore/\D/
:/[^0-9]/
/\s/
:/[ \t\r\n\f]/
Some simple methods
I’ve learned two methods.
match
in Regexp classgsub
in String class- ‘g’ stands for “global”
1 2 3 4 5 6 7 8 9 10 11 |
|
My interpretation of the code of the above plugin
If I don’t write down the reasons for using the metacharacters, quantifiers, etc, now, it’s likely for me to forget them in a month.
/foo.bar/m
: With the trailingm
, the.
inside/
s matches any characters.
To match any characters (including\n
) inside a<td>
tag./a+?/
: non-greedy cousin of/a+/
To match<td>...</td>
, but not<td>...</td>...<td>...</td>
Parts of the matching pattern that I don’t undersand:
/\</
means the same as/</
./\>/
means the same as/>/
./\ /
means the same as/ /
.
I also don’t understand why ' '
is used, but not ''
in the
second argument of the above gsub
command.
Putting things together
I’ve changed my way of thinking: instead of changing the styles, I
decided to manipulate the contents. Once the HTML tags for the
redundant images had been removed, the Atom Feed should be better.
Re-reading the HTML code in my RSS page, I realized that three tags
could be stripped down: <div class="caption">
, <div
id="image-dialog-*">
and <div class="illustration print">
.
From Walter’s plugin, I knew that this involves writing Ruby code.
Any programmer will know that this can be done by using gsub
two
times. However, this is not beautiful. How about multiple
replacements in general? I found the last answer of
this question on Stack Overflow elegant. The arrow =>
in
variable map
fascinates me. At first, I thought that there’s a “map” object
in Ruby, and searched “ruby regex gsub map”, but I couldn’t see a webpage that
I, having no experience in writing Ruby code, could understand. It took me
some time to figure out that variable map
is actually a Hash.
I copied public/atom.xml
to my home folder and used a Ruby script to
test my method first. To avoid seeing broken things while previewing
the site, I didn’t directly modify plugins/custom_filter.rb
.
1 2 3 4 5 6 7 8 9 10 11 |
|
I didn’t have much time to study Ruby’s File I/O, so I just direct
the standard output to a file. Thus, within the Vim buffer that held
the file, I typed the following editor command. (The current directory
is ~
.)
:!ruby % atom.xml > atom_changed.xml
To compare the difference between the two XML files, the following command can be used.
:vertical diffsplit atom.xml atom_changed.xml
Of course diff -u
can be used, but since it’s the first time that
I compare the two files, I have no idea about the length of the
output. If the output length is greater than the buffer length of my
terminal, then I couldn’t see all the differences. vimdiff
directly enter Vim’s diff mode from the terminal. The ]c
mapping is
for jumping to the next difference.
With this keyboard shortcut, I could quickly browse through the files
and knew that the gsub
method had been correctly applied.
Therefore, I added a method in module CustomLiquidFilters
in
plugins/custom_filter.rb
.
I learnt to use method each_pair
in Hash class from an answer to
another Stack Overflow question about gsub
.
1 2 3 4 5 6 7 8 9 |
|
Moreover, similar to Walter’s modification to his source/atom.xml
,
to test my newly written code, I also needed to change it a little
bit.
1 2 3 4 |
|
Due to my limited knowledge in Jekyll, I can’t find a
way to escape the Liquid command inside an Octopress
codeblock.
Unfortunately, I got strange output from rake
.
[owner@localhost ~/octopress]$ rake generate
## Generating Site with Jekyll
unchanged sass/print.scss
identical source/stylesheets/screen.css
Configuration from /home/owner/octopress/_config.yml
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb:78:
in `require': /home/owner/octopress/plugins/custom_filter.rb:7: dynamic constant
assignment (SyntaxError)
RegexMap = {
^
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:78:in `block (2 levels) in setup'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:77:in `each'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:77:in `block in setup'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:76:in `each'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:76:in `setup'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb
:31:in `initialize'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/bin/jekyll:238:in
`new'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/bin/jekyll:238:in
`<top (required)>'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/bin/jekyll:23:in `load'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/bin/jekyll:23:in `<main>'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/bin/ruby_executable_hooks:15:in `eval
'
from /home/owner/.rvm/gems/ruby-1.9.3-p484/bin/ruby_executable_hooks:15:in `<mai
n>'
I searched “ruby dynamic constant assignment” on Google, and read the first search result, which was a Stack Overflow question. The answers on the top were very informative and I couldn’t comprehend them. I could just understand the last one.
After that, I tried to move the lines of code that defined hash
Regexp
outside of method remove_bigfig
, and generate the site
again. I encountered another error.
[owner@localhost ~/octopress]$ !rake
rake generate
## Generating Site with Jekyll
unchanged sass/print.scss
identical source/stylesheets/screen.css
Configuration from /home/owner/octopress/_config.yml
Building site: source -> public
Liquid Exception: undefined method `gsub' for #<Hash:0xa927e30> in atom.xm
l
/home/owner/octopress/plugins/octopress_filters.rb:81:in `expand_urls'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/context.rb:58
:in `invoke'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/variable.rb:4
3:in `block in render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/variable.rb:3
8:in `each'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/variable.rb:3
8:in `inject'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/variable.rb:3
8:in `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:94:i
n `block in render_all'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:92:i
n `collect'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:92:i
n `render_all'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/tags/for.rb:1
16:in `block (2 levels) in render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/tags/for.rb:1
04:in `each'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/tags/for.rb:1
04:in `each_with_index'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/tags/for.rb:1
04:in `block in render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/context.rb:91
:in `stack'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/tags/for.rb:1
03:in `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:94:i
n `block in render_all'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:92:i
n `collect'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:92:i
n `render_all'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/block.rb:82:i
n `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/template.rb:1
24:in `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/liquid-2.3.0/lib/liquid/template.rb:1
32:in `render!'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/convertible.
rb:79:in `do_layout'
/home/owner/octopress/plugins/post_filters.rb:167:in `do_layout'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/page.rb:100:
in `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb:204:
in `block in render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb:203:
in `each'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb:203:
in `render'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/lib/jekyll/site.rb:41:i
n `process'
/home/owner/.rvm/gems/ruby-1.9.3-p484/gems/jekyll-0.12.1/bin/jekyll:264:in `<top
(required)>'
/home/owner/.rvm/gems/ruby-1.9.3-p484/bin/jekyll:23:in `load'
/home/owner/.rvm/gems/ruby-1.9.3-p484/bin/jekyll:23:in `<main>'
/home/owner/.rvm/gems/ruby-1.9.3-p484/bin/ruby_executable_hooks:15:in `eval'
/home/owner/.rvm/gems/ruby-1.9.3-p484/bin/ruby_executable_hooks:15:in `<main>'
Build Failed
I tried googling “Liquid Exception: undefined method `gsub’ for”, but
the search weren’t useful to me. Appending the word “hash” to the
search string didn’t help. Finally, I changed it to “gsub hash”,
and clicked the first search result, which was
a Stack Overflow question. In the last row of the codeblock,
there’s a command which printed and returned the result. Not understanding
what the code truly did, I quickly knew the reason of the previous build
failure—the method remove_bigfig
wasn’t returning a String. I added the
variable to the last line of the method, and finally solved the problem.