What Do the Different Brackets in Ruby Mean

What do the different brackets in Ruby mean?

It depends on the context:

  1. When on their own, or assigning to a variable, [] creates arrays, and {} creates hashes. e.g.

    a = [1,2,3] # an array
    b = {1 => 2} # a hash
  2. [] can be overridden as a custom method, and is generally used to fetch things from hashes (the standard library sets up [] as a method on hashes which is the same as fetch)

    There is also a convention that it is used as a class method in the same way you might use a static Create method in C# or Java. e.g.

    a = {1 => 2} # create a hash for example
    puts a[1] # same as a.fetch(1), will print 2

    Hash[1,2,3,4] # this is a custom class method which creates a new hash

    See the Ruby Hash docs for that last example.

  3. This is probably the most tricky one -
    {} is also syntax for blocks, but only when passed to a method OUTSIDE the arguments parens.

    When you invoke methods without parens, Ruby looks at where you put the commas to figure out where the arguments end (where the parens would have been, had you typed them)

    1.upto(2) { puts 'hello' } # it's a block
    1.upto 2 { puts 'hello' } # syntax error, ruby can't figure out where the function args end
    1.upto 2, { puts 'hello' } # the comma means "argument", so ruby sees it as a hash - this won't work because puts 'hello' isn't a valid hash

What are all the different uses of the [square brackets] in Ruby?

Okay, just for my own notes I have gone and had a closer look at this and, building on Holger Just's answer, come up with the following: the use of square brackets in Ruby can be divided into 6 uses, 3 of them a part of Ruby's method definitions and 3 of them semantic constructs.

Method definition

Object creation via class methods Array::[], Hash::[]

Array.[](1,2,3) #=> [1,2,3]                        #Un-sugared notation
Array["a","b","c"] #=> ["a","b","c"] #Sugared equivalent
Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}

Nothing to do with literal constructors, although it does the same thing.

Element reference via instance methods Array#[], Bignum#[], Continuation#[], Fixnum#[], Hash#[], MatchData#[], Method#[], Proc#[], String#[], Struct#[], Symbol#[], Thread#[], and class methods Dir::[], ENV::[]

ary = [1,2,"abc", [15,16,[26,27]]]  
ary.[](2) #=> "abc" #Un-sugared notation
ary[2] #=> "abc" #Sugared equivalent
ary[0,2] #=> [1,2]
ary[3][2][1] #=> 26
[1,2,3][0] #=> 1
"Is a string"[7,3] #=> "rin"

Element assignment via instance methods Array#[]=, Hash#[]=, String#[]=, Struct#[]=, Thread#[]=, and class method ENV::[]=

ary = [1,2,3]  
ary.[]=(1,"abc") #=> [1,"abc",3] #un-sugared notation
ary[2] = "def" #=> [1,"abc","def"] #Sugared equivalent
hash = {"a"=>1, "b"=>2}
hash["a"] = 3 #=> {"a"=>3, "b"=>2}

Semantic constructs

Object creation via the array literal constructor

ary = []  

There are a bunch of literal constructors in Ruby that create an object of the relevant class via the use of (usually) a simple symbol pair, square brackets being the literal constructor for array objects: Array [], Hash {}, Proc ->(){}, Range .. and ..., Regexp //, String "" and '', Symbol : and :"".

Object creation via the % notation

%q[hello there you] #=> "hello there you"           # String % notation  
%w[hello there you] #=> ["hello", "there", "you"] # Array % notation

It is not, strictly speaking, square-bracket notation, but rather two-symbol-pair notation of which you can use square brackets if you wish. So %q@hello there you@ is equally valid.

Ruby's regular expressions

/[^A-Fa-f0-9]/  

Square brackets indicate character classes in Ruby regular expressions.

I did find another use of the [], as a pattern for use in the Dir::glob method, but its supposed to act exactly as it does in regular expressions. Still, it indicates that there are possibly more uses hidden away in Ruby's 1500+ methods.

How does defining [square bracket] method in Ruby work?

Methods in ruby, unlike many languages can contain some special characters. One of which is the array lookup syntax.

If you were to implement your own hash class where when retrieving an item in your hash, you wanted to reverse it, you could do the following:

class SillyHash < Hash

def [](key)
super.reverse
end

end

You can prove this by calling a hash with the following:

a = {:foo => "bar"}
=> {:foo=>"bar"}
a.[](:foo)
=> "bar"
a.send(:[], :foo)
=> "bar"

So the def [] defined the method that is used when you do my_array["key"] Other methods that may look strange to you are:

class SillyHash < Hash

def [](key)
super.reverse
end

def []=(key, value)
#do something
end

def some_value=(value)
#do something
end

def is_valid?(value)
#some boolean expression
end

end

Just to clarify, the definition of a [] method is unrelated to arrays or hashes. Take the following (contrived) example:

class B
def []
"foo"
end
end

B.new[]
=> "foo"

do..end vs curly braces for blocks in Ruby

The general convention is to use do..end for multi-line blocks and curly braces for single line blocks, but there is also a difference between the two that can be illustrated with this example:

puts [1,2,3].map{ |k| k+1 }
2
3
4
=> nil
puts [1,2,3].map do |k| k+1; end
#<Enumerator:0x0000010a06d140>
=> nil

This means that {} has a higher precedence than do..end, so keep that in mind when deciding what you want to use.

One more example to keep in mind while you develop your preferences.

The following code:

task :rake => pre_rake_task do
something
end

really means:

task(:rake => pre_rake_task){ something }

And this code:

task :rake => pre_rake_task {
something
}

really means:

task :rake => (pre_rake_task { something })

So to get the actual definition that you want, with curly braces, you must do:

task(:rake => pre_rake_task) {
something
}

Maybe using braces for parameters is something you want to do anyways, but if you don't it's probably best to use do..end in these cases to avoid this confusion.

How do I read square brackets in Ruby documentation

I don't see anywhere on that documentation site where the notation used for argument lists is explained. However, the square brackets are frequently used to mean "optional" in programming documentation. So this means that the fetch method can be called with just one argument, or two. If you pass two, obviously you would need a comma. So these two calls would be valid:

a.fetch(k)
a.fetch(k, 5)

What do the square brackets mean here?

Ruby returns the last statement from a method or a block. In this case, with the brackets, the block returns an array of two items, so calling that block in map, if PAYMENT_TYPES had three items, would result in something like [ [a1, b1], [a2, b2], [a3, b3] ].

ruby regex, everything BUT what is in parentheses and brackets

Try this /\(.+/ which will match everything from the opening ( onwards. If you strip that out, you're left with 'Some words' which should be what you need?

Two points

  1. I may be misunderstanding the question
  2. You need something more complicated if there's any possibility of an ( appearing earlier in the string.

By the way, I find this rather valuable when trying to come up with Regex patterns.

Edit This pattern should only match stuff in brackets even if there is a stray bracket earlier in the string.

string.gsub(/(\(|\[).+(\)|\])/, '')

Does using curly braces go against the Ruby way?

While some people go with "braces for one-liners, do-end for multi-liners", I personally find the following rule the most logical:

  • use do-end when your block has side-effects (typically, with each and related methods) and
  • use braces when your block is without side-effects (map, inject and alike)

This logic goes well with method chaining issue that Matt wrote about.

One benefit of this approach is that it is going to make you think about side-effects every time you write a block, and they are very important, although sometimes overlooked by coders with no functional programming background.

Another way to put it, without involving side-effects terminology would be:

  • use do-end for blocks that perform
  • use { and } for blocks that return

Here are couple of articles with more info:

http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc

http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace



Related Topics



Leave a reply



Submit