You have an app that has a note field and you don’t allow HTML in that field. The users would like the ability to add links into that field. How about implementing a link discovery feature?
Sounds great. Where do I start?
Let’s say you want to make a note that says “The url https://www.sitepoint.com/ruby/ should be a link” The URL should turn into a link.
Getting Started
Let’s make a new Ruby file
$ touch make_url.rb
Open that new file up and add the following code.
make_url.rb
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
puts NOTE
When you run that code you will see the NOTE output to the screen.
$ ruby make_url.rb
The url https://www.sitepoint.com/ruby/ should be a link
That really doesn’t get us anywhere. We need to see if there is a URL somewhere in that string. One way is to split the string, look at each word, and see if they match the pattern of a URL.
Let’s split the string and look at the individual words.
make_url.rb
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def hasURL(note)
words = note.split
words.each do |word|
puts word
end
end
hasURL(NOTE)
Run that and you see each individual word.
$ ruby make_url.rb
The
url
https://www.sitepoint.com/ruby/
should
be
a
link
Split takes the string and will split it into an array. The default delimiter for splitting is whitespace. This gives us an array of words that we can individually test against a URL pattern.
make_url.rb
require 'uri'
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def isURL(word)
if word =~ URI::regexp
puts '---- we have a URL! => ' + word
else
puts word
end
end
def hasURL(note)
words = note.split
words.each do |word|
isURL(word)
end
end
hasURL(NOTE)
Let’s run that and wee what we get.
$ ruby make_url.rb
The
url
---- we have a URL! => https://www.sitepoint.com/ruby/
should
be
a
link
It works! You might be wondering what that URI::regexp
does. It checks to see if it’s a URI like string, returning true if we have a URL. Ruby is great.
We can use our new knowledge to create links.
make_url.rb
require 'uri'
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def makelink(url)
puts '<a href="' + url + '">' + url + '</a>'
end
def isURL(word)
if word =~ URI::regexp
makelink(word)
else
puts word
end
end
def hasURL(note)
words = note.split
words.each do |word|
isURL(word)
end
end
hasURL(NOTE)
This results in
$ ruby make_url.rb
The
url
<a href="https://www.sitepoint.com/ruby/">http:// www.sitepoint.com/ruby/</a>
should
be
a
link
We are getting close.
Refactor
What if we used the map to loop through each word? In the make_url.rb file comment out hasURL(note)
and add
# hasURL(NOTE)
puts NOTE.split.map { |x| x }
Save the file and run it.
$ ruby make_url.rb
The
url
https://www.sitepoint.com/ruby/
should
be
a
link
This is a step back in terms of output, Now we can remove some code. Remove the hasURL
method.
Instead of sending the check to a method, we can check right inline. Since we are doing that we can also remove the isURL
method and clean up the makeURL
method.
require 'uri'
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def makelink(url)
'<a href="' + url + '">' + url + '</a>'
end
puts NOTE.split.map { |x| x =~ URI::regexp ? makelink(x) : x }
Let’s run that code.
$ ruby make_url.rb
The
url
<a href="https://www.sitepoint.com/ruby/">https://www.sitepoint.com/ruby/</a>
should
be
a
link
Now you’re splitting, iterating though each word, and checking that word to see if it’s a URL. If so, make a link. We have the same output as before and we’ve removed half of the code.
Getting the Band Back Together
That’s cool and all, but the note is still an array. Let’s join it back together.
puts NOTE.split.map { |x| x =~ URI::regexp ? makelink(x) : x }.join(" ")
Run the code and enjoy the simplicity.
$ ruby make_url.rb
The url <a href="https://www.sitepoint.com/ruby/">https://www.sitepoint.com/ruby/</a> should be a link
Awesome.
The code we had.
require 'uri'
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def makelink(url)
puts '<a href="' + url + '">' + url + '</a>'
end
def isURL(word)
if word =~ URI::regexp
makelink(word)
else
puts word
end
end
def hasURL(note)
words = note.split
words.each do |word|
isURL(word)
end
end
hasURL(NOTE)
The code we have.
make_url.rb
require ‘uri’
NOTE = 'The url https://www.sitepoint.com/ruby/ should be a link'
def makelink(url)
'<a href="' + url + '">' + url + '</a>'
end
puts NOTE.split.map { |x| x =~ URI::regexp ? makelink(x) : x }.join(" ")
Much cleaner.
When I first started with Ruby, I would see the code we just wrote and I scratch my head. Now we are starting to write code like that and we understand what’s going on in those terse statements.
Ruby is chock-full of utilities and methods that allow us to be very succinct in achieving our goal. Here, we scan strings for URL-like strings and create HTML links out of each one. This is done with just a few lines of Ruby.
You can use this utility to store the note with an array of links or simply display the note in a HTML friendly way.
John is a Dallas-based front-end/back-end web developer with 15+ years experience. His professional growth has come from big corporate day jobs and weekend freelance. His is enjoys working the Ruby the most these days and has even added pain to the process by developing Rails for Windows! He’s had many years of enjoyment with Cold Fusion and has strong background in web standards.