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:
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
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
Access Instance Variable from Outside the Class
How to Write a Ruby Command Line App That Supports Tab Completion
Preferred Ruby Plugin for Eclipse
Install Any Version of Ruby with Rvm on Mavericks
Same Instance Variable for All Actions of a Controller
Difference Between 'Self.Method_Name' and 'Class << Self' in Ruby
How to Merge Two Hashes with No New Keys
Preserve Newline in Text Area with Ruby on Rails
One Liner in Ruby for Displaying a Prompt, Getting Input, and Assigning to a Variable
Creating Routes with an Optional Path Prefix
Rails 4 How to Ignore Pending Migrations
How to Spawn a Child Process in Ruby
How to Switch to an Older Version of Rails
How to Randomly Iterate Through a Large Range