Organization Solutions

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 http://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 http://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 http://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 http://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
http://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 http://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! => http://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 http://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="http://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
http://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 http://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="http://www.sitepoint.com/ruby/">http://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="http://www.sitepoint.com/ruby/">http://www.sitepoint.com/ruby/</a> should be a link

Awesome.

The code we had.

require 'uri'

NOTE = 'The url http://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 http://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.

Get your free chapter of Level Up Your Web Apps with Go

Get a free chapter of Level Up Your Web Apps with Go, plus updates and exclusive offers from SitePoint.


  • tonypmartin

    Would using gsub with a block achieve the same thing? eg:

    puts NOTE.gsub(URI::regexp) {|url| ‘‘ + url + ‘‘}

    I think this would also work if you wanted to do a replacement for some text that might include spaces.

Related books & courses
Rails Deep Dive

Available on SitePoint Premium. Check it out now!