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:
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__ | BEGIN | END | alias | and | begin | |
break | case | class | def | defined? | do | else | elsif | 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 | | | |
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 Class | Description |
---|
[.] | 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
Modifier | Description |
---|
+ | 1 or more |
* | 0 or more |
? | 0 or 1 |
{3,5} | between 3 and 5 |
Metacharacter(s) | Description |
---|
^ | Matches beginning of line |
$ | Matches end of line |
\A | Matches beginning of string |
\b | Matches word boundaries when outside brackets; backspace (0x08) when inside brackets |
\B | Matches non-word boundaries |
\G | Matches point where last match finished or start position |
\z | Matches end of string |
\Z | Matches 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
Shorthand | Description |
---|
\a | Matches bell character |
[\b] | Matches backspace character (must be used in a character class) |
\cx | Matches control character |
\C-x | Matches control character |
\d | Matches decimal digit character ([0-9]) |
\D | Matches non-digit character ([^0-9]) |
\e | Matches escape character |
\f | Matches formfeed character |
\h | Matches hexdigit character ([0-9a-fA-F]) |
\H | Matches non-hexdigit character ([^0-9a-fA-F]) |
\M-x | Matches metacharacter |
\M-\Cx | Matches meta-control character |
\n | Newline |
\nnn | Octal character |
\r | Return |
\s | Matches whitespace character ([ \t\r\n\f]) |
\S | Matches non-whitespace character ([^ \t\r\n\f]) |
\t | Tab |
\v | Vertical tab |
\w | Matches word character ([a-zA-Z0-9_]) |
\W | Matches non-word character ([^a-zA-Z0-9_]) |
\xhh | Hexadecimal 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.pwd | Dir.mkdir(path[, mode=0777]) | Dir.new(path) | Dir.open(path) |
Dir.delete(path) | Dir.rmdir( path) | Dir.unlink(path) | | |