Tuesday, 27 May 2014

Ruby - %w vs %W – secrets revealed!


Well, well… no sooner had I published the blog post on “Ruby Variables (with an overview of %w or %W)”, than a colleague suggested I split it out into its own post and explain more! Explain more?! Not sure there’s that much more to explain on w and W, but in the spirit of adventure let’s see what we can do.

The problem when looking at an example or two of a Ruby array using %w or %W, is that it’s not obvious what the difference is: What does %w Vs %W mean? If you search the texts and a bit of Google you’ll find the same question asked in many different ways. It seems it is an area of general confusion. A common thing you’ll read on blog posts is “%W performs normal double quote substitutions. %w does not”… OMG!! It’s all so clear now! Oh no, wait… WHAT DOES THAT EVEN MEAN?!
Before we look at how we use it, let’s get some context on what this is first.

General Delimited Input


In Ruby we have a set of literal strings, arrays, regular expressions and shell commands. Literals create objects that you can use in your Ruby program. An example is a string literal where we might write “Hello World”. However, we also have a form of syntax to use with these called General Delimited Syntax, each example of these starts with the % symbol. So, when we see % and something, we know this is general delimited input being used. Our %w and %W that we use in an Array are part of a set of different types of delimited input, namely:

              Type                    Description

·       %q                       Single quoted string

·       %Q or %             Double quoted string

·       %w or %W         Array of tokens

·       %r                        Regular Expression

·       %x                        Shell Command

·       %i                         Array of Symbols

Don’t worry about what all of these types are for now, as we progress in the Blog and YouTube posts, we’ll cover them as required. We’re focusing on the %w and %W type of delimited input here. Feel free to experiment though!

Lower Case or Upper Case?


The use of w or W reflects the features that single and double quotes provide us. Yes, when you write things in Ruby using ‘ or “ it really does mean something different. You might not see the effects of course, just having ‘Hello World’ or “Hello World” in your program won’t call the different features.  Lower case w gives us the same effects as using ‘ and upper case W is like using “.

When using single quotes we can’t use Interpolation and Escape Characters are limited. As you’ll have guessed, when using double quotes, we can use Interpolation and there are more Escape Characters we can use.

For example, in IRB or in a .rb file, try using interpolation with single and then double quotes.

stringA="World!"
puts 'Hello #{stringA}'

The above will give an output of:   Hello #{stringA}
Whereas if you change the single quotes to double as below;

stringB="World!"
puts "hello #{stringB}"

We should now see an output of: Hello World!
  … because we can use interpolation with double quotes.

Back to the W
So, coming back around to the use of %w or %W, we should see the same effect using these in our array. That is, %w should not allow interpolation, but %W should. Let’s test it.
As before, run the following in your preferred way, using a lower case w:

stringA = "World!"
myArrayLC = %w(Hello #{stringA})
puts myArrayLC

The output will be similar to single quotes, that is we’ll get Hello and #{stringA} printed, most likely on separate lines as we’re printing from an array. Now change it to have an uppercase W.

stringB = "World!"
myArrayUC = %W(Hello #{stringB})
puts myArrayUC

This time we’ll see Hello and World! printed to screen.

Escape Characters
The other item of difference was that upper and lower case (single and double quotes) allow or restrict the use of escape characters. The most common you’ll likely use in an array or %q type string will be to escape the space between words. This one will work with both types of delimited input for arrays. Run the following to see it in action.

myEscapeArray = %w(Hello this\ world)
puts myEscapeArray

Now try it with an uppercase W, no change? There’s no difference because the backslash escape  is supported by both versions.

Another example of a commonly used escape characters is \n for newline, let’s see that one in action with single quotes:

puts 'testing the \n newline'

The output for this is:  testing the \n newline  all on the same line, single quotes doesn’t support \n.
Now change it to use double quotes.

puts "testing the \n newline" 

This will now output the following, as \n is supported:

testing the
   newline

If we try this with our %w and  %W array, let’s see if it works the same (which it should…). Remembering that listing of array elements might appear that a newline has been inserted, we need to watch for the \n being printed or used.

myEscapeArray = %w(Hello this\n world)
puts myEscapeArray

The output now is:

     Hello
     this\n
     world

Which we know is just a listing of array elements in the way we’d expect. However, as we can see the \n we know this escape character isn’t supported. Let’s change this to uppercase W.

myEscapeArray = %W(Hello this\n world)
puts myEscapeArray

The output almost looks the same, except this time there’s no \n showing.

     Hello
     this
     world

As expected, \n is supported with upper case W, just like it is for double quotes.



Delimiter Characters

The last item to cover for our %w or %W arrays is the delimiter character. As in the examples above, normally we’ll use the open and closing parenthesis, ( and ), but it doesn’t have to be these we use.

Whatever character follows the type is the delimiter and it can be any character. Therefore all the following are valid:

myStringA = %q-MyStringHere-
puts myStringA

myStringB = %q~MyStringHere~
puts myStringB

myStringC = %q:MyStringHere:
puts myStringC

Change the above to have an uppercase Q and see it works the same, though you’d have guessed that by now. Why you would want to use such odd characters, especially where they may be ones used by Ruby, is beyond me, but you may have a use for them. Given we’ve proved this in terms of strings, let’s prove it for an array.
myDelimiterArrayA = %w-Hello this\ world-
puts myDelimiterArrayA

myDelimiterArrayB = %w~Hello this\ world~
puts myDelimiterArrayB

myDelimiterArrayC = %w:Hello this\ world:
puts myDelimiterArrayC

Try the above with an uppercase W and different delimiter characters to prove out any other combinations you’re curious about.


In Summary
We’ve seen that %w and %W as used in our Arrays, mirrors the features we get with single and double quoted strings. This means we can have interpolation of code and certain escape characters available when using these and other delimited input types.
The delimiter used can also be varied from the common parenthesis, as we’ve seen any delimiter character can be used, as best suits your needs.

That’s the secrets of %w and %W revealed!
Mark.


------------------------------------------------------------------
Enjoyed this post?
Say thanks by sharing, clicking an advert or checking out the links above!
------------------------------------------------------------------




0 comments: