2
\$\begingroup\$

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)
seand
2,4651 gold badge20 silver badges29 bronze badges
asked Dec 12, 2011 at 13:05
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

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)
answered Dec 12, 2011 at 22:33
\$\endgroup\$
1
\$\begingroup\$

I want it to be more elegant and readable such as str.sub_heading().sub_codeblock()

  1. If you want to call directly on String object you must open the class and add the methods.

  2. 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).

answered Dec 14, 2011 at 13:41
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.