Home The Prometric Ruby Silver Exam
Post
Cancel

The Prometric Ruby Silver Exam

Since starting work with my web development company in Tokyo, I have been encouraged to take the Prometric Ruby Silver Test. My first attempt was a fail on this test, so this time I am going to put my study notes here. Prometric seem to be providing tests globally, so check out their site here if you are interested in assessing your Ruby level.

Practice Test Question 1: Assigning variables separated with commas

1
2
3
4
5
6
7
a, b = 0
c, a = 1
a, d = 1, 2
b, c = 3

p [a, b, c, d]
# Answer: [1, 3, nil, 2]

So this will explain this one:

1
2
3
4
5
6
7
a, b = 0
p a
p b

a, b = 0, 1
p a
p b

Only the first variable is assigned if there is only one value after the =.


Practice Test Question 2: .find_all

1
2
3
# Which of the following methods does the same as .find_all ?
# select, detect, collect, map
# Answer: select
1
2
3
p (1..10).find_all { |i|  i % 3 == 0 } # [3, 6, 9]
p (1..10).select { |i|  i % 3 == 0 } # [3, 6, 9]
# outputs array items that meet crieria in block

find_all


Practice Test Question 3: .class

1
2
3
hoge = *"a"
puts hoge.class
# Answer: array

So, here * is converting the string into an array. Let’s test this a bit:

1
2
3
4
5
6
7
8
test_one  = *"a"
puts test_one.class # Array
puts "a" # String
test_two = %w(a a a)
puts test_two.class # Array
puts %w(a a a).class # Array
test_three = {a: "a", b: "b"}
puts test_three.class # Hash

Practice Test Question 4: .pop , .push , .shift , .unshift

1
2
3
4
5
6
7
s = ["one", "two", "three"]
s.pop
s.pop
s.unshift
s.push "four"
p s
# Answer: ["one", "four"]

These are standard array methods.

1
2
3
s = ["one", "two", "three"]
s.pop
p s # ["one", "two"]

pop removes the last element of an array.

1
2
3
s = ["one", "two", "three"]
s.push "four"
p s # ["one", "two", "three", "four"]

push adds an element to the end of an array.

1
2
3
s = ["one", "two", "three"]
s.shift
p s # [two", "three"]

shift removes an element from the start of an array.

1
2
3
s = ["one", "two", "three"]
s.unshift("zero")
p s # ["zero", "one", "two", "three"]

unshift adds an element to the start of an array.

unshift


Practice Test Question 5: .strip , .chop

1
2
3
4
str = "Liberty Fish   \r\n"
str.strip
p str
# Answer: "Liberty Fish   \r\n"
1
2
3
str = "Liberty Fish   \r\n"
str.strip!
p str # "Liberty Fish"

This question addresses the difference between .strip and .strip!. strip! basically removes leading amd trailing whitespace.

These characters also get removed by strip:

1
2
"\tgoodbye\r\n".strip   # "goodbye"
"\x00\t\n\v\f\r ".strip # ""
1
2
3
4
str = "Liberty Fish   \r\n"
str.chop
p str
# Answer: "Liberty Fish   \r\n"

Without the ! chop, and strip, won’t do anything. It’s interesting to compare .chop and .strip at this point:

1
2
p "Liberty Fish   \r\n".chop # "Liberty Fish   "
p "Liberty Fish   \r\n".strip # "Liberty Fish"

.strip will also remove white space.


Practice Test Question 6: .sort

1
2
3
4
arr = [5, 3, 8, 1, 4, 2, 6, 9, 0, 7]
arr.sort!{ |a, b | b <=> a }.reverse!
p arr
# Answer: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

This one illustrates the sort method. Let’s test the sort method.

.sort! will sort array items (ascending):

1
2
3
arr = [5, 3, 8, 1, 4, 2, 6, 9, 0, 7]
arr.sort!
p arr # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

So, the b <=> a will sort items descending from bigger to smaller:

1
2
3
arr = [5, 3, 8, 1, 4, 2, 6, 9, 0, 7]
arr.sort!{ |a, b | b <=> a }
p arr # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Practice Test Question 7: * n

1
2
p "Hello" * 5
# Answer: "HelloHelloHelloHelloHello"

Lets try some math operators on strings:

1
p "Hello" + 5 # no implicit conversion of Integer into String (TypeError)
1
p "Hello" + "5" # "Hello5"

Practice Test Question 8: .split

1
2
3
str = "1;2:3;4"
p str.split(";|:")
# Answer: ["1;2:3;4"]

So, split will divide a string into substrings in an array. Here are some more examples of .split in action.

1
p "1;2:3;4".split(":") # ["1;2", "3;4"]
1
2
3
`//` will split every character.
```ruby
p "hello".split(//) # ["h", "e", "l", "l", "o"]

The number in the split parentheses designates the number of substrings.

1
p "hello".split(//, 4) # ["h", "e", "l", "lo"]

.split will also take arguments between the forward slashes (regex I think):

1
2
3
4
5
6
7
str = "1;2:3;4"
p str.split(/;|:/)
# Output: ["1", "2", "3", "4"]

str = "1;2:3;4"
p str.split(/;&:|2/)
# Output: ["1;", ":3;4"]

This is another (nasty) .split practice test question:

1
2
p "Apple-Banana-Lemon".split /(-)/
# Answer: ["Apple", "-", "Banana", "-", "Lemon"]

So, the parentheses are not essential after .split. In this case the paretheses within the forward slashes are not only splitting the string by that substring, but also outputting the “splitter” element. Take a look at this:

1
2
3
4
p "Apple-Banana-Lemon".split /(-)/ # ["Apple", "-", "Banana", "-", "Lemon"]
p "Apple-Banana-Lemon".split(/(-)/) # ["Apple", "-", "Banana", "-", "Lemon"]
p "Apple-Banana-Lemon".split /-/ # ["Apple", "Banana", "Lemon"]
p "Apple-Banana-Lemon".split(/-/) # ["Apple", "Banana", "Lemon"]

Practice Test Question 9: .each_with_index

1
2
3
4
5
6
7
8
9
("a".."d").each_with_index do |v, i|
  puts "#{i} / #{v}"
end

# Answer:
# 0 / a
# 1 / b
# 2 / c
# 3 / d

Practice Test Question 10: .partition

1
2
3
a, = (1..5).partition(&:odd?)
p a
# Answer: [1, 3, 5]

Interesting. Searches for the thing matching in the parentheses and then returns the parts before it, the match, and the part after. So look like this:

1
"hello".partition("l") # ["he", "l", "lo"]

This is interesting too.

1
2
a = (1..5).partition(&:odd?)
p a # [[1, 3, 5], [2, 4]]

These will all basically do the same thing:

1
2
3
4
a, = (1..5).partition(&:odd?)
p a
p (1..5).find_all { |i|  i.odd? } # [1, 3, 5]
p (1..5).select { |i|  i.odd? } # [1, 3, 5]

Practice Test Question 11: .reverse_each

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(1..10).each
.reverse_each
.each do |i|
  puts i
end
# Answer:
# 10
# 9
# 8
# 7
# 6
# 5
# 4
# 3
# 2
# 1

.reverse_each will iterate over the items in a reverse order - interesting. Let’s play with that a bit.

1
2
3
4
(1..10)
.reverse_each do |i|
  puts i
end

OK, as I thought, this is mostly a trick question of sorts. This will return the same as the test question code. So, … .each.reverse_each.each will effectively return the same as .reverse_each. .each iterates forwards, .each.reverse_each iterates backwards the array items iterated forwards, and .each.reverse_each.each iterates forward the backwards iterated forward iterated array - that was a mouthful.


Practice Test Question 12: EOF

1
2
3
4
5
6
7
8
s = <<'EOF'
Hello,
Ruby
EOF
'EOF'

p s
# Answer: "Hello,\nRuby\n"

After have experimented with this one I have learnt the following: 1) the end of file is designated with EOF - without this the code will raise an error 2) New lines have to begin with an uppercase letter 3) spaces between lines, and the final EOF cause \n in the output

1
2
3
4
5
6
7
8
9
s = <<'EOF'
Hello

Rbhjbhj

EOF

p s
# "Hello\n\nRbhjbhj\n\n"

This is a variant of this question:

1
2
3
4
5
6
7
s = <<'EOF'
Hello,
Ruby
EOF
'EOF'

p s

This interesting beacsue of the final 'EOF' - a red hearing.


Practice Test Question 13: Dir

1
2
3
4
5
6
# which of these are class methods for Dir?
Dir.delete
Dir.dirname
Dir.chmod
Dir.rmdir
# answer .delete, .rmdir

The Dir class handles directories in ruby. .delete and .rmdir are, so far, the only Dir class methods I know from the tes question list…Now I have just learnt some more:

1
2
3
4
Dir.pwd # get the current file path of the directory
Dir.delete # will delete the directory
Dir.rmdir # the same
Dir.chdir(path) # changes the current directory

Practice Test Question 14: 'r', 'w'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
open('textfile.txt', XXXX) do |f|
  data = f.read.upcase
  f.rewind
  f.puts data
end

# What should we put in XXXX i order to convert this:
recode 1
recode 2
recode 3

# to this:

RECODE 1
RECODE 2
RECODE 3

# Answer: 'r+'

Basically 'w' is for write only, 'r' is for read only, and 'r+' and 'w+' are for read an write modes. Maybe this is a better description:

1
2
3
4
# r = Read-only mode
# r+ = Read-Write mode
# w = Write-mode only
# w+ = Read-write mode

What’s hthe difference between 'r+' and 'w+' ? Ohh..I see now 'w+' can read the created text after having created the containing file, while 'r+' can write to a file after having read its contents.


Practice Test Question 15: .strftime

1
2
3
4
5
6
7
8
require 'date'
p Date.today.to_s
# Which of these will output the same date format as the above
Date.today.strftime("%y/%m/%d")
Date.today.strftime('%y-%m-%d')
Date.today.strftime("%Y/%m/%d")
Date.today.strftime("%Y-%m-%d")
# Answer: Date.today.strftime("%Y-%m-%d")

.strftime is very useful for formatting dates. Lets take a look:

1
2
3
4
5
6
7
8
9
require 'date'
p Date.today.to_s # "2023-01-21"
p Date.today.strftime("%y/%m/%d") # "23/01/21"
p Date.today.strftime('%y-%m-%d') # "23-01-21"
p Date.today.strftime("%Y/%m/%d") # "2023/01/21"
p Date.today.strftime("%Y-%m-%d") # "2023-01-21"
p Date.today.strftime("%x") # "01/05/15"
p Date.today.strftime("%D") # "01/05/15"
p Date.today.strftime("%F") # The ISO 8601 date format (%Y-%m-%d)

So the %Y will provide the 4-digit year that we want here. (By the way you need require 'date' in order to test this). Many of these simply need to be memorized it seems. "%x" and %D give the same result for example - can’t currently see any logic in choosing the letter x here.

Here are the letter codes that output the same thing:

1
2
3
4
5
p Date.today.strftime("%x") # "01/05/15"
p Date.today.strftime("%D") # "01/05/15"

p Date.today.strftime("%Y-%m-%d") # "2023-01-21"
p Date.today.strftime("%F") # The ISO 8601 date format (%Y-%m-%d)

Practice Test Question 16: variable vs method name

1
2
3
4
5
6
7
8
9
10
11
12
hoge = 0
def hoge
  x = 0
  5.times do |i|
    x += 1
  end
  x
end
puts hoge

# What's the output of this code?
# Answer: 0

In this one even though the method is defined with the same name as the variable after the variable was defined, the variable takes precedence - interesting.

Here is a variation of this type of question using a global variable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

[*1..10].select do
  Count.up
end

p $val
# Answer: 10

First off lets look at .select used here:

1
2
3
4
5
6
7
8
9
10
[*1..10].select do
  p 0
end
# Outputs 0 ten times

[1..10].select do
  p 0
end
# Outputs 0 once

So .select here is being used in the same way as 10.times do. Essentially the global variable here is accessed from within and outside the class block.


Practice Test Question 17: unless, elsif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def hoge(n)
  unless n != 3
    "hello"
  elsif n == 5
    "world"
  end
end

str = ''
str.concat hoge(3)
str.concat hoge(5)

puts str

# Answer: error

elsif has to follow an if statement. This makes me think if, logically, there might or should be an unlessif


Practice Test Question 18: .collect

1
2
3
4
5
# Which of the follwing has the same effect as .collect
# select
# detect
# find
# map

Here’s a quick test:

1
2
3
a = [ "a", "b", "c", "d" ]
p a.collect { |x| x + "!" } # ["a!", "b!", "c!", "d!"]
p a.map { |x| x + "!" } # ["a!", "b!", "c!", "d!"]

Practice Test Question 19: substrings

1
2
3
str = "abcdefghijk"
p str[2,4]
# Answer: "cdef"

4 characters from character 2. Lets compare different ways to get substrings:

1
2
3
str = "abcdefghijk"
p str[2..4]
# "cde"

From character 2 to 4.

1
2
3
str = "abcdefghijk"
p str[2...4]
# "cd"

From character 2 up until, but not including, character 4.

1
2
3
str = "abcdefghijk"
p str[2..-2]
# "cdefghij"

From character 2 until character -2, but forward in direction.


Practice Test Question 20: ternary operators

1
2
3
4
X = 10
Y = X < 10 ? "C" : "D"
puts Y
# Answer: D

No issues with defining a variable with a single upper case letter.

However, this does not work within a methid:

1
2
3
4
5
6
7
def hoge
  x = 10
  Y = x < 10 ? "C" : "D"
  puts Y
end
hoge
# answer: error

Practice Test Question 21: .upto

1
2
p 0.upto(5).select(&:odd?)
# Answer: [1, 3, 5]

Practice Test Question 22: .sub

1
2
3
4
5
6
7
8
chars = "I love apple, banana and grape"

5.times do
  chars = chars.sub("a", "@")
end

p chars
# Answer: "I love @pple, b@n@n@ @nd grape"

OK, lets play around with .sub and .gsub:

1
p "hello".gsub(/[aeiou]/, '*')  # "h*ll*"

The regex (I think) here will replace all vowels with ‘*’ when using .gsub. .sub will only look for the first match and then replace that. Here is a comparison:

1
2
p "hello".gsub('l', '*') # "he**o"
p "hello".sub('l', '*') # "he*lo"

Practice Test Question 23: .product , .transpose

1
2
3
arr = [1,2].product([3,4]).transpose
p arr
# Answer: [[1, 1, 2, 2], [3, 4, 3, 4]]

This needs to be broken down in order to understand it.

1
p arr = [1,2].product # [[1], [2]]

product

1
p arr = [1,2].product([3, 4]) # [[1, 3], [1, 4], [2, 3], [2, 4]]

.product returns the combinations of all the items within two arrays - from left to right.

transpose

1
p [[1, 3], [1, 4], [2, 3], [2, 4]].transpose # [[1, 1, 2, 2], [3, 4, 3, 4]]

.transpose is taking all items at the same index position within multiple arrays, and then putting them together in new sub-arrays.


Practice Test Question 24: .product , attr_accessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo
  attr_accessor :foo

  def initialize
    @foo = 0
  end
end

foo1 = Foo.new
foo1.foo += 1
foo2 = Foo.new
foo2.foo += 2

puts "#{foo1.foo}/#{foo2.foo}"

# Answer: 1/2

Ruby classes can have attr_accessor, attr_reader, attr_writer


Practice Test Question 25: .invert

1
2
3
h = {a: 100, b: 200}
p h.invert
# Answer: {100=>:a, 200=>:b}

.invert seems useful, but I can’t yet imagine a use case for this.


Practice Test Question 26: module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Question: correct way to define module?
# 1:
module(MyModule) {

}

# 2:
module MyModule

end

# 3:
module(MyModule) do

end

# 4:
class MyModule

end

# Answer: 4

So what are modeules then? Well they are like ruby classes except they cannot be instantiated.


Practice Test Question 27: raise

1
2
3
raise ['Error Message']
# Question: what kind of error does this raise?
# Answer: TypeError

I have to say, I don’t know the reasons behind this yet…


Practice Test Question 28: .slice

1
2
3
a = [1,2,3,4]
p a.slice(2,1)
# Answer: [3]

.slice will give a sub-array slice of an array. The numbering in the parentheses works the same as for getting substrings.

1
2
p [1,2,3,4].slice(0,3) # 3 items from the item at index position 0: [1, 2, 3]
p [1,2,3,4].slice(1..3) # all items between and including z index position 1 , and up until and including index position 3: [2,3, 4]

Practice Test Question 29: .delete

1
2
3
4
h = {a: 100, b: 200}
h.delete(:a)
p h
# Answer: {:b=>200}

.delete works on both arrays and hashes. Used with an array, the item in the parentheses is searched for and then removed.

1
2
3
4
5
6
7
8
9
number_array = [1, 2, 3]
letter_array = ["a", "b", "c"]
p [1, 2, 3].delete(2) # 2
number_array.delete(2)
p number_array # [1, 3]
p ["a", "b", "c"].delete(2) # nil
p ["a", "b", "c"].delete("a") # "a"
letter_array.delete("a")
p letter_array # ["b", "c"]

Practice Test Question 30: .each_cons

1
2
3
4
5
6
7
8
9
arr = (1..30).to_a
container = []

arr.each_cons(7) do |i|
  container << i
end

p container.length
# Answer: 24

Practice Test Question 31: &, &&, |, ||

1
2
3
4
5
a1 = [1,2,3]
a2 = [4,2,3]

p a1 & a2
# Answer: [2, 3]

These operators seem really useful. I’ve found them a bit tricky to memorise, but they all make sense upon inspection:

1
2
3
4
5
6
7
a1 = [1,2,3]
a2 = [4,2,3]

p a1 & a2 # returns shared items: [2, 3]
p a1 && a2 # returns last item (after operator): [4, 2, 3]
p a1 | a2 # returns unique items from both arrays: [1, 2, 3, 4]
p a1 || a2 # returns first item (before operator): [1, 2, 3]

Just out of curiosity, what happens with three items:

1
2
3
4
5
a1 = [1,2,3]
a2 = [4,2,3]
a3 = [5, 3, 6]
p a1 && a2 && a3 # [5, 3, 6]
p a1 || a2 || a3 # [1, 2, 3]

And, this test question tricked me:

1
2
3
4
v1 = 1 - 1 == 0
v2 = v1 || raise RuntimeError
puts v2 && false
# error

In this one, even though the RuntimeError comes after the ||, it is raised regardless.


Practice Test Question 32: .scan

1
2
3
str = "aaabbcccddd"
p str.scan("c")
# Answer: ["c", "c", "c"]

I couldn’t find much documentation on .scan from apidock.com. However it seems to only work with finding substrings within strings and then outputting them in an array, so let test it a bit:

1
2
3
p [1, 2, 3, 3, 4, 5].scan(3) # outputs error
p "123345".scan(3) # outputs error
p "123345".scan("3") # Outputs ["3", "3"]

Practice Test Question 33: IO.read

1
2
3
p IO.read("text.txt", 3, offset = 1)
# Question: what's the output of this using the given text.txt file
# Answer: "Ex\n"
REx
Silver
REx
Gold

This one is very interesting. I’m now going to test out the offset parameter:

1
2
3
4
5
6
7
p IO.read("text.txt", 3, offset = 0)
# output: "REx"
p IO.read("text.txt", 6, offset = 0)
# output: "REx\nSi"
puts IO.read("text.txt", 6, offset = 0)
# REx
# Si

It’s also interesting to note here the difference between puts and p.


Practice Test Question 34: !

The ! related questions have appeared quite often in my practice test questions, so I’m going to test this now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# reverse - ! not required for permanent change
arr = ["apple", "banana", "orange"].reverse
arr.reverse
p arr # outputs: ["orange", "banana", "apple"]

# flatten - ! required for permanent change
arrr =  [["apple"],["banana"],["orange"]]
arrr.flatten
p arrr # outputs: [["apple"], ["banana"], ["orange"]]

# strip - ! required for permament change
str = "Liberty Fish   \r\n"
str.strip
p str # outputs "Liberty Fish   \r\n"

# sort - ! required for permanent change
arr = [5, 3, 8, 1, 4, 2, 6, 9, 0, 7]
arr.sort
p arr # [5, 3, 8, 1, 4, 2, 6, 9, 0, 7]
arr.sort!
p arr # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# compact - ! required for permanent change
arr = [1, nil, nil, nil, nil, 6]
arr.compact
p arr # [1, nil, nil, nil, nil, 6]
arr.compact!
p arr # [1, 6]

# upcase
arr = Array.new(3){"a"}
arr.first.upcase
p arr # ["a", "a", "a"]
arr.first.upcase!
p arr # p arr # ["A", "a", "a"]

Practice Test Question 35: 0..i

1
2
10.times{|d| print d == 3..d == 5 ? "T" : "F" }
# Answer: FFFTTTFFFF

At first I didn’t understand this one…I’m still finding it a bit unintuitive…

1
2
3
4
5
10.times{|d| print d == 0..d == 3 ? "T" : "F" }
# outputs T for all d values within 0..3 # TTTTFFFFFF

10.times{|d| print d == 0..d == 4 ? "T" : "F" }
# outputs T for all d values within 0..4 # TTTTTFFFFF

Ruby Notes 1: .equal? vs ==

1
2
3
4
5
6
a1 = "abc"
a2 = 'abc'

print a1.equal? a2
print a1 == a2
# Answer: falsetrue

Different degrees of equality are being tested here - interesting

1
2
3
4
5
6
7
8
9
x = 1
y = 1.0

print x == y
print x.eql? y
print x.equal? y
print x.equal?(1)

# Answer: truefalsefalsetrue

Practice Test Question 37: .any vs .select

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

[*1..10].any? do
  Count.up
end

p $val
# Answer: 3

Fortunately .slelect and .any bear a close relationship with the English meanings, so this all makes sense. Compare this to the similar practice question shown above using .select:

.select will look through all of the values in [*1..10], while .any? will only look until the matching element, in this case 3.

1
2
3
4
5
6
7
8
9
10
11
12
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

p [*1..10].select { Count.up } # outputs [3]

p $val # Outputs: 10
1
2
3
4
5
6
7
8
9
10
11
12
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

p [*1..10].any? { Count.up } # outputs true

p $val # Outouts: 3

Practice Test Question 38: has default values

1
2
3
4
5
6
h = Hash.new("default value")
h[:a]
h[:b] = 100

p h
# Answer: {:b=>100}

The has default value is assihgned correctly in this example, but in order to see it returned we need to ask for a value within the hash that has no value. So, like this:

1
p h[:a] # p h[:a]

Ruby Notes 2: %() vs %w()

1
2
3
4
5
6
x = %(a b)
y = %W(c d)
z = y << x

p z
# Answer: ["c", "d", "a b"]

I’m familiar with %w() because it is useful for quickly generating an array. The capitalized W, %W(), does exactly the same thing here. %(), on the ohter hand will join the items into a single string.


Practice Test Question 40: values_at()

1
2
3
4
5
hash = {price: 100, order_code: 200, order_date: "2018/09/20", tax: 0.8}

p hash.__(1)__
# Question: What goes here to get [100, 0.8]?
# Answer: values_at(:price, :tax)

Ruby Notes 3: the splat hash

1
2
3
4
5
6
7
def bar(*n1, n2)
  puts n1
  puts n2
end

bar 5, 6, 7, 8
# Answer 5 6 7 8

Method variables marked with a * will take all the method variables up until the last one / ones. In this case puts n1 will output 5, 6, 7, and puts n2 will out put 8. Let’s test this:

1
2
3
4
5
6
7
8
def bar(*n1, n2, n3)
  # puts n1
  puts n2
  puts n3
end

bar 5, 6, 7, 8
# Output: 7 8

Ruby Notes 4: .index

Getting the index of a character in a string is done like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = "sliaR no ybuR"
p a.index("R", 0) # 4
p a.index("R", 1) # 4
p a.index("R", 2) # 4
p a.index("R", 3) # 4
p a.index("R", 4) # 4

p a.index("R", 5) # 12
p a.index("R", 6) # 12
p a.index("R", 7) # 12
p a.index("R", 8) # 12
p a.index("R", 9) # 12
p a.index("R", 10) # 12
p a.index("R", 11) # 12
p a.index("R", 12) # 12

p a.index("R", 13) # nil

The index of the first character searched appearing after the integer value given is returned. ‘nil’ is returned if the integer value is greater than the total number of characters in the string.


Ruby Notes 5: .delete_if , .reject!

delete_if and reject! function as follows:

1
2
3
4
5
6
7
a = [0, 1, 2, 3, 4, 5]
a.delete_if{|x| x % 2 == 0}
p a # [1, 3, 5]

a = [0, 1, 2, 3, 4, 5]
a.reject!{|x| x % 2 == 0}
p a # [1, 3, 5]

I think I’ve seen somewhere that these two are not exactly identical in their behaviour.


Ruby Notes 6 Errors

Types of errors are tested in the Prometric Ruby silver exam. These are the ones I have come across so far:

Type Error

1
raise ['Error Message'] # TypeError

ZeroDivisionError

1
1 / 0 # ZeroDivisionError

NoMethodError

1
"7".binary # NoMethodError

LocalJumpError: no block given

1
p [1, 2, 3].inject do|x, y| x + y ** 2 end rescue p $! # #<LocalJumpError: no block given>

SyntaxError

1
2
3
4
5
unless integer = 1
p "integer doesn't equal 1"
elsif integer == 2
p "integer equals 2"
end

ArgumentError

1
2
3
arr = ["c", 2, "a", 3, 1, "b"]
arr.sort
p arr # ArgumentError

dynamic constant assignment

1
2
3
4
5
6
def hoge
  x = 10
  Y = x < 10 ? "C" : "D"
  puts Y
end
hoge # dynamic constant assignment

Ruby Notes 7: .combination

The difference between .combination and .permutation appeared in the third Ruby Silver test I took (and failed). Here is .combination:

1
2
3
4
5
6
a = [ "a", "b", "c" ]
p a.combination(1).to_a # => [["a"], ["b"], ["c"]]
p a.combination(2).to_a # => [["a", "b"], ["a", "c"], ["b", "c"]]
p a.combination(3).to_a # => [["a", "b", "c"]]
p a.combination(4).to_a # => []

1
2
3
4
5
a = [ "a", "b", "c" ]
p a.permutation(1).to_a # => [["a"], ["b"], ["c"]]
p a.permutation(2).to_a # => [["a", "b"], ["a", "c"], ["b", "a"], ["b", "c"], ["c", "a"], ["c", "b"]]
p a.permutation(3).to_a # => [["a", "b", "c"], ["a", "c", "b"], ["b", "a", "c"], ["b", "c", "a"], ["c", "a", "b"], ["c", "b", "a"]]
p a.permutation(4).to_a # => []

Ruby Notes 8: reserved words

The reserved words also appeared in one of the Prometric Ruby Silver test questions. These will have to be memorized.

__ENCODING____FILE____LINE__BEGINENDaliasandbegin 
breakcaseclassdefdefined?doelseelsifend
ensurefalseforifinmodulenextnilnot
orredorescueretryreturnselfsuperthentrue
undefunlessuntilwhenwhileyield   

Ruby Notes 9: regex

Regex in ruby is going to require some time to fully understand. Let’s go.

.match and ~= are the two most common ways of evaluating a regex pattern. The ~= operator and the .match method output different results.

1
2
p /y/ =~ 'haystack'   # 2 # outputs string index of first match
p /y/.match('haystack') # #<MatchData "y"> outputs the matching item

Unfound items return nil.

1
2
p /z/ =~ 'haystack'   # nil
p /z/.match('haystack') # nil

The ~= has its oposite !~:

1
2
p /y/ !~ 'haystack' # does not match /y/ false
p /z/ !~ 'haystack' # does not match /z/ true

Character Classes

Character ClassDescription
[.]Matches any character except a newline (unless in multiline mode)
[a-zA-Z0-9_]Matches word characters (compare with \w)
[^a-zA-Z0-9_]Matches non-word characters (compare with \W)
[0-9]Matches digits (compare with \d)
[^0-9]Matches non-digits (compare with \D)
[0-9a-fA-F]Matches hexdigits (compare with \h)
[^0-9a-fA-F]Matches non-hexdigits (compare with \H)
[ \t\r\n\f]Matches whitespace characters (compare with \s)
[^ \t\r\n\f]Matches non-whitespace characters (compare with \S)

Lower Case Letters [a-z]

1
2
3
4
5
# [a-z]
p /[a-z]/ =~ 'haystack'   # 0
p /[a-z]/.match('haystack') # <MatchData "h">
p /[a-z]/ =~ 'Haystack' # 1
p /[a-z]/.match('Haystack') # <MatchData "a">

Upper Case Letters [A-Z]

1
2
3
# [A-Z]
p /[A-Z]/ =~ 'Haystack' # 0
p /[A-Z]/.match('Haystack') # <MatchData "H">

Word Characters [a-zA-Z0-9_], \w

1
2
3
4
5
6
# [a-zA-Z0-9_] \w
p /[a-zA-Z0-9_]/ =~ 'Hay0stack' # 0
p /[a-zA-Z0-9_]/.match('Hay0stack') # <MatchData "H">

p /\w/ =~ 'Haystack' # 0
p /\w/.match('Haystack') # <MatchData "H">

Non Word Characters [^a-zA-Z0-9_], \W

1
2
3
4
5
6
# [^a-zA-Z0-9_] \W
p /[^a-zA-Z0-9_]/ =~ 'Hay0stack*' # 0
p /[^a-zA-Z0-9_]/.match('Hay0stack*') # <MatchData "H">

p /\W/ =~ 'Hay0stack*' # 0
p /\W/.match('Hay0stack*') # <MatchData "H">

Digits [0-9], \d

1
2
3
4
5
6
# [0-9] \d
p /[0-9]/ =~ 'Hay0stack' # 3
p /[0-9]/.match('Hay0stack') # <MatchData "0">

p /\d/ =~ 'Hay0stack' # 3
p /\d/.match('Hay0stack') # <MatchData "0">

Non Digits [^0-9], \D

1
2
3
4
5
6
7
# [^0-9] \D
p /[^0-9]/ =~ '000Hay0stack' # 3
p /[^0-9]/.match('000Hay0stack') # <MatchData "H">

p /\D/ =~ '000Hay0stack' # 3
p /\D/.match('000Hay0stack') # <MatchData "H">

White Space \s

1
2
3
4
5
# [ \t\r\n\f]
p /\s/ =~ 'the Hay0stack*' # 3
p /[ \t\r\n\f]/ =~ 'the Hay0stack*' # 3
p /\s/.match('the Hay0stack*') # <MatchData " ">
p /[ \t\r\n\f]/.match('the Hay0stack*') # <MatchData " ">

Non White Space \S

1
2
3
4
5
# [^ \t\r\n\f]
p /\S/ =~ '  the Hay0stack*' # 2
p /[^ \t\r\n\f]/ =~ '  the Hay0stack*' # 2
p /\S/.match('  the Hay0stack*') # <MatchData "t"> returns first non white space character
p /[^ \t\r\n\f]/.match('  the Hay0stack*') # <MatchData "t"> 

ranges [abcdwxyz], [a-dw-z]

1
2
3
4
5
# [abcdwxyz] is equivalent to [a-dw-z]. The
p /[abcdwxyz]/ =~ '000Hay0stack' # 4
p /[abcdwxyz]/.match('000Hay0stack') # <MatchData "a">


Modifiers

ModifierDescription
+1 or more
*0 or more
?0 or 1
{3,5}between 3 and 5

Anchor Metacharacters

Metacharacter(s)Description
^Matches beginning of line
$Matches end of line
\AMatches beginning of string
\bMatches word boundaries when outside brackets; backspace (0x08) when inside brackets
\BMatches non-word boundaries
\GMatches point where last match finished or start position
\zMatches end of string
\ZMatches end of string. If string ends with a newline, it matches just before newline.

String length match

1
2
3
4
5
6
7
8
9
10
11
12
13
# \w{n}
p /\w{4}/ =~ 'Hay0s' # 0
p /\w{4}/.match('Hay0s') #<MatchData "Hay0">

# ^\w{4}$
p /^\w{4}$/ =~ 'Hay0s' # nil
p /^\w{4}$/.match('Hay0s') # nil

# ^\w{4}$
p /^\w{4}$/ =~ 'Hay0' # 0
p /^\w{4}$/.match('Hay0') # <MatchData "Hay0">


Shorthands

ShorthandDescription
\aMatches bell character
[\b]Matches backspace character (must be used in a character class)
\cxMatches control character
\C-xMatches control character
\dMatches decimal digit character ([0-9])
\DMatches non-digit character ([^0-9])
\eMatches escape character
\fMatches formfeed character
\hMatches hexdigit character ([0-9a-fA-F])
\HMatches non-hexdigit character ([^0-9a-fA-F])
\M-xMatches metacharacter
\M-\CxMatches meta-control character
\nNewline
\nnnOctal character
\rReturn
\sMatches whitespace character ([ \t\r\n\f])
\SMatches non-whitespace character ([^ \t\r\n\f])
\tTab
\vVertical tab
\wMatches word character ([a-zA-Z0-9_])
\WMatches non-word character ([^a-zA-Z0-9_])
\xhhHexadecimal character
\x{hhhhhhhh}Hexadecimal character (wide)

Ruby Notes 10: File class methods

          
File.atime(path)File.basename(path[, suffix])File.blockdev?(path)File.chardev?( path)File.chmod(mode, path)File.chown(owner, group, path)File.ctime(path)File.delete(path)File.unlink(path)File.directory?(path)
File.dirname(path)File.executable?(path)File.executable_real?(path)File.exist?(path)File.expand_path(path[, dir])File.file?(path)File.ftype(path)File.grpowned?(path)File.join(item)File.link(old, new)
File.lstat(path)File.mtime(path)File.new( path[, mode = "r"])File.owned?(path)File.pipe?( path)File.readable?(path)File.readable_real?(path)File.readlink( path)File.rename(old, new)File.setgid?(path)
File.setuid?(path)File.size(path)File:.size?(path)File.socket?(path)File.split(path)File.stat(path)File.sticky?(path)File.symlink(old, new)File.symlink?(path)File.truncate( path, len)
File.unlink(path)File.umask([mask])File.utime( atime, mtime, path)File.writable?(path)File.writable_real?(path)File.zero?(path)    

Ruby Notes 11: Directcory class methods

     
Dir[pattern]Dir.chdir(path)Dir.chroot(path)Dir.pwd` Dir.entries(path)`
Dir.foreach(path) {|f| ...}Dir.getwd, Dir.pwdDir.mkdir(path[, mode=0777])Dir.new(path)Dir.open(path)
Dir.delete(path)Dir.rmdir( path)Dir.unlink(path)  
This post is licensed under CC BY 4.0 by the author.