I have a series of string manipulation, I realize this with the following code. I want it to be more elegant and readable such as str.sub_heading().sub_codeblock()...
, how could I rewrite my code?
def sub_heading(str)
str.gsub!(/^(#+)\w+/) {|m| m.gsub("#", "=")}
str.gsub!(/^(=+)(.+)/, '1円 2円 1円')
end
def sub_codeblock(str)
str.gsub!(/```(.+\n)((.|\n)+)```/, '{{{#!text_pygments 1円2円}}}')
end
def sub_inlinecode(str)
str.gsub!(/`(.+)`/, '{{{1円}}}')
end
def sub_bold(str)
str.gsub!(/([^\w]|^)\*\*\w[\w\s\d\-_'"]*\*\*([^\w]|$)/) {|m| m.gsub("**", "'''")}
end
def sub_italic(str)
str.gsub!(/([^*]|^)\*\w[\w\s\d\-_'"]*\*([^*]|$)/) {|m| m.gsub("*", "''")}
end
def sub_link(str)
str.gsub!(/\[\[(.+)\|(.+)\]\]/, '[[2円|1円]]')
end
sub_heading(inputdata)
sub_codeblock(inputdata)
sub_inlinecode(inputdata)
sub_bold(inputdata)
sub_italic(inputdata)
sub_link(inputdata)
2 Answers 2
You may collect the replacements in a Hash and call them on after the other.
replacements = {
/1/ => ' one ',
/2/ => ' two ',
/([34])/ => ' (1円 is three or four) ',
}
test = '123'
replacements.each{|regex, repl|
test.gsub!(regex, repl)
}
p test
The gsub
-version with blocks need a little trick:
replacements = {
/1/ => ' one ',
/2/ => ' two ',
/3/ => Proc.new{|m| m*2},
}
test = '123'
replacements.each{|regex, repl|
if repl.is_a?(Proc)
test.gsub!(regex){|m| repl.call(m)}
else
test.gsub!(regex, repl)
end
}
p test
In your case you may define your replacements with:
Replacements = {
# sub_heading
/^(#+)\w+/ => Proc.new{|m| m.gsub("#", "=")},
/^(=+)(.+)/ => '1円 2円 1円',
# sub_codeblock
/```(.+\n)((.|\n)+)```/ => '{{{#!text_pygments 1円2円}}}',
# sub_inlinecode
/`(.+)`/ => '{{{1円}}}',
# sub_bold
/([^\w]|^)\*\*\w[\w\s\d\-_'"]*\*\*([^\w]|$)/ => Proc.new{|m| m.gsub("**", "'''")},
# sub_italic
/([^*]|^)\*\w[\w\s\d\-_'"]*\*([^*]|$)/ => Proc.new{|m| m.gsub("*", "''")},
# sub_link
/\[\[(.+)\|(.+)\]\]/ => '[[2円|1円]]',
}
def my_replace(inputstring)
Replacements.each{|regex, repl|
if repl.is_a?(Proc)
inputstring.gsub!(regex){|m| repl.call(m)}
else
inputstring.gsub!(regex, repl)
end
}
end
my_replace(inputdata)
I want it to be more elegant and readable such as str.sub_heading().sub_codeblock()
If you want to call directly on String object you must open the class and add the methods.
If you want "str.method1.method2...." (which is the correct approach) you must not use in-place methods like sub!. So:
class String def sub_heading(str) gsub(/^(#+)\w+/) { |m| m.gsub("#", "=") }. gsub(/^(=+)(.+)/, '1円 2円 1円') end .... end
You get the idea for the others.
However, I woulnd't open a standard class to add such specific functions, write a class-method with this always (remember: create new strings, don't update).