Learning Ruby Coming from Javascript
Novice programmers often get intimidated by the idea of learning a new language. That is where the idea of this blog comes from. As a student in the Flatiron School, I spent my first half of the program learning Javascript and its framework React (the front-end side). When the time comes to switch gears, Ruby comes into play to code the back-end side of our programs. It was natural to compare and contrast Ruby and Javascript along the way to understand their similarities and differences. The purpose of this blog is to help anyone, new to Ruby, learn its basic concepts and fundamentals.
Introduction to Ruby
It is important to note that Ruby is primarily an Object Oriented Language (OOP) whereas Javascript is not strictly OOP; however, Javascript provides features such as classes and objects which are inspired by OOP. So, what is OOP? OOP is a type of programming based on the concept of "objects" which can contain data in the form of fields (often known as attributes or properties), and code in the form of procedures (often known as methods).OOP is about structuring code so that its functionality can be shared throughout the application program. On the other hand, Javascript is procedural programming language by nature where programs are built in sequential order and functions are called to share their behavior. Javascript can be an OOP language but it was not originally designed as an OOP language. The OOP syntactic sugar was added later on. Understanding this concept will explain the key differences between Ruby and Javascript syntax.
Language Purpose
Javascript
build client-side applications that run in the browser.
Work in the browser environment/sandbox where we can access:
- Make network requests
- Update the DOM
- Listen for events
- Debug our code in the browser's developer tools
Ruby
build server-side applications.
take advantage from our computer system:
- Read and write files
- Listen for network requests and send responses
- Connect to a database to access and update data we can build all kinds of apps not just web apps Command line interfaces Web servers Games Web scrapers
Terminal Output Methods
One of the main differences between Javascript and Ruby is that Ruby code run from the terminal using the Ruby interpreter whereas Javascript run code in the browser.
The command ruby -v
is used to check which Ruby version is used in the system.
To run Ruby application use the command ruby some_file.rb
, where some_file
is the name of the file where Ruby code is written.
Any code written in some_file.rb
can be outputted to the terminal using Ruby's various methods for printing output: puts
, print
, p
, and pp
.
puts
and print
are both used to print strings to the terminal with a difference of a line break added at the end of each string when puts
is used.
If we run this code:
puts "I am learning Ruby!"
puts "I am learning Ruby!"
puts "I am learning Ruby!"
We will receive this output in the terminal:
I am learning Ruby!
I am learning Ruby!
I am learning Ruby!
If we run the same code using print
:
print "I am learning Ruby!"
print "I am learning Ruby!"
print "I am learning Ruby!"
We will receive an output without a line break:
I am learning Ruby!I am learning Ruby!I am learning Ruby!%
To inspect a non string data, p
would be a better choice compare to puts
because the latter one attempts to convert everything to a string by calling the .to_s
method. On the other hand, p
calls the .inspect
method which will present data in a nicer format.
puts [1, 2, 3, 4]
1
2
3
4
=> nil
#`puts` will convert `nil` to an empty string
puts [1, 2, nil, nil, nil, 6]
1
2
6
=> nil
p
will return a raw version of an object (i.e including quotes and new line characters). puts
will always return nil
.
p "Hello World!"
"Hello World!"
=> "Hello World!"
p "Hello World!\n"
"Hello World!\n"
=> "Hello World!\n"
p
is more useful for debugging purposes whereas puts
is useful for display to the user.
pp
is used for printing nested and complicated arrays and hashes. pp
calls the .pretty_inspect
method to print the data in an organized and easy to read fashion.
[{:id=>1, :color=>"blue"},
{:id=>2, :color=>"red"},
{:id=>3, :color=>"yellow"}]
In Javascript, console.log
would have the equivalent function to puts
in Ruby.
Data Types in Ruby
Strings
Strings in Ruby can be defined with single or double quotes similarly to Javascript:
"I am a string!"
'I am also a string!!'
Since Ruby is an OOP language, we can call several methods on string literals (i.e. "hello"
). Each string in ruby is actually an instance of the class String
. Therefore, class methods are available to its instances. We can check look up these methods via "example".methods
.
"hello".upcase
# => "HELLO"
"hello".capitalize
# => "Hello"
"hello".reverse
# => "olleh"
String Interpolation
String interpolation exists in both Ruby and Javascript; however, backticks have a different purpose in Ruby:
# Ruby (comment in Ruby)
name = "Joe"
puts "Hello #{name}"
// JavaScript (Comment in Javascript)
const name = "Joe";
console.log(`Hello ${dogName}`);
Numbers
There are two types of numbers in Ruby: integers as whole numbers and floats as decimal numbers. Ruby provides several methods to work on both types of numbers.
> 2.3.floor
=> 2
> 8.5.ceil
=> 9
Also, we can convert strings to numbers:
> "2.5".to_i
=> 2
> "2".to_i
=> 2
> "2".to_f
=> 2.0
Unlike Javascript, Ruby will not convert an integer to a float during the process of arithmetic operations unless one of the sides is a float:
> 5/4
=> 1
> 5/4.to_f
=> 1.25
> 5/4.0
=> 1.25
Nil
In Ruby, there is only one case of absence of value which is represented by nil
. For example, puts
will always return nil
. On the other hand, Javascript has two different datatypes that represent the absence of a value null
and undefined
. The latter one is commonly seen when we create a variable and we do not assign a value to it. Ruby will not allow the creation of a variable without assigning a value to it. If we intent to create a variable and not assign it a value, we must explicitly assign nil
to declare an empty value.
puts "Return something"
# Return something
# => nil
> name
NameError (undefined local variable or method `name' for main:Object)
> name = nil
=> nil
>
let someValue;
console.log(someValue);
// => undefined
someValue = null;
console.log(someValue);
// => null
Booleans
Booleans have two values: true
and false
like in Javascript. In Ruby, however, true
is an instance of TrueClass
and false
is an instance of FalseClass
.
Additionally, only nil
and false
are falsy values. Everything else is truthy including 0
and empty string""
. On the other hand, in Javascript, null
, undefined
, 0
, false
, ""
, and NaN
are falsy values.
Symbols
The symbol data type (:symbol_example
) exists in both Ruby and Javascript yet the use of symbols is more common in Ruby where symbols are used as keys on a hash (a hash is equivalent to an object in Javascript). While a symbol is a representation of data similar to a string, Ruby allocates the same space in memory for symbols versus a string which is allocated a different space in memory each time it is called:
> :some_symbol.object_id
=> 2077788
> :some_symbol.object_id
=> 2077788
> "a string".object_id
=> 260
> "a string".object_id
=> 280
>
Arrays
Arrays have similar functionality in both Ruby and Javascript. They can be created using literal or class constructors:
> [3, 6, 9]
=> [3, 6, 9]
> Array.new
=> []
The Ruby documentation https://www.ruby-lang.org/en/documentation/ provides a comprehensive list of methods to perform CRUD actions (create, read, update, delete) in addition to operating on arrays as well as elements within an array. Some of these methods can work for both Ruby and Javascript arrays, some methods in Javascript have equivalents methods in Ruby, and some others are exclusive to Ruby.
Similarly to Javascript, we can check elements in an array by index in Ruby:
#Ruby
> my_array = [3, 6, 9, 12, 15]
=> [3, 6, 9, 12, 15]
> my_array[0]
=> 3
> my_array[-1]
=> 15
Ruby has a wide selection of enumerable methods that allows us to traverse, search, and sort through arrays. Some enumerables are used interchangeably in Ruby as well as in Javascript to loop over elements of an array. Some examples consist of but not limited to .map
, .filter
. .each
, and .find
. Ruby has a version of .map
called .collect
and .select
which is equivalent to .filter
.
Ruby has convenient methods to check first and last elements on a given array: Array.first
and Array.last
respectively compare to Javascript. For instance, to check the last element on an array with an unknown size we use: Array[Array.length-1]
. And, to check the the length of an array in Ruby we use Array.size
.
To extract a range of element from an array in Javascript, we can use the slice method. The slice method does not mutate the original array and it stops extracting elements before the last designated index. For instance: slice(1,3)
will extract the element with index 1 [1]
and exclude the element with index 3 [3]
:
//Javascript
someArray = [1, 2, 3, 4, 5, 6]
(6) [1, 2, 3, 4, 5, 6]
someArray.slice(1,3)
(2) [2, 3]
someArray
(6) [1, 2, 3, 4, 5, 6]
In Ruby, we can extract a range of elements from an array using [0..2]
which will return all the elements between index 0 and index 2 including the last one. But if we want to exclude last element we use the three dots method: [0...2]
:
:006 > my_array = [3, 6, 9, 12, 15]
=> [3, 6, 9, 12, 15]
> my_array[0..1]
=> [3, 6]
> my_array[0...2]
=> [3, 6]
> my_array[0..2]
=> [3, 6, 9]
> my_array[0...2]
=> [3, 6]
To add an element to the end of an array in Javascript we use push
method whereas the shovel <<
method is more commonly used in Ruby:
//Javascript
someArray
(6) [1, 2, 3, 4, 5, 6]
someArray.push(9)
7
someArray
(7) [1, 2, 3, 4, 5, 6, 9]
#Ruby
011 > my_array = [3, 6, 9, 12, 15]
=> [3, 6, 9, 12, 15]
2.7.4 :012 > my_array << 10
=> [3, 6, 9, 12, 15, 10]
2.7.4 :013 >
Both languages have the ability to concatenate arrays, meaning combining multiple arrays, using concat()
method. In Ruby, we can combine arrays using +
as well:
//Javascript
a = [1, 2, 3, 4]
(4) [1, 2, 3, 4]
b = [3, 6, 9]
(3) [3, 6, 9]
a + b
'1,2,3,43,6,9'
a.concat(b)
(7) [1, 2, 3, 4, 3, 6, 9]
#Ruby
> a= [1, 2, 3, 4 , nil]
=> [1, 2, 3, 4, nil]
> b= [6, 7, 8, 9]
=> [6, 7, 8, 9]
> a.concat(b)
=> [1, 2, 3, 4, nil, 6, 7, 8, 9]
>a= [1, 2, 3, 4 , nil]
=> [1, 2, 3, 4, nil]
> b= [6, 7, 8, 9]
=> [6, 7, 8, 9]
> a + b
=> [1, 2, 3, 4, nil, 6, 7, 8, 9]
To remove first and last elements from an array, both Ruby and Javascript use shift
and pop
respectively.
In Ruby, there are some methods that has either a question or an exclamation mark (i.e. include?
and reverse!
). if a method includes a question mark, this means that the return will be a boolean value (true
or false
). Any method with exclamation mark will change the original array. We can keep original array by omitting the exclamation point:
#Ruby
> a = [1, 2, 3, 4]
=> [1, 2, 3, 4]
> a.reverse
=> [4, 3, 2, 1]
> a
=> [1, 2, 3, 4]
> a.reverse!
=> [4, 3, 2, 1]
> a
=> [4, 3, 2, 1]
It is also worth mentioning that some methods are simpler to use in Ruby compare to Javascript. For example, to add all elements in a given array we simply use .sum
whereas in Javascript we use the reduce method: Array.reduce((sum, num) => sum + num)
. Another example of a simple method in Ruby is the .uniq
method which returns one version of each element in an array: [1, 1, 2, 3].uniq => [1, 2, 3]
. To achieve the same results in Javascript, we use the filter method array.filter((num, index, array) => array.indexOf(num)===index)
In Ruby, we can create arrays of strings and symbols as such:
#Ruby
%w[word word]
=> ["word", "word"]
> %i[word word]
=> [:word, :word]
Hashes
Hashes in Ruby can be compared to a plain old Javascript object. However, the term object is used in Ruby to indicate an instance of a class. Hashes are composed of key/value pairs where each key points to a value: { key1: "value1", key2: "value2" }
.
Unlike Javascript, we cannot use use dot notation to access values within a hash, only bracket notation is valid with hashes:
some_hash = { key1: "value1", key2: "value2" }
some_hash[:key2]
# => "value2"
We can also create hashes with strings instead of keys: { "string1" => "value1", "string2" => "value2" }
.
A hash can be converted to an array:
> some_hash = { key1: "value1", key2: "value2" }
=> {:key1=>"value1", :key2=>"value2"}
> some_hash.to_a
=> [[:key1, "value1"], [:key2, "value2"]]
There are several methods that are available to the Hash class similarly to the Array class. The Ruby documentation https://www.ruby-lang.org/en/documentation/ provides a list of method for every class.
Methods
A method in Ruby is the equivalent of a function in Javascript:
//Javascript
function someFunction(parameter) {
console.log("Running someFunction");
return parameter + 1;
}
#Ruby
def some_method(parameter)
puts "Running some_method"
parameter + 1
end
Here are the key differences:
- The
def
keyword defines a method in Ruby just asfunction
in Javascript. - By convention, the name of the method
some_method
is in snake case whereas the name of the function in Javascript is in camel casesomeFunction
. - Parameters are defined in parentheses in both languages but we can omit the parentheses if the method has no parameter.
- the
end
keyword defines the method's body just as the curly parentheses do in Javascript. -
puts
is equivalent toconsole.log
. It will output to the terminal but has anil
return value. - The return value in a Ruby method will be always the last line in the method's body. The
return
keyword can be omitted and the method will implicitly return the last line.
Method Scope
In Javascript, functions have access to variables defined in their parent scope whether the parent scope consists of another function or the global scope. In Ruby scope functions differently. Any variable defined outside of the def
and end
keywords is unreachable:
guest_name = "Joe"
def say_hello_to_guest
puts "Hello #{guest_name}!"
end
=> NameError (undefined local variable or method `guest_name'
for main:Object)
Calling the guest_name
variable from inside the method will throw an undefined local variable error. To solve the issue of an out of scope variable, we have to pass is as an argument:
guest_name = "Joe"
def say_hello_to_guest
puts "Hello #{guest_name}!"
end
say_hello_to_guest(guest_name)
#=> "Hello Joe!"
Variables
In Javascript, declaring a variable require either let
or const
keywords preceding the variable name. A let
variable can be declared first before assigning a value to it whereas a const
variable hoists the declaration and the assignment at the same time. We cannot declare a const
without assigning a value to it. In Ruby, due to scoping issues as well as the concept of Object Oriented Programming, variables are treated differently.
Variables in Ruby:
- Local variables: start with a lower case or an underscore(_), should snake case if more than one word is used to name the variable (i.e. name = "Sarah", pet_name = "Pup").
- Global variables: start with a dollar sign ($) and are available in the global scope. They are rarely used because of debugging issues:
> $guest_name = "Joe"
=> "Joe"
> def say_hello_to_guest
> puts "Hello #{$guest_name}!"
> end
=> :say_hello_to_guest
> say_hello_to_guest
Hello Joe!
=> nil
- Instance variables: start with an at symbol (@) (i.e. @name = "Sarah").
- class variables: start with double at symbol (i.e. @@name = "Sarah"). Both instance and class variables are seen within the topic of Object Oriented Programming.
- Constant: holds data that does not change. Must be in all caps (i.e. NAME = "Sarah"). It is equivalent to
const
in Javascript. Scope wise, a constant can also be accessed from outside of the class using:book::GENRES
. Unlike Javascript declaring a variable with a constant in Ruby does not prevent the variable from being reassigned though it will give a warning.
Debugging in Ruby
Ruby comes with its own REPLs (Read, Evaluate, Print, Loop) when installed. The first REPL is IRB (Interactive Ruby) which is similar to the browser's console in Javascript. IRB allows you to experiment some procedural programming. It is a completely new environment, separate from our code, where we have to copy and paste the blocks of code we want to test. The second REPL is 'Pry
which offers more functionality than the previous one because it injects an interactive environment into our code. Pry
allows more flexibility in testing our code, we just have to add binding.pry
anywhere in our code similar to debugger
in Javascript.
Conclusion
Learning the syntax is the first step to learn a new language. It is also crucial to understand the concept the language is built around as well as its history https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/. After mastering Ruby fundamentals, the next step is to learn about Macros(getters and setters methods), initialize method, public vs private methods, self, class variables and methods, instance variables and methods, and class inheritance.
Top comments (0)