What do the different brackets in Ruby mean?
It depends on the context:
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[]
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 asfetch
)
There is also a convention that it is used as a class method in the same way you might use astatic 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 hashSee the Ruby Hash docs for that last example.
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
- I may be misunderstanding the question
- 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, witheach
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
How to Return Something Early from a Block
Find Classes Available in a Module
Rails 6.1, Ruby 3.0.0: Tests Error as They Cannot Load Rexml
Ruby - Determine If a Number Is a Prime
How to Install Nokogiri Ruby Gem with Mkmf.Log Saying Libiconv Not Found
How to Format a Number 1000 as "1 000"
What Ide to Use for Developing in Ruby on Rails on Windows
Rails: Opposite of Hash#To_Param
Rails: Plus Sign in Get-Request Replaced by Space
Cannot Execute "Rails Console" Due to an Error with Readline
How to Use Unicorn as "Rails S"
How to Get a Stack Trace Object in Ruby
Eager Loading: the Right Way to Do Things
How to Catch Errno::Econnreset Class in "Case When"
Sidekiq Not Deallocating Memory After Workers Have Finished