-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy path09_oop.rb
193 lines (154 loc) ยท 5.46 KB
/
09_oop.rb
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# OOP = OBJECT ORIENTED PROGRAMMING
puts "*OOP I*"
# Ruby is an object-oriented language
# As any other OOP language, it uses *objects* to store *attributes* and *methods* to store *behaviours*
# ATTRIBUTES = (objects = intances of a Class)
# +
# BEHAVIOURS = (methods = instances of functions)
# 1. Attributes
# 1. Attributes
"Hello!".length # => I apply the method length on a string, and it returns the attribute `6` of type `Integer`
4.even? # => returns `true`, an attribute of type `TrueClass` (a method with a question mark returns a boolean, it's convention! check https://rubyonrails.org/doctrine/#convention-over-configuration)
teachers = [ # => returns the variable `teachers`: an `Array` with inside two `Hash`es
{
name: "Mariana",
age: 37,
country: "Portugal"
},
{
name: "Gabriele",
age: 27,
country: "Italy"
},
{
name: "Shannon",
age: 33,
country: "USA"
}
]
# Procs and lambdas (block of code contained in `do end` or `{ }`)
# A lambda *is a proc* with some additional features (see previous the lesson!)
print_name = Proc.new { |person| puts person[:name] }
# or
print_name = lambda { |person| puts person[:name] }
# or (new faster and cleaner way for a lambda!)
print_name = ->(person) { puts person[:name] }
teachers.each(&print_name)
# From now on always use this syntax to assign a lambda (the other ones are obsolete)
get_flag = ->(person) do
case person[:country]
when "Portugal" then "๐ต๐น"
when "Italy" then "๐ฎ๐น"
when "USA" then "๐บ๐ธ"
else "๐"
end
end
# 2. Behaviours
# 2.1 Standard methods
# Let's pass the lambda to a method
# The most common methods for a collection:
# - :map -> returns the values
# - :each -> returns always nil, but it can execute some other methods (actions) while looping
flags = teachers.map(&get_flag)
puts "---"
puts "Le Wagon guys:"
teachers.each_with_index do |teacher, index|
puts "#{teacher[:name]} from #{flags[index]}"
end
puts "---"
# 2.2 Custom methods
def get_italians(people)
is_italian = ->(person) { person[:country] == "๐ฎ๐น" } # another lambda
people.filter(&is_italian) # pass the lambda to the filter method, and return (implicitly!) the italian teachers
end
students = [
{
name: "Federico",
country: "๐ฎ๐น"
},
{
name: "Nuno",
country: "๐ต๐น"
},
{
name: "Flavia",
country: "๐ฎ๐น"
},
{
name: "Riccardo",
country: "๐ฎ๐น"
}
]
italian_students = get_italians(students).map { |student| student[:name] } # call the method and get the string
puts "Some italians guys following the course: #{italian_students.join(', ')}"
#####################################
# Classes
# Syntax:
# - ClassName => the 'mold'
# - class_instance => the 'cake'
# I can initialize any object (and 'label' it with a variable) with ObjectClassName.new, except for booleans and numbers (it's too intuitive already, we just need to type them!)
# Basic objects:
booleans = [true, false] # [TrueClass, NilClass]
numbers = [1993, 3.14] # [Integer, Float]
"Hello there!" # String.new("Hello there!")
[] # Array.new
{} # Hash.new
proc = Proc.new { |param| puts param }
# or
proc = proc { |param| puts param }
# or
lambda = lambda { |param| puts param }
# or
lambda = ->(param) { puts param } # always use this one!
# There are a lot of pre-defined classes, let's print some of them! ๐คฉ
puts "---"
puts "All the available Ruby classes:"
ruby_classes = ObjectSpace.each_object(Class).to_a # => array with all available classes (don't worry about the :each_object method now)
puts ruby_classes
# One of them is the `File` class, to manipulate files
# Let's use it to store the `welcome.rb` file and print its content! ;)
# Check this article on RubyGuides ๐ https://www.rubyguides.com/2015/05/working-with-files-ruby
welcome_file = File.new("test/welcome.rb")
file_content = welcome_file.read
puts "---"
puts file_content
# Methods
# Method.new does not exist because it's a *behaviour* and not an attribute
# I can just use `def end` to declare a new method
def say_hello
puts "Hello there"
end
def return_hello
puts "I'm another string"
"I'm will be printed after!" # implicit return
end
puts "---"
say_hello
hello_string = return_hello # assign the string "hello"
puts hello_string
puts "---"
#####################################
# What if I want my own class with its own attributes and the behaviours I want?
# Syntax:
# ClassName # => "mold"
# instance = ClassName.new(attributes) # => "cake", one unit of that class
# Place it in one file with the same name
# You need to convert the UpperCamelCase syntax of the model name to lower_snake_case.rb for the file
# LeWagonTeacher => le_wagon_teacher.rb
# To require a file we need to use the require_relative keyword, followed by the path relative to the current file
require_relative "test/teacher.rb"
# Why we don't use just require?
# Because require is reserved for gems (what is a gem? check it on RubyGuides!) and file systems, so we need to load the file relatively to where we are
attributes = {
name: "Gabriele",
age: 26,
country: "Italy"
}
# Instances of the Teacher model, initialized with some attributes
gabriele = Teacher.new(attributes)
mariana = Teacher.new(name: "Mariana", country: "Portugal")
# Actions executed on the instance of the model (behaviours)
print_teacher_welcome_message = ->(teacher) { puts teacher.welcome_message }
[gabriele, mariana].each(&print_teacher_welcome_message)
gabriele.birthday
puts "He is turning #{gabriele.age}" # => 27