How Does Defining [Square Bracket] Method in Ruby Work

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"

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.

Unable to use [square bracket] method in Custom Ruby class?

You need to define a [] method as well (in addition to []=).

class CompositeTask < Task
def [](index)
@sub_tasks[index]
end
end

How to write a method in ruby that takes hash-style, square bracketed arguments, like mymethod[arg]?

You're quite close. object[sth] is just a syntax sugar for object.[](sth). So to do what you need you have to define some_stats method that returns the object which defines [] method:

class Stats
def [](key)
if key.to_s =~ /something/
#do something
return something
else
#do something else
return something_else
end
end

def some_stats
Stats.new
end

some_stats[:something_new] #=> something
some_stats[:not_new] #=> something_else

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

Square brackets in ActiveRecord::Migration class name?

Ruby objects can have [] methods. They are used in the Array class, but any class can implement them.

def []()
...
end

Since classes are full objects, they too can have square bracket methods.

Ruby: differences between () and [] in method parameters

when you call a method in ruby you use (). Sometimes you are allowed to use [] on a particular object and it works, but only because type of this object has [] method defined in its definition. for instance

class Foo
def [](key)
key
end
end

# and later you can call:

foo = Foo.new
foo['anything']

Ruby square bracket setter/getter

Yes, it can be done. You need to define a []= and [] methods.

In this example, I am using a Hash as the internal data structure - you are free to use whatever you like.

class Word
attr_reader :meaning

def initialize
@meaning = Meaning.new
end
end

class Meaning
attr_reader :h

def initialize
@h = {}
end

def []=(key, value)
@h[key] = value
end

def [](key)
@h[key]
end
end

Example:

word = Word.new
word.meaning[:english] = 'Hello'
word.meaning[:english] # => 'Hello'

Call module or module function using square brackets

This is the closest possible syntax that I found in Elixir.
It's possible to define a module method using curly braces and then using it like this: :atom.{}

defmodule Pair do
defstruct [:id]

def {pair_name}, do: %Pair{id: from_name(pair_name)}
def from_name(_), do: 1
end

Usage:

Pair.{"some_name"} => %Pair{id: 1}



Related Topics



Leave a reply



Submit