972

I'm looking at the documentation for FileUtils.

I'm confused by the following line:

FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'

What does the %w mean? Can you point me to the documentation?

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
Dane O'Connor
  • 75,180
  • 37
  • 119
  • 173
  • 1
    Does this answer your question? [What is the %w "thing" in ruby?](https://stackoverflow.com/questions/5475830/what-is-the-w-thing-in-ruby) – aerijman Feb 04 '21 at 18:42

8 Answers8

1417

%w(foo bar) is a shortcut for ["foo", "bar"]. Meaning it's a notation to write an array of strings separated by spaces instead of commas and without quotes around them. You can find a list of ways of writing literals in zenspider's quickref.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 221
    Also, the parenthesis can be almost any other character such as square brackets %w[...], curly braces %w{...} or even something like exclamation marks %w!...!. All of these have the same behavior (returning an array). – ryanb Aug 13 '09 at 21:40
  • 169
    The easiest way to mnemonically remember what this means is "Whitespace (w) separated array". – Julik Aug 14 '09 at 09:36
  • 9
    See "General Delimited Input" here http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html – Jared Beck May 27 '12 at 18:42
  • 1
    Is it possible to add an empty string to the array? Result should be e.q. ['abc', '', 'def']. – Meinhard Jan 05 '13 at 21:45
  • 137
    If string has spaces, just escape them with \. Ex.: `%w(ab\ c def) # => ["ab c", "def"]` – Dmytro Jan 25 '13 at 19:49
  • 1
    Perl: `qw/Interpolated word list without quotes/` – Chloe May 22 '13 at 21:13
  • 10
    Guess this page would have solved the question, too: http://www.ruby-doc.org/core-2.0/doc/syntax/literals_rdoc.html#label-Percent+Strings – TheConstructor Jul 21 '13 at 12:57
  • 5
    @Dmitriy, you should really think hard if you want to use the `%w(..)` syntax if your strings contain spaces, escaping them will make your code much less readable. I'd recommend using a regular array of strings within tick marks then (`['...', '.. ..']`). – Nicolas Mar 24 '14 at 18:58
  • 3
    By the way, since ruby 2.0 there is also the `%i(...)` operator for creating an array of symbols: `%i(a b cd) # => [:a, :b, :cd]` – Nicolas Mar 24 '14 at 18:59
  • 5
    Why does Ruby have this alternate way of writing string arrays when the normal syntax works just fine? Does anyone know what the design thoughts were? Seems redundant and just an opportunity for confusion when reading someone else's code. – levininja Oct 08 '14 at 20:59
  • 1
    @levininja: Readability and brevity. Otherwise you may as well ask "why make Ruby when you can do everything in assembly?" – Amadan Oct 27 '14 at 04:22
  • 2
    @levininja because `%w(....)` notation is significantly easier to type. Compare `x = ["the","quick", "brown", "fox"]` to `x = %w( the quick brown fox)` especially when you are cutting and pasting. – Ray Baxter Jul 08 '15 at 04:34
  • 1
    Why `w`? Please someone tell me what is the reasoning behind this choice in ruby. – Yuri Ghensev Jun 29 '17 at 20:23
  • 1
    @YuriGhensev "w" stands for "words". – sepp2k Jun 29 '17 at 20:33
  • @sepp2k It makes sense if it is equivalent to `"a b c".split` – Yuri Ghensev Jun 29 '17 at 20:40
  • Is there a way of using this for dynamic values, like variables? e.g. `%w( self.id, self.name )`. It assumes they are strings so I get `[ 'self.id', 'self.name' ]` – Joshua Pinter Jul 19 '17 at 03:25
  • 4
    Worst ruby syntax ever, how many items in `%w(there_are fewer_than_you would_think)`? Sacrificing readability for writability is the essence of technical debt. – jjg Apr 18 '18 at 11:14
  • @jjg The syntax is optional you can use the normal array syntax if `%w` doesn't increase readability. You are also not limited to a single space between words. If you wanted to make your example more readable you could use double spaces to separate underscored literals. `%w[there_are fewer_than_you would_think]` – 3limin4t0r Aug 12 '21 at 09:51
582

I think of %w() as a "word array" - the elements are delimited by spaces and it returns an array of strings.

Here are all % literals:

  • %w() array of strings
  • %r() regular expression.
  • %q() string
  • %x() a shell command (returning the output string)
  • %i() array of symbols (Ruby >= 2.0.0)
  • %s() symbol
  • %() (without letter) shortcut for %Q()

The delimiters ( and ) can be replaced with a lot of variations, like [ and ], |, !, etc.

When using a capital letter %W() you can use string interpolation #{variable}, similar to the " and ' string delimiters. This rule works for all the other % literals as well.

abc = 'a b c'
%w[1 2#{abc} d] #=> ["1", "2\#{abc}", "d"]
%W[1 2#{abc} d] #=> ["1", "2a b c", "d"]
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
Mike Woodhouse
  • 51,832
  • 12
  • 88
  • 127
61

There is also %s that allows you to create any symbols, for example:

%s|some words|          #Same as :'some words'
%s[other words]         #Same as :'other words'
%s_last example_        #Same as :'last example'

Since Ruby 2.0.0 you also have:

%i( a b c )   # => [ :a, :b, :c ]
%i[ a b c ]   # => [ :a, :b, :c ]
%i_ a b c _   # => [ :a, :b, :c ]
# etc...
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Eraden
  • 2,818
  • 1
  • 19
  • 17
34

%W and %w allow you to create an Array of strings without using quotes and commas.

Community
  • 1
  • 1
Evan Meagher
  • 4,517
  • 21
  • 18
28

Though it's an old post, the question keep coming up and the answers don't always seem clear to me, so, here's my thoughts:

%w and %W are examples of General Delimited Input types, that relate to Arrays. There are other types that include %q, %Q, %r, %x and %i.

The difference between the upper and lower case version is that it gives us access to the features of single and double quotes. With single quotes and (lowercase) %w, we have no code interpolation (#{someCode}) and a limited range of escape characters that work (\\, \n). With double quotes and (uppercase) %W we do have access to these features.

The delimiter used can be any character, not just the open parenthesis. Play with the examples above to see that in effect.

For a full write up with examples of %w and the full list, escape characters and delimiters, have a look at "Ruby - %w vs %W – secrets revealed!"

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Mark C
  • 615
  • 9
  • 15
24

Instead of %w() we should use %w[]

According to Ruby style guide:

Prefer %w to the literal array syntax when you need an array of words (non-empty strings without spaces and special characters in them). Apply this rule only to arrays with two or more elements.

# bad
STATES = ['draft', 'open', 'closed']

# good
STATES = %w[draft open closed]

Use the braces that are the most appropriate for the various kinds of percent literals.

[] for array literals(%w, %i, %W, %I) as it is aligned with the standard array literals.

# bad
%w(one two three)
%i(one two three)

# good
%w[one two three]
%i[one two three]

For more read here.

Rajkaran Mishra
  • 4,532
  • 2
  • 36
  • 61
13

Excerpted from the documentation for Percent Strings at http://ruby-doc.org/core/doc/syntax/literals_rdoc.html#label-Percent+Strings:

Besides %(...) which creates a String, the % may create other types of object. As with strings, an uppercase letter allows interpolation and escaped characters while a lowercase letter disables them.

These are the types of percent strings in ruby:
...
%w: Array of Strings

carpeliam
  • 6,691
  • 2
  • 38
  • 42
itsnikolay
  • 17,415
  • 4
  • 65
  • 64
2

I was given a bunch of columns from a CSV spreadsheet of full names of users and I needed to keep the formatting, with spaces. The easiest way I found to get them in while using ruby was to do:

names = %(Porter Smith
Jimmy Jones
Ronald Jackson).split("\n")

This highlights that %() creates a string like "Porter Smith\nJimmyJones\nRonald Jackson" and to get the array you split the string on the "\n" ["Porter Smith", "Jimmy Jones", "Ronald Jackson"]

So to answer the OP's original question too, they could have wrote %(cgi\ spaeinfilename.rb;complex.rb;date.rb).split(';') if there happened to be space when you want the space to exist in the final array output.

Tim Fletcher
  • 7,062
  • 1
  • 35
  • 33
pjammer
  • 9,489
  • 5
  • 46
  • 56