Ruby
Great information here:
Use Ruby in two ways:
ruby
), or
Make a file called hello.rb
that looks like this:
puts "Hello, world"
To run this script:
$ ruby hello.rb Hello, world
The method puts
(“put string”) automatically puts a newline at the end. Another simple script:
# A script to print some Pythagorean triples. 1.upto(100) do |c| 1.upto(c) do |b| 1.upto(b) do |a| puts "(#{a},#{b},#{c})" if a * a + b * b == c * c end end end
And another (this time using print
, which does not add the newline):
# A script to write the Fibonacci numbers up to and including the # first commandline argument. n = ARGV[0].to_i; a, b = 0, 1 while b <= n print "#{b} " a, b = b, a+b end
(Ruby treats the string "blah"
as the value 0; Python would have given a type error).
The prompt is >>
. Results are indicated with =>
. Use _
to refer to the result of the last expression.
$ irb --simple-prompt
>> 5 / 2
=> 2
>> 5.0 / 2
=> 2.5
>> 5 + 6 * 4 / 3
=> 13
>> 5 + 6 * (4 / 3)
=> 11
>> 'dog'
=> "dog"
>> x = 4
>> 6 / 0
ZeroDivisionError (divided by 0)
>> 6.0 / 0
=> Infinity
>> 4 ** 3
=> 64
>> 10 ** 50
=> 100000000000000000000000000000000000000000000000000
>> 10.0 ** 50
=> 1.0e+050
>> 5645674 % 23
=> 2
>> 8.class
=> Integer
>> 7.0.class
=> Float
>> "hello".upcase
=> "HELLO"
>> "hello".capitalize
=> "Hello"
>> _.class
=> String
>> true.to_s
=> "true"
Things you might have noticed:
Everything is an object, even nil
. Numbers and booleans are symbols are objects. There are no weird “primitive values” like Java and JavaScript has. Even modules and classes are objects too. Every object has an object id:
>> 5.object_id => 11 >> 45.3421.object_id => 159137057222940850 >> nil.object_id => 8 >> 0.object_id => 1 >> "dog".object_id => 180 >> "dog".object_id => 200 >> :dog.object_id => 2035868 >> :dog.object_id => 2035868 >> Math.object_id => 220 >> true.object_id => 20 >> [true,75.2,{"x"=>5}].object_id => 240 >> [true,75.2,{"x"=>5}].object_id => 260 >> [0,1].object_id => 280 >> [0,1].object_id => 300 >> x = [0,1] >> x.object_id => 320 >> x.object_id => 320
Things to notice:
""
) or a new array or a new hash, you make a new object, even if the values inside the string, array, or hash, are equal.:dog
for example.What does it mean for something to be an object? It means it can receive messages that you send it. When you send an object a message, the object is called the receiver. The message it receives is the name of a method, which is code that the object executes. Then the object responds with the return value of the executed method, which, you guess it, is another object.
>> 5.abs => 5 >> 38.succ => 39 >> 300.even? => true >> 300.odd? => false >> 573.gcd(99) => 3 >> 573.gcd 99 => 3 >> "ubuntu".gsub("u", "oo") => "ooboontoo" >> "ubuntu".gsub "u", "oo" => "ooboontoo" >> 295.+(7) => 302 >> 798113.digits => [3, 1, 1, 8, 9, 7] >> 798113.send(:digits) => [3, 1, 1, 8, 9, 7] >> 21.send(:*, 5) => 105
Things to notice:
x + y
is actually syntactic sugar for x.+(y)
send
, which is itself a message 🤯What aboutputs
?
Earlier we ran across methods calledputs
and
It turns out they really are methods, but hang in there, we’ll see what is going on later.
Every object has exactly one class. An object is an instance of its class. (For example the object 3
is an instance of the class Integer
.) All classes except BasicObject
have a superclass. To find out the class, of an object, send it the message class
. Note that classes are objects too, and their class is Class
.
>> 3.class => Integer >> 243523523523523464635653343453245.class => Integer >> 2.0.class => Float >> ["dog", 4, 4.2, 3, 2, "rat"].class => Array >> :abc.class => Symbol >> {:CA => "Sacramento", :HI => "Honolulu"}.class => Hash >> nil.class => NilClass >> "hello there".class => String >> String.class => Class >> Class.class => Class >> Object.class => Class >> (1..10).class => Range >> /\d+/.class => Regexp >> false.class => FalseClass >> true.class => TrueClass >> Math.class => Module >> Module.class => Class >> String.superclass => Object >> Object.superclass => BasicObject >> BasicObject.superclass => nil
What are classes for? A class defines methods that its instances can execute. For example, instances of the class Integer
can execute abs
, odd?
, gcd
, etc. Since classes are themselves objects, they can execute methods too. The methods that instances can execute are called instance methods and the ones the class itself executes are called class methods.
Learn how to read the Ruby class documentation
Go to the Ruby-Doc.org home page and click on Core API. Scroll down a bit and you will see links to amazing documentation pages for each of the built-in classes.
These docs are absolutely full of examples! Pay particular attention to the distinction between instance methods and class methods.
Variables start with lowercase; constants with uppercase. Try reassigning a constant. Funny, all you get is a warning. What did you expect?
>> 18 < 8
=> false
>> 9 * 4.0 * Math.sin(Math::PI/2) / 2
=> 18.0
>> Math.acosh(-8.4)
Math::DomainError (Numerical argument is out of domain - "acosh")
>> Math.acosh(9)
=> 2.8872709503576206
>> 79342.to_s(16)
=> "135ee"
>> "135ee".hex
=> 79342
Strings are sequences of characters together with an encoding.
>> "Это — Руби?".encoding => #<Encoding:UTF-8> >> "Это — Руби?".size => 11 >> "Это — Руби?".bytesize => 20 >> "Это — Руби?".codepoints.map {|c| c.to_s(16)}.join(' ') => "42d 442 43e 20 2014 20 420 443 431 438 3f" >> "Это — Руби?".bytes.map {|c| c.to_s(16)}.join(' ') => "d0 ad d1 82 d0 be 20 e2 80 94 20 d0 a0 d1 83 d0 b1 d0 b8 3f"
>> "abcdef".length => 6 >> "abcdef".reverse => "fedcba" >> "dog".capitalize => "Dog" >> "dog".upcase => "DOG" >> "RatS".downcase => "rats" >> greeting = "Hello there" >> "rat"[2] => "t"
Strings in Ruby are mutable by default!
To get the effect of immutable strings common in most other languages, use symbols. Alternatively, you can invokes.freeze
to make s immutable. Or, you can put the comment# frozen_string_literal: true
at the top of a file.
>> greeting[1] = "u" >> greeting => "Hullo there" >> greeting.split => ["Hullo", "there"] >> greeting.chop => "Hullo ther" >> greeting => "Hullo there" >> greeting.chop! => "Hullo ther" >> greeting => "Hullo ther" >> " Lots of space ".squeeze => " Lots of space " >> " Lots of space ".strip => "Lots of space" >> "%4d + %4d = %f\n" % [6, 3, 9] => " 6 + 3 = 9.000000\n" >> "abc" << "def" << "g" => "abcdefg" >> "a000".hex => 40960 >> "small" <=> "Big" => 1 >> "dog" == "dog" => true >> "HO" * 3 => "HOHOHO" >> 355.to_s => "355" >> "345847583".to_i => 345847583
Double-quoted strings support interpolation, single-quoted strings do not.
>> x = 10 >> 'There are #{x} things here' => "There are \#{x} things here" >> "There are #{x} things here" => "There are 10 things here" >> %q{There are #{x} things here} => "There are \#{x} things here" >> %Q{There are #{x} things here} => "There are 10 things here" >> %q(Strings can go on multiple lines) => "Strings\ncan go on\nmultiple\n lines"
>> a = [8, 4, 3, 10, 6, "dog", :rat, [3.1]]
>> a.length
=> 8
>> a[3..5]
=> [10, 6, "dog"]
>> a[3...5]
=> [10, 6]
>> a.reverse
=> [[3.1], :rat, "dog", 6, 10, 3, 4, 8]
>> a.sort
ArgumentError (comparison of Integer with Array failed)
>> a.reverse!
=> [[3.1], :rat, "dog", 6, 10, 3, 4, 8]
>> a
=> [[3.1], :rat, "dog", 6, 10, 3, 4, 8]
>> a.each {|x| print x, "-"}; puts
[3.1]-rat-dog-6-10-3-4-8-
=> nil
>> a.join "/"
=> "3.1/rat/dog/6/10/3/4/8"
>> a.reject! {|x| !(Integer === x)}
=> [6, 10, 3, 4, 8]
>> a.sort.reverse
=> [10, 8, 6, 4, 3]
Hashes in Ruby are mutable collections of key-value pairs, with unique keys. [Docs]
>> m = {"a"=>3, "c"=>4, "b"=>6, "y"=>2, "x"=>4} >> m["y"] => 2 >> m.each {|k, v| puts "There are #{v} #{k}'s"} There are 3 a's There are 4 c's There are 6 b's There are 2 y's There are 4 x's => {"a"=>3, "c"=>4, "b"=>6, "y"=>2, "x"=>4} >> m.default => nil >> m["f"] => nil >> m["f"]=5 => 5 >> m["f"] => 5 >> m.empty? => false >> m.delete "x" => 4 >> m => {"a"=>3, "c"=>4, "b"=>6, "y"=>2, "f"=>5} >> m.delete_if {|k, v| v % 2 == 0} => {"a"=>3, "f"=>5} >> m.has_key? "c" => false >> m.length => 2 >> m.values => [3, 5]
Keys and values can be anything, but symbols are probably the most common kind of key.
>> caps = {:ca => 'sacramento', :hi => 'honolulu', :wa => 'seattle'} >> caps[:wa] = 'olympia' >> caps => {:ca=>"sacramento", :hi=>"honolulu", :wa=>"olympia"}
If the key is a symbol, then you can write the colon after the symbol name and omit the hashrocket.
>> {a: 90, b: 80, c: 70, d: 60} => {:a=>90, :b=>80, :c=>70, :d=>60}
The most common kind of method is the instance method; it goes inside classes. Let’s add a method to the Integer
class:
>> class Integer >> def tripled; self * 3; end >> end => :tripled >> 30.tripled => 90
You can write top-level methods in Ruby! These are written outside of a class; they just seem to be out there on their own:
>> def fact(n) >> (1..n).inject(1, :*) >> end => :fact >> fact 12 => 479001600 >> fact 50 => 30414093201713378043612608166064768844377641568960512000000000000
How did this work? When you define a method at the “top-level” like this, Ruby actually adds it to the class Object
as a private instance method. A private method in Ruby is called without explicitly giving the receiver; this implicit receiver is based on the context. For a Ruby script, or in the irb shell, Ruby gives you an implicit global object of class Object
. So what looks like a top-level function is actually a method of this global object.
As in many modern languages, method can have named parameters, rest parameters, defaults on parameters, and splats in arguments.
def positional(x, y, z) # cannot be called with names "#{x} #{y} #{z}" end def named(x:, y:, z:) # must be called with names "#{x} #{y} #{z}" end def rest(x, *y) # All args after first collected into array y "#{x} #{y}" end def defaulted(x, y=100) # y gets 100 if not passed in "#{x} #{y}" end def defaulted_and_named(x, y:2) "#{x} #{y}" end positional(1, 2, 3) # "1 2 3" named(z:3, x:1, y:2) # "1 2 3" rest(1) # "1 []" rest(1, 2, 3, 4) # "1 [2, 3, 4]" positional(1, *[2, 3]) # "1 2 3" defaulted(1) # "1 100" defaulted(1, 2) # "1 2" defaulted_and_named(1) # "1 2" defaulted_and_named(1,y:3) # "1 3"
Every method call can have a block following its arguments. The block is executed when the method body calls yield
. A method that calls yield
is called an iterator.
def hello yield "hello" yield "hi" yield "hola" end hello {|s| puts s} def collatz(n) while true yield n return if n == 1 n = n % 2 == 0 ? n / 2 : 3 * n + 1 end end result = [] collatz(577) {|n| result << n} puts(result.join " -> ")
Two syntaxes for blocks
You can usedo ... endor you can use{ ... }They are semantically the same.
Calling methods with blocks is one of the most characteristic bits of Ruby syntax.
We’ve seen it before in the methodupTo
.
Blocks can’t be assigned to variables, so Ruby has procs which can. There are two kinds of procs: those defined with Proc.new
(don't use these), and a better kind of proc, called a lambda. You should always use lambdas, pretty much.
There are two syntaxes for writing lambdas, and they are semantically exactly the same. There are also three syntaxes for calling lambdas, and they are exactly the same. There’s more than one way to do things in this language!
>> addSeven = lambda {|x| x + 7} >> addSeven = -> (x) {x + 7} >> addSeven.class => Proc >> addSeven.call(5) => 12 >> addSeven[5] => 12 >> addSeven.(5) => 12
>> def multiplier(n) >> -> x {x * n} >> end => :multiplier >> timesFour = multiplier(4) >> timesTen = multiplier(10) >> timesTen.call(8) => 80 >> timesTen[8] => 80 >> timesTen.call("abc") => "abcabcabcabcabcabcabcabcabcabc" >> def adder(n) >> -> x {x + n} >> end => :adder >> addSix = adder(6) >> def compose(f, g) >> -> x {f.call(g.call(x))} >> end => :compose >> compose(addSix, timesFour)[3] => 18 >> addSix.arity => 1
Kernel.lambda
and those created with Proc.new
. What is this difference?
It turns out you can pass a block directly to a method without first converting it to a proc. This gives you a non-lambda proc, interestingly enough:
>> def f(x, y, &p) >> p.call(x, y+1) >> end => :f >> f(2, 4) {|x, y| y * x} => 10
The module Enumerable
has tons of methods, many of which are iterators. The methods include
all?
, any?
, chunk
, collect
, collect_concat
,
count
, cycle
, detect
, drop
, drop_while
,
each_cons
, each_entry
, each_slice
, each_with_index
,
each_with_object
, entries
, find
, find_all
,
find_index
, first
, flat_map
, grep
, group_by
,
include?
, inject
, map
, max
, max_by
,
member?
, min
, min_by
, minmax
, minmax_by
,
none?
, one?
, partition
, reduce
, reject
,
reverse_each
, select
, slice_before
, sort
,
sort_by
, take
, take_while
, to_a
, zip
Many of the built-in classes mixin Enumerable
: Range
,
Array
, Hash
, IO
, Dir
, and Struct
.
>> (1..10).inject {|x,y| x + y} => 55 >> (1..10).inject(4) {|x,y| x + y} => 59 >> (1..4).entries => [1, 2, 3, 4] >> [10, 20, 30, 40, 50, 60].find {|x| x % 15 == 0} => 30 >> [10, 20, 30, 40, 50, 60].find_all {|x| x % 15 == 0} => [30, 60] >> {:a=>5, :b=>7, :c=>20}.entries => [[:c, 20], [:b, 7], [:a, 5]] >> [6, 4, 3, 9, -2, 11].max => 11 >> {:a=>5, :b=>7, :c=>20}.any? {|k,v| v > 5} => true >> {:a=>5, :b=>7, :c=>20}.any? {|k,v| v > 500} => false >> Dir.new(".").entries[0..3] => [".", "..", "animals.rb", "circle.rb"]
If you mixin Enumerable
into your own class, you must implement
each
yourself, and if you want to call max
, min
, or
sort
, then you also have to write <=>
, Then all the
other methods will work automatically!
>> class C >> include Enumerable >> def each >> yield 1 >> yield 2 >> yield 3 >> end >> end => :each >> c = C.new >> c.find_all {|x| true} => [1, 2, 3] >> c.include? 2 => true >> c.include? 20 => false >> c.zip ["a", "b", "c"] => [[1, "a"], [2, "b"], [3, "c"]] >> c.partition {|x| (x&1).zero?} => [[2], [1, 3]]
Fibers are Ruby’s mechanism for lighweight cooperative concurrency. You “call” the fiber with resume
and it runs until it yield
s. Then you resume it again and it picks up where it left off.
>> f = Fiber.new do
>> Fiber.yield 1
>> Fiber.yield 2
>> Fiber.yield 3
>> end
>> f.resume
=> 1
>> f.resume
=> 2
>> f.resume
=> 3
>> f.resume
=> nil
>> f.resume
FiberError (dead fiber called)
You can return a fiber from a method call and it will be able to access the local variables and parameters of the surrounding method.
You could put some code reusable code in one file:
# This file contains a function that returns a roman numeral for # a given integer. You can also interpret this file directly, # in which case you get a simple commandline program which prompts # for an integer input then repsonds with the number that the program # thinks was entered as a roman numeral. # Returns a string representing the roman numeral for the positive integer # passed in. Raises an exception if n isn't a positive integer in the # range 1..4999. def to_roman(n) raise ArgumentError, "Not in 1..4999" unless (1..4999) === n roman_map = [ [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], [100, 'C'], [90, 'XC'], [50, 'L'], [40, 'XL'], [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'] ] result = ""; for value, letters in roman_map while value <= n result << letters n -= value end end result; end if __FILE__ == $0 puts "Enter an integer:" begin n = gets.chomp.to_i puts "#{n} is #{to_roman(n)}" rescue ArgumentError, NoMethodError => e puts e.message end end
and use it in another:
# An example script that shows how to use code from another fle. require './roman.rb' puts to_roman(2983)
$ ruby useroman.rb MMCMLXXXIII
Instance fields have names beginning with @
. The initialize
method
is called during the call to new
on the class.
# A trivial circle class. class Circle def initialize(x = 0, y = 0, r = 1) @x = x @y = y @r = r end def area Math::PI * @r * @r end def perimeter Math::PI * 2.0 * @r end def expand!(factor) @r *= factor self end def move!(dx, dy) @x += dx @y += dy self end end
>> require './circle.rb' => true >> c = Circle.new >> c.expand! 4 => #<Circle:0x0000010112f168 @x=0, @y=0, @r=4> >> c.expand!(2).perimeter.to_s => "50.26548245743669" >> c = Circle.new 1, 1, 10 >> c.expand!(6).move!(2, -10) => #<Circle:0x0000010113dab0 @x=3, @y=-9, @r=60> >> class Circle >> def to_s >> "<Circle at (#{@x},#{@y}) with radius #{@r}>" >> end >> end => :to_s >> c => #<Circle:0x0000010113dab0 @x=3, @y=-9, @r=60> >> c.to_s => "<Circle at (3,-9) with radius 60>" >> "#{c}" => "<Circle at (3,-9) with radius 60>"
# A typical example of inheritance and poymorphism class Animal def initialize(name) @name = name end def speak() "#{@name} says #{sound()}" end end class Cow < Animal def sound() "moo" end end class Horse < Animal def sound() "neigh" end end class Sheep < Animal def sound() "baaaaa" end end if __FILE__ == $0 s = Horse.new "CJ" puts(s.speak()) c = Cow.new("Bessie") puts(c.speak()) puts(Sheep.new("Little Lamb").speak()) end
$ ruby animals.rb CJ says neigh Bessie says moo Little Lamb says baaaaa
Define your class bit by bit:
>> class C
>> def method1
>> 0
>> end
>> end
=> :method1
>> c = C.new
>> c.method1
=> 0
>> c.method2
NoMethodError (undefined method `method2' for #<C:0x00007f9464143ae8>)
>> class C
>> def method2
>> 1
>> end
>> end
=> nil
>> c.method2
=> 1
You can even add fields and methods to built-in classes:
>> 2.squared
NoMethodError (undefined method `squared' for 2:Integer)
>> class Integer
>> def squared
>> self * self
>> end
>> end
=> nil
>> 2.squared
=> 4
Fields aren’t directly accessible. You can write getters and setters if you want to...
>> class C >> def value >> @value >> end >> def value=(v) >> @value = v >> end >> end => :value= >> c = C.new >> c.value = 20 >> c.value => 20
...but that’s not the Ruby way. Normally you would use the attr_reader
, attr_writer
, and attr_accessor
methods to automatically generate the variables and the reader and writer methods.
>> class Point
>> attr_accessor :x, :y
>> end
=> nil
>> p = Point.new
>> p.x = 5
>> p.x
=> 5
>> p
=> #<Point:0x00007f9512a86110 @x=5>
>> class Q
>> attr_writer :x
>> end
=> nil
>> q = Q.new
>> q.x = 4
=> 4
>> q.x
NoMethodError (undefined method `x' for #<Q:0x00007f9512a056c8 @x=4>)
Methods that are called on instances of a class are called instance methods; methods called on the class object are called class objects.
>> class Point >> attr_accessor :x, :y >> def initialize(x, y); @x = x; @y = y; end >> def midpoint(q); Point.new((@x + q.x) / 2, (@y + q.y) / 2); end >> def Point.random(xmin, xmax, ymin, ymax) >> Point.new(xmin + rand*(xmax - xmin), ymin+rand*(ymax-ymin)); >> end >> end => :random >> p = Point.new(18, 77.5) >> q = Point.random(-2, 2, -10, 10) >> q.midpoint(p) => #<Point:0x00007f9512a763a0 @x=9.001095195360934, @y=34.2459443872966> >> Point.singleton_methods => [:random] >> Point.instance_methods(false) => [:x, :x=, :y, :y=, :midpoint]
Okay so, since q
is an instance of class Point
, and midpoint
is defined within Point
, we can call q.midpoint
. But with class methods
it is not so simple, right? When we call Point.random
, it can’t possibly be the
case that random
was defined within the class of which Point
is an
instance, right?
So Ruby is doing something else. But what? Note first of all that in the documentation you will see the
term class methods, but to access them you use the method singleton_methods
. Singleton
what? What is really going on here? Before answering this let’s look at one other interesting thing about
methods.
When we called Point.random
above, this worked because random
is a method
that we attached only to Point
and to no other object. In fact, Ruby lets us do this
for any object, not just classes. That’s right: You can attach new methods directly to an object.
This is cool.
>> a = Array.new
>> b = Array.new
>> def b.hello
>> "hi there"
>> end
=> :hello
>> b.hello
=> "hi there"
>> a.hello
NoMethodError (undefined method `hello' for []:Array)
Wait, what? So we somehow attached a method to b
but not to any other array? Uh... don’t
methods belong to classes and not objects? Did we change the class of b
? Let’s see:
>> b.class => Array
Nope. What’s going on? Answer: Ruby has singleton classes.
In addition to each object being an instance of a class, each object has attached to it its very own singleton class: a class object that is owned solely by the object. So while the class String
, for example, can have bazillions of instances, an object’s singleton class belongs only to the object and to no other objects. The singleton class is where the “object-specific methods” go.
Let’s work with the singleton class a bit:
>> a = [] >> b = [] >> def b.hello; "Hi there"; end => :hello >> b.hello => "Hi there" >> bs = b.singleton_class >> b.class => Array >> bs.class => Class >> bs.superclass => Array >> bs.instance_methods(false) => [:hello] >> b.singleton_methods(false) => [:hello]
Call these methods to set the visibility of methods you are about to define:
private
— make visible only within the object
protected
— make visible from objects of the same
class and its descendents
public
— make visible everywhere
Oh yeah, and visibility is dynamic:
>> class C
>> def a; 0; end
>> private
>> def b; 1; end
>> protected
>> def c; 2; end
>> def d; 2; end
>> public
>> def e; 2; end
>> private :d
>> end
=> C
>> C.private_instance_methods(false)
=> [:b, :d]
>> C.protected_instance_methods(false)
=> [:c]
>> C.public_instance_methods(false)
=> [:e, :a]
>> c = C.new
>> c.b
NoMethodError (private method `b' called for #<C:0x00007f9512ad4ba8>)
>> class C
>> public :b
>> end
=> C
>> c.b
=> 1
A module is an object that contains methods. A class is a module that you can instantiate.
Use modules for namespacing (e.g. Math
) or mixins (e.g.
Enumerable
and Comparable
). Modules may be included into
other modules and classes:
>> module M >> def bracket >> "(" + self.to_s + ")" >> end >> end => :bracket >> class Dog >> include M >> def bark >> "woof" >> end >> end => :bark >> sparky = Dog.new >> sparky.bark => "woof" >> sparky.bracket => "(#<Dog:0x000001011a1f88>)"
Three ways to write a regex:
/\by(?:es)?|no?/i
%r{\by(?:es)?|no?}i
Regexp.new('\by(?:es)?|no?', Regexp::IGNORECASE)
Regexp methods: ===
, =~
.
String methods:
=~
, []
, []=
, gsub
, gsub!,match
,
scan
, slice
, slice!
, split
, sub
,
sub!
>> phone = /((\d{3})(?:\.|-))?(\d{3})(?:\.|-)(\d{4})/ >> phone =~ 'Call 555-1212 for info' => 5 >> [$`, $&, $', $1, $2, $3, $4, $5] => ["Call ", "555-1212", " for info", nil, nil, "555", "1212", nil] >> phone =~ '800.221.9989' => 0 >> [$`, $&, $', $1, $2, $3, $4, $5] => ["", "800.221.9989", "", "800.", "800", "221", "9989", nil] >> phone =~ '1800.221.9989' => 1 >> [$`, $&, $', $1, $2, $3, $4, $5] => ["1", "800.221.9989", "", "800.", "800", "221", "9989", nil] >> message = "Your phone number is 800.555.1212." => "Your phone number is 800.555.1212." >> message.sub(phone, "---") => "Your phone number is ---." >> message[/o./] = "X" => "X" >> message => "YXr phone number is 800.555.1212."
To raise exceptions, use Kernel.raise
:
raise
raise ArgumentError
raise ArgumentError, "too small"
raise ArgumentError, "uh-oh", stackTrace
Exceptions are caught in a rescue clause within a block. You can also use ensure and else clauses.
begin ... rescue ... end
begin ... rescue ... ensure ... end
begin ... rescue ... else ... ensure ... end
Some wild stuff can be found in:
Module | Selected Methods |
---|---|
Kernel | binding caller global_variables local_variables p |
Object | class instance_of? instance_variable_get instance_variable_set instance_variables is_a? kind_of? method methods object_id private_methods protected_methods public_methods respond_to? singleton_methods |
Module | constants nesting ancestors class_variables const_defined? const_get const_set constants include? included_modules instance_method instance_methods method_defined? name private_instance_methods protected_instance_methods public_instance_methods. |
Class | superclass |
ObjectSpace | _id2ref, each_object |
alias and BEGIN begin break case class def defined? do else elsif END end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield
From lowest to highest precedence
Operator | Description |
---|---|
[] []= |
Element get, element set |
** |
Exponentiation |
! ~ + - |
Not, complement, unary plus, unary minus |
* / % |
Multiplication, division, modulo |
+ - |
Binary plus, binary minus |
<< >> |
Left shift, right shift |
& |
And (bitwise for integers) |
| ^ |
Inclusive or, exclusive or (bitwise for integers) |
< <= >= > |
Less, Less or equal, Greater or equal, greater |
<=> == != === =~ !~ |
Comparison, equal, not equal, case-equal, match, no match |
&& |
Short circuit logical and |
|| |
Short circuit logical or |
.. ... |
Inclusive range, exclusive range |
?: |
Ternary conditional |
= **= *= /= %= += -= |
Assignment |
defined? |
Is the operand defined? |
not |
Logical not |
and or |
Short circuit logical and, short circuit logical or |
if unless while until |
If, unless, while, until |
begin/end |
block |
The following are just methods that you can override
[] []= ** ! ~ @+ @- * / % + - << >> & | ^ <= < >= > <=> == === =~
(Note @+ and @- are method names for the unary plus and minus)
Ruby has the following kinds of expressions (and probably more):
While a Ruby script really is a sequence of expressions, some forms are pretty complex: they’re not exactly primitive values, method calls, or operators. They’re not really statments either. Anyway here are a few of these:
The built-in classes and modules are available to every Ruby
program without the need to say require
. Some of them are:
Classes | Modules |
---|---|
BasicObject Object (Kernel) Symbol NilClass TrueClass FalseClass String (Comparable) Numeric (Comparable) Integer Float Regexp Range (Enumerable) Array (Enumerable) Hash (Enumerable) Exception Time (Comparable) Proc Thread ThreadGroup Continutation Binding IO (Enumerable) File Dir (Enumerable) File::Stat (Comparable) Process::Status MatchData Module Class Method UnboundMethod Struct (Enumerable) Struct::Tms |
Kernel Comparable Enumerable Math ObjectSpace Marshal GC FileTest Process Process::Sys Process::GID Process::UID Signal Errno |
The so-called standard library consists of libraries that need to be require
d in your program, but are "standard" in the sense they’re part of pretty much every Ruby installation.
abbrev
base64
benchmark
bigdecimal
cgi
cmath
complex
continuation
coverage
csv
curses
date
dbm
debug
delegate
digest
dl
drb
e2mmap
English
erb
etc
extmk
fcntl
fiber
fiddle
fileutils
find
forwardable
gdbm
generator
getoptlong
gserver
iconv
io/wait
ipaddr
json
logger
mathn
matrix
minitest/benchmark
minitest/mock
minitest/spec
minitest/unit
mkmf
monitor
mutex_m
net/ftp
net/http
net/imap
net/pop
net/smtp
net/telnet
nkf
observer
open-uri
open3
openssl
optparse
ostruct
parsedate
pathname
pp
prettyprint
profile
profiler
pstore
pty
racc
racc/parser
rational
rdoc
readline
resolv
resolv-replace
rexml
rinda
ripper
rss
rubygems
scanf
sdbm
securerandom
set
shell
shellwords
singleton
socket
stringio
strscan
syck
sync
syslog
tempfile
test/unit
thread
thwait
time
timeout
tk
tmpdir
tracer
tsort
un
uri
weakref
webrick
Win32API
win32ole
xmlrpc
yaml
zlib
$!
$@
$&
$`
$'
$+
$1 $2 $3 $4 $5 $6 $7 $8 $9
$~
$=
$/
$\
$,
$;
$.
$<
$>
$_
$0
$*
$$
$?
$:
$"
$DEBUG
$FILENAME
$LOAD_PATH
$stderr
$stdin
$stdout
$VERBOSE
$-0
$-a
$-d
$-F
$-i
$-I
$-l
$-p
$-v
$-w
The command line apps you will use most are
If you prefer to get your documentation on the web, you can look at Ruby-Doc.org.
Documentation is often bundled inside of IDEs, such as fxri, FreeRIDE, Arachno, RDT, etc.
The library Test::Unit
does some magic, so just make a test case class and run it:
require 'test/unit' require './roman.rb' class TestRoman < Test::Unit::TestCase def test_ok expectations = [ [1, 'I'], [2, 'II'], [3, 'III'], [4, 'IV'], [5, 'V'], [8, 'VIII'], [9, 'IX'], [49, 'XLIX'], [50, 'L'], [70, 'LXX'], [499, 'CDXCIX'], [900, 'CM'], [4876, 'MMMMDCCCLXXVI'] ]; expectations.each do |arabic, roman| assert_equal(to_roman(arabic), roman); end end def test_argument_validation [1, 2, 35, 4998, 4999].each do |n| assert_nothing_raised() {to_roman n} end [-234, -1, 0, 5000, 5001, 235234235235235].each do |n| assert_raise(ArgumentError) {to_roman n} end end end
$ ruby testroman.rb Loaded suite testroman Started .. Finished in 0.001735 seconds. -------------------------------------------------------------------------------------- 2 tests, 24 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed -------------------------------------------------------------------------------------- 1152.74 tests/s, 13832.85 assertions/s
There are many assert methods: assert assert_block assert_equal assert_in_delta assert_instance_of assert_kind_of assert_match assert_nil assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_operator assert_raise assert_raises assert_respond_to assert_same assert_send assert_throws build_message flunk use_pp=
Many things are not covered here, including
BEGIN
and END
blocks
__DATA__