gsub + loop

E

Eleo

This question actually pertains to a Rails app but it's more of a
general Ruby question so I'll ask it here.

Within a body of text I'm trying to match URLs for
youtube/google/myspace/etc videos and replace them with their associated
embed codes. For each different site there is a different regular
expression and a different embed code. So I made a hash with each value
being an array containing the regular expression and replacement like:
{:videosite => [regexp, replacement]}. From there I figured I should
loop through the hash and check the text against each expression and
replace the URLs if necessary. Unfortunately I am having a problem:

http://pastie.caboo.se/64785

class Embedment < ActiveRecord::Base
def self.capture_embedments(text)
embedments = []
regexps.each do |k,v|
text.gsub!(v[0]) do |match|
embedments << embedment = self.new
embedment.html = v[1]
end
end

return embedments
end

def self.regexps
return {
:youtube => [/\(youtube:.*?(?:v=)?([\w|-]{11}).*\)/, "<object
width=\"425\" height=\"350\"><param name=\"movie\"
value=\"http://www.youtube.com/v/#{match[0]}\"></param><param
name=\"wmode\" value=\"transparent\"></param><embed
src=\"http://www.youtube.com/v/#{match[0]}\"
type=\"application/x-shockwave-flash\" wmode=\"transparent\"
width=\"425\" height=\"350\"></embed></object>"]
}
end
end

I think the flaw in my plan is that the second member of the array is
being parsed as soon as it's referenced, so this raises an exception
(undefined local variable or method `match' for Embedment:Class) since
the object 'match' does not exist yet. I'm guessing my approach to this
problem is very very wrong, but I have yet to see past my poor solution.
The reason why I separated the regular expressions from the method is
because there's going to be a few tens of them and I wanted to
consolidate them. Any help would be appreciated.
 
R

Robert Klemme

This question actually pertains to a Rails app but it's more of a
general Ruby question so I'll ask it here.

Within a body of text I'm trying to match URLs for
youtube/google/myspace/etc videos and replace them with their associated
embed codes. For each different site there is a different regular
expression and a different embed code. So I made a hash with each value
being an array containing the regular expression and replacement like:
{:videosite => [regexp, replacement]}. From there I figured I should
loop through the hash and check the text against each expression and
replace the URLs if necessary. Unfortunately I am having a problem:

http://pastie.caboo.se/64785

class Embedment < ActiveRecord::Base
def self.capture_embedments(text)
embedments = []
regexps.each do |k,v|
text.gsub!(v[0]) do |match|
embedments << embedment = self.new
embedment.html = v[1]
end
end

return embedments
end

def self.regexps
return {
:youtube => [/\(youtube:.*?(?:v=)?([\w|-]{11}).*\)/, "<object
width=\"425\" height=\"350\"><param name=\"movie\"
value=\"http://www.youtube.com/v/#{match[0]}\"></param><param
name=\"wmode\" value=\"transparent\"></param><embed
src=\"http://www.youtube.com/v/#{match[0]}\"
type=\"application/x-shockwave-flash\" wmode=\"transparent\"
width=\"425\" height=\"350\"></embed></object>"]
}
end
end

I think the flaw in my plan is that the second member of the array is
being parsed as soon as it's referenced, so this raises an exception
(undefined local variable or method `match' for Embedment:Class) since
the object 'match' does not exist yet.

You're right on!
I'm guessing my approach to this
problem is very very wrong, but I have yet to see past my poor solution.
The reason why I separated the regular expressions from the method is
because there's going to be a few tens of them and I wanted to
consolidate them. Any help would be appreciated.

You are not too far away. Just use proper regexp escapes in the
replacement string plus apply the replacement twice. So #{match[0]}
becomes \\& and #{match[1]} becomes \\1 etc.

class Embedment < ActiveRecord::Base
def self.capture_embedments(text)
embedments = []
REGEXPS.each do |k,v|
text.gsub!(v[0]) do |match|
embedment = new
embedments << embedment
embedment.html = match.sub(*v)
end
end

return embedments
end
end


Note also, that it's better to make the replacements a constant in the
class. And if you iterate only, you don't need symbols as keys, just do

REGEXPS = {
/\(youtube:.*?(?:v=)?([\w|-]{11}).*\)/ => "...",
}

And then

REGEXPS.each do |rx,repl|
text.gsub!(rx) do |match|
embedment = new
embedments << embedment
embedment.html = match.sub(rx,repl)
end
end

If you need more flexibility you can replace the replacement string with
a block. Then you can do

class Embedment
REGEXPS = {
/\(youtube:.*?(?:v=)?([\w|-]{11}).*\)/ =>
lambda {|match| "<!-- matched: #{match} -->" }
}
end


Then you can do

REGEXPS.each do |rx,repl|
text.gsub!(rx) do |match|
embedment = new
embedments << embedment
embedment.html = match.sub(rx,&repl)
end
end


Kind regards

robert
 
P

Paul Stickney

While not related to using gsub/regular expressions, consider an
option like hpricot?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top