Introduction to Ruby
Data Types
A literal is any notation that lets you represent a fixed value in source code. For instance, all of the following are literals in Ruby: Data types like strings,integer literals, array literals,hash literals,symbol literal and nil.
'Hello, world!' # string literal
375 # integer literal
3.141528 # float literal
true # boolean literal
{ 'a' => 1, 'b' => 2 } # hash literal
[ 1, 2, 3 ] # array literal
:sym # symbol literal
nil # nil literal
nil
means nothing in ruby
Type Conversion
Type conversion means converting from one data type to another is called type conversion,here 13
which is a integer is being converted into a float using to_f
which converts the integer ot 13.0
,similarly for the string,converting 13 to string using to_s
.
irb(main):001:0> 13.to_f
=> 13.0
irb(main):002:0> 13.to_f
=> 13.0
irb(main):003:0> 13.to_s
=> "13"
irb(main):004:0>
String Interpolation
Often in input output statements,string interpolation is used for variable placeholders within the puts
statements.
irb(main):013:0> #String interpolation
=> nil
irb(main):014:0> name= "vinay"
=> "vinay"
irb(main):015:0> puts "hello, #{name}"
hello, vinay
=> nil
In the above example the variable name
is used in the puts
statement.
Strings
Strings are group of characters,there are lot of inbuilt function for string operations few of them are, .capitalize
capitalizes the first alphabet of the string,empty?
returns a boolean whether the string is empty or not,length
returns the length of the string,split
function splits the characters in the string based on the separator.
irb(main):016:0> "Vinay".capitalize
=> "Vinay"
irb(main):017:0> "vinay".capitalize
=> "Vinay"
irb(main):018:0> "hello".empty?
=> false
irb(main):019:0> "vinay".length
=> 5
irb(main):020:0> "hello world".split
=> ["hello", "world"]
irb(main):021:0> "hello world".split("")
=> ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
Basic Data Structures Arrays and Hashes.
Array Literals and Hash literals are important data structures,to handle large continous data.
Array is a collection of data of the same type,that are accessed by index,whereas Hash are stored in a key:value
pair,where the value
is accessed by mentioning the key.
irb(main):022:0> #Basic data strctures arrays and hashes
=> nil
irb(main):023:0> [1,4,5,67,8]
=> [1, 4, 5, 67, 8]
irb(main):024:0> #hashes
=> nil
irb(main):025:0> {:dog => "barks"}
=> {:dog=>"barks"}
irb(main):026:0>
Symbols
Symbol is a text that begins with a colon(:symbol) while strings are enclosed within the double quotes.Strings are mutable objects,while symbols are immutable objects,since strings are mutable and their value can be changed,it can cause bugs, there at that time where object’s value shouldn’t be changed,at that time symbols can be used.
irb(main):021:0> "a string".object_id
=> 237820 irb(main):022:0> "a string".object_id
=> 239900
irb(main):023:0> "a string".object_id
=> 241980
irb(main):024:0> :a_symbol.object_id
=> 2332828
irb(main):025:0> :a_symbol.object_id
=> 2332828
irb(main):026:0> :a_symbol.object_id
=> 2332828
For every new string created there is a different object_id created,making it different objects,where as in symbols,it points to the same object id.A
Variables
Variable names are reusable,you can assign a new value to a variable at any point.To name variables in ruby follow snake_case
and not CamelCase
age=20
Variables as references,variable is effectively a reference or a pointer to that address in memory.
desired_location= "Bengaluru"
referenced_location= desired_location
reference_location.upcase!
here since the referenced_location
is a pointer to desired_location
changing the referenced_location
will also reflect on the actual variable.
- gets and chomp
irb(main):034:0> name = gets
Bob
=> "Bob\n"
irb(main):035:0> name = gets.chomp
Bob
=> "Bob"
irb(main):036:0> "hello "+ name
=> "hello Bob"
irb(main):037:0>
Variable Scope variable’s scope determines where in a program the particular variable is accessible,
name="Vinay Keshava"
def print_full_name(first_name,last_name)
name = first_name+ ' ' + last_name
puts name
end
print_full_name 'Mahesh', 'Kumar'
print_full_name 'Suresh', 'Kumar'
puts name
Output of the above program.
$ ruby variable_examples.rb
Mahesh Kumar
Suresh Kumar
Vinay Keshava
- Variable blocks
total=0
[1,2,4].each { |number| total += number}
puts total
a=5
3.times do |n|
a=3
end
puts a
-
Types of Variable
- Constants
- Global Variablesruby
- Class Variables
- Instance Variables
- Local Variables
-
Constants
Capitalizing every letter in variable’s name.Constants are used for storing data that never needs to change.
MY_CONSTANT = 'I am available throughout your app.'
- Global Variables Accessible throughout the entire app,overriding all scope boundaries.
$var = 'I am also available throughout your app.'
- Class Variables
Class Variables are declared by starting the variable name with two @
signs,these variables are accessible by instances of the class and by the class itself.
@@instances = 0
- Instance Variables
Instances variables are declared by starting the variable with one
@
sign,these variables are available throughout the current instance of the parent class.
@var = "I'm available throughout the current instance of this class"
- Local Variable
Most common variables you will come across and obey all scope boundary rules.
var = 'Hello world'
Input & Output
gets
:returns the user input,difference bw puts
& print
is puts
appends a new line at the end of the string while print
does not.
irb(main):001:0> puts "hello world"
hello world
=> nil
irb(main):002:0> print "hello world"
hello world=> nil
irb(main):003:0> gets
hello world
=> "hello world\n"
irb(main):004:0> gets.chomp
hello world
=> "hello world"
irb(main):005:0> name =gets.chomp
hell world
=> "hell world"
irb(main):006:0> name
=> "hell world"
since gets appends an new line escape character at the end of the line,to avoid this we use chomp
.
Conditional Logic
Conditional statements,similar to in other programming languages,case statements
just like switch checks for condition against a set of values defined,where in the example below,is demonstrated using the grade variable with the help of case
and when
keywords.
if true==false
print "This is not printing"
elsif true== true
print "True is true hence false is false\n"
end
if 1<2 && 5<6
print "This is printing because 1 is smaller than 2\n"
end
#case statements
grade = 'F'
pass_fail = case grade
when 'A' then "Hell yeah distinction"
when 'B' then "Ahh first class yes yes"
else "You shall not pass in life"
end
puts pass_fail
percentage = 50.00
pass_fail_percentage = case percentage
when 70.00
puts "Above 70.00 you dumbshit"
total=percentage*100
when 80.00
puts "80.00 ahh yes yes"
total=percentage*100
else
puts "You shall not pass go graze donkeysss man"
end
# unless statements - unless statement works in the opposite way to if statement,it only processes the code if it evaluates to false,unless can be added with else too.
age = 19
unless age <18
puts "get a job"
else
puts " Careful now"
end
# Ternary Operator
response = age < 18? "You still have time to become 19": "You're a grown up kid"
puts response
unless
statement works in the opposite way of if statement,it processes the block of code only if it evaluates to false.
Loops
Loops are used to repeat a set of statements.Types of loops are loop
,for
,while
.
until
loop opposite to while
loop,which evaluates as long as the condition is false not like while loop which only evaluates when the expression evaluate to true.
i=0
#this type of ruby's loop is infinite until you stop it.
loop do
puts "i is #{i}"
i+=1
break if i==10
end
#while loop
i=0
puts "while loop"
while i<10 do
puts "i is #{i}"
i+=1
end
#using while loop with gets
while gets.chomp !="yes" do
puts "Are we there yet?"
end
#until loop
i=0
until i>=10 do
puts "i is #{i}"
i +=1
end
# forloops
for i in 0..5
puts "#{i} zombie coming"
end
#times loop
5.times do
puts "hello world"
end
#upto and downto loops
5.upto(10) { |num| print "#{num}" }
puts " "
10.downto(5) { |num| print "#{num}" }
#iterators
names = ["vinay","keshava","hello","world"]
names.each { |name| puts name }
Block is some lines of code that is ready to be executed,when working with blocks they are two styles,single line and multi line.
In single line block we use {}
curly braces,while in multi line style we use the do
and end
keywords.
##block
names = ["vinay","keshava","hello","world"]
names.each { |name| puts name }
names.each do |name|
puts "#{name}"
end
Arrays
Arrays are a collection of data of the same type,that are referenced by an index.Array.new
is another way to create an array apart from the traditional way of creating it.
Array elements are accessed by an index.
some of the important methods used in arrays are first
, which returns the value at the first index,and last
function returns the value at the last index.
num_array=[1,3,4,5,76]
str_array = ["vinay","hello","world","keshava"]
#Creating an array using .new
Array.new
Array.new(3) #creates a new array with size 3
a1 = Array.new(4,7) #creates a new array with size 3,with all the values in these indexes is "7"
puts a1
Array.new(4,true)
#first and last array methods - to access the first and last value of the array.
puts str_array.first
puts str_array.last
puts str_array.first(3)
# adding a element to the array.
num_array=[1,2]
print num_array
puts ""
num_array.push(3,4)
print num_array
puts ""
num_array << 5 # shovel operator which adds 5 to the array.
print num_array
# deleting an element from the array.
num_array.pop # delete 5
puts num_array
Shift/Unshift and Push/Pop
.unshift
and .push
is used to add an element to an array, while `.unshift’ adds element to beginning of the array,while ‘.push’ adds the element to the end.
.shift
and .pop
is used to remove an element from the array,and the removed element is returned,.shift
removes an element from the beginning while, .pop
removes the element from the end.
#shift unshift and push and pop
=> [1, 1, 3, 4, 5]
irb(main):005:0> num_array
=> [1, 1, 3, 4, 5]
irb(main):006:0> num_array.shift
=> 1
irb(main):007:0> num_array
=> [1, 3, 4, 5]
irb(main):008:0> num_array.push(10)
=> [1, 3, 4, 5, 10]
irb(main):010:0> num_array.unshift
=> [1, 3, 4, 5, 10]
irb(main):011:0> num_array.unshift(1)
=> [1, 1, 3, 4, 5, 10]
irb(main):012:0> num_array.shift
=> 1
irb(main):013:0> num_array
=> [1, 3, 4, 5, 10]
irb(main):014:0> num_array.shift
=> 1
irb(main):015:0> num_array
=> [3, 4, 5, 10]
irb(main):016:0> num_array.shift
=> 3
irb(main):017:0> num_array
=> [4, 5, 10]
irb(main):018:0>
Basic array methods
num_array.methods
in the irb will display all the array methods available.
Hashes
One of the drawback of Array’s is,it holds data of the same type and the way of accessing the elements in the array is time consuming due to indexing of elements from 0
.
Hash is like a key:value
pair,where to access the value,we use the key which can be of different data types,can be string
,array
,integer
etc.
Another style of creating an hash similar to array using .new
like Hash.new
.
To access the values in the hash we use the fetch
option along with key
.
Stings are not prefferred to use as keys in the hash due to their mutable nature,hence symbols
are used due to their immutable nature.
irb(main):004:0> hash_with_different_types = { "name"=> "vinay", "degrees"=>["MBA","MTECH","MS"],12=>"twelve" }
=> {"name"=>"vinay", "degrees"=>["MBA", "MTECH", "MS"], 12=>"twelve"}
irb(main):005:0> #creating a hash with Hash.new
=> nil
irb(main):006:0> new_hash=Hash.new
=> {}
irb(main):007:0> new_hash[10=>"ten"]
=> nil
irb(main):008:0> new_hash
=> {}
irb(main):009:0> new_hash={10=>"ten"}
=> {10=>"ten"}
irb(main):010:0> #accessing hash values
=> nil
irb(main):011:0> new_hash[10]
=> "ten"
irb(main):012:0> new_hash.fetch(10)
=> "ten"
irb(main):013:0> #adding and changing data
=> nil
irb(main):014:0> my_hash_example[8]="eighttttee"
=> "eighttttee"
irb(main):015:0> my_hash_example
=> {10=>"ten", 8=>"eighttttee", 7=>"seven"}
irb(main):016:0> my_hash_example[9]="ninie"
=> "ninie"
irb(main):017:0> my_hash_example
=> {10=>"ten", 8=>"eighttttee", 7=>"seven", 9=>"ninie"}
irb(main):018:0> #deleting a hash data element
=> nil
irb(main):019:0> my_hash_example.delete(10)
=> "ten"
irb(main):020:0> my_hash_example
=> {8=>"eighttttee", 7=>"seven", 9=>"ninie"}
irb(main):021:0> #methods in hashes
=> nil
irb(main):022:0> my_hash_example.keys
=> [8, 7, 9]
irb(main):024:0> my_hash_example.values
=> ["eighttttee", "seven", "ninie"]
irb(main):027:0> #merging two hashes
=> nil
irb(main):028:0> my_hash_example.merge(hash_with_different_types)
=> {8=>"eighttttee", 7=>"seven", 9=>"ninie", "name"=>"vinay", "degrees"=>["MBA", "MTECH", "MS"], 12=>"twelve"}
irb(main):029:0> new_merged_hash=my_hash_example.merge(hash_with_different_types)
=> {8=>"eighttttee", 7=>"seven", 9=>"ninie", "name"=>"vinay", "degrees"=>["MBA", "MTECH", "MS"], 12=>"twelve"}
irb(main):030:0> new_merged_hash
=> {8=>"eighttttee", 7=>"seven", 9=>"ninie", "name"=>"vinay", "degrees"=>["MBA", "MTECH", "MS"], 12=>"twelve"}
irb(main):031:0>
Symbols
The first style is rocket style of declaring hashes,while the second style is symbols syntax
irb(main):031:0> #symbols as hashes
=> nil
irb(main):032:1* american_cars = {
irb(main):033:1* :chevrolet => "Corvette",
irb(main):034:1* :fort => "Mustang",
irb(main):035:1* :ferrari => "1"
irb(main):036:0> }
=> {:chevrolet=>"Corvette", :fort=>"Mustang", :ferrari=>"1"}
irb(main):037:0> american_cars
=> {:chevrolet=>"Corvette", :fort=>"Mustang", :ferrari=>"1"}
irb(main):038:1* japnese_cars = {
irb(main):039:1* honda: "Accord",
irb(main):040:1* toyota: "Corolla",
irb(main):041:1* nissan: "Altime"
irb(main):042:0> }
=> {:honda=>"Accord", :toyota=>"Corolla", :nissan=>"Altime"}
Methods
Methods are useful, when you want to repeatedly want to execute a set of statements based on condition,then comes methods into picture.
def hello_world_method
puts "hello world"
end
hello_world_method
def add_two_numbers(a,b)
puts a+b
#puts a-b Error: Undefined method
end
add_two_numbers(10,20)
add_two_numbers("hello","world")
#method with return type and argument
def hello_world_with_argument(name)
return name+" Hello World"
end
puts hello_world_with_argument("vinay")
#default parameters
def method_with_default_parameters(name="Vinay")
"Hello" + name
end
puts method_with_default_parameters
puts method_with_default_parameters("Mahesh")
#predicate methods- which return a boolean
puts 5.even?
puts 6.even?
Advanced Arrays
puts "Remove all duplicates"
array1 = [1,1,1,1,2]
print array1.uniq
puts "\nRemoving All Nil Elements"
array1=[1,2,4,5,nil,"John"]
array2=array1.compact
#compact removes all the nil elements.
print array1.to_s
print array2.to_s
puts "Remove Odd numbers"
array=[10,34,44,32,21,9,3,8]
even_array= array.reject do |item|
item.odd?
end
puts even_array
puts "Joining Arrays"
#using concat
numbers1= [1,2,4,5]
numbers2= [5,6]
all_numbers = numbers1+ numbers2
print all_numbers
# Destructuring Array.- Instead of manually assigning values using indexes, we can use this option of destructuring arrays.
puts "\nDestructuring Array"
destructuring_array = [89,90,"Hello","world"]
mark1,mark2,string1,string2 = destructuring_array
puts mark1
puts mark2
puts string2
# Destructuring using greedy variables- adding a star before a variable name makes the variable greedy and that takes all the remaining values
mark1,*other_values= destructuring_array
puts "Destructuring array using greedy variable"
puts mark1
print other_values
puts "\nVariables are greedy,but ruby is damn smart"
mark1, *other_variables, string2= destructuring_array
puts mark1
print other_variables
print string2
puts "\n Creating an array using %w"
w_array = %w{one two three four}
print w_array
puts "\n Quicker way to create array of strings"
array_of_strings= %w[hello world blue green red yellow]
print array_of_strings
puts "\n Quicker way to create array of symbols using %i"
array_of_symbols = %i[symbol1 symbol2 symbol3]
print array_of_symbols
Comments
# single line comments
=begin
hello world this is a multi line comment in ruby
=end
Debugging with pry-byebug gem
> ruby advanced_arrays.rb
Remove all duplicates
[1, 2]
Removing All Nil Elements
[1, 2, 4, 5, nil, "John"][1, 2, 4, 5, "John"]Remove Odd numbers
10
34
44
32
8
Joining Arrays
[1, 2, 4, 5, 5, 6]
Destructuring Array
From: /home/vinay/Documents/learn/ruby/ruby-exercises/advanced_arrays/advanced_arrays.rb:34 :
29: # Destructuring Array.- Instead of manually assigning values using indexes, we can use this option of destructuring arrays.
30: puts "\nDestructuring Array"
31: destructuring_array = [89,90,"Hello","world"]
32: mark1,mark2,string1,string2 = destructuring_array
33: binding.pry
=> 34: puts mark1
35: puts mark2
36: puts string2
37:
38: # Destructuring using greedy variables- adding a star before a variable name makes the variable greedy and that takes all the remaining values
39: mark1,*other_values= destructuring_array
[1] pry(main)> mark1
=> 89
[2] pry(main)> mark2
=> 90
[3] pry(main)> string1
=> "Hello"
[4] pry(main)>
Enumerable Methods
puts "Select enumerable methods"
friends = ['Sharon','Vinay','Suresh','Mahesh']
print friends.select { |friend| friend!= 'Vinay'}
puts "\n\nEach enumerable methods"
friends.each { |friend| puts "hello"+ friend}
puts "each_with_index method- returns two block elements,the value and the index of the value"
friends.each_with_index { |fruit, index| print fruit if index.even? }
puts "\n the map method,instead of creating two separate arrays or creating a new array to put the same data,we can use the map"
friends.each { |friend| friend.upcase }
# the above just converts but doesn't saves to the original array,instead creating a new array will be like duplicating data
friends.map { |friend| friend.upcase}
print friends
puts "\nreduce method- takes an array or hash and reduces it to single object"
my_numbers = [10,20,40,90]
print my_numbers.reduce { |sum, number| sum+number }
puts "\n Bang methods end with an exclamation and often modify the object they are called on"
#just like friends in the above example if we want to modify the original object we use bang method,we use the above map method to modify the original array
friends.map! { |friend| friend.upcase }
print friends
puts "\n Return values of enumerables - it is not a good practice to use bang methods and modify original objects,instead return the enumerables and assign it to a new object"
invited_friends = friends.select { |friend| friend!='VINAY' }
print invited_friends
Predicate Enumerable Methods
#include? predicate enumerable method
numbers = [5,7,7,8]
print numbers.include?(8)
#any method returns true if any elements in array or hash matches the condition within the block;otherwise return false
print numbers.any? { |num| num>10 }
print numbers.any? { |num| num<10 }
#all? method returns true if all the elements in your array or hash matches the condition
puts "\nall? predicate enumerable method"
print numbers.all? {|num| num>1}
# none? method returns true only if the condition in the block matches with none of the elements in array/hash,otherwise it returns false.
print numbers.none? { |num| num>20}
#saying there are no numbers greater than 20