#RUBY PROJECTS AS EXCERCISE
# - game of life with GUI
# - calculator
# - sudoku solver (backpropagation)
# - file input reader -> word analyzer / char analyser
# TAKE HOME
# CRUD for create, read, update, and delete
# TAKE HOME 2
# Normally type checking is not done in Ruby, but instead objects are assessed
# based on their ability to respond to particular methods, commonly called “Duck
# typing”. In other words, if it responds to the methods you want, there’s no
# reason to be particular about the type.
# TAKE HOME 3
# almost everything is an object in ruby! Only exception are blocks!
# DATA TYPES IN RUBY
- symbols # Symbols are unique identifiers that are considered code, not data
- numbers # integer VS floats
# while strings represent data that can change, symbols represent unique values, which are static.
# if the text at hand is "data", then use a string. If its code, then use a symbol, especially when used as keys in hashes
# TESTING IN SANDBOX
# ruby irb: TESTENVIRONMENT IN CMD
irb # start IRB = Interactive Ruby (Shell)
irb
# DETERMINE DATA TYPE IN RUBY (anyways)
p 1.instance_of? Integer #=> True
p "1".instance_of? String #=> True
p [1,2].instance_of? Array #=> True
# alternative: is_a? (type)
p 1.is_a? (Integer)
p "string".is_a? (String)
# DISPLAY TO CONSOLE
puts "hello, World!" # adds newline at end
print "hello, World!" # no newline at end
print "hello,", 250, " World" # print different types (separate by comma)
# STRING OPERATIONS
.chomp # cuts last separotr? not sure yet.
.upcase #
.downcase # Uppercase converted to downcase
.capitalize # First character capitalized, others converted to downcase
.reverse # returns reversed string
.length # returns length of string
"hello,World".split(",") # splits string by delimitter, outputs array
.strip() # eliminates leading and ending whitespaces
.index()
.center(6, '-')
"Aksc" < "B" # true! compares first letter! Capitalization is important though!
# general substitution! replaces all instances of "f" with "F"
.gsub(/f/, "F")
.nil? #check if value is nil
# title methods
"hi".center(6, '-') # // --hi--
" hi ".center(12, '-') # // ---- hi ----
# OBJECT MODIFIERS (shortcut)
name.upcase! # same as name = name.upcase
name.gsub!(/f/, "F")
# QUESTIONMARK FUNCTIONS
# general rule: functions ending with "?" evaluate to true/false
.include? "substring" # matches substring -> returns true/false
"name".eql? "name" # true
"name".eql? "nam" # false
"name".include? "m" # true
"name".include? "x" # false
"name".index("a") # 1
"name".index("me") # 2
# EQL? method can be used on all objects?
1.eql? 1
x = [1,2,3]
x.eql? [1,2,3]
# MTHODS FOR INTEGERS
12.next # // 13 (doesnt work for floats)
"Thomas Starzynski"[0,3] # Tho
"Thomas Starzynski".index("Star") # 7
"Thomas Starzynski"[7,1] # Starzynski
# STRING INTERPOLATION vs CONCATENATION
puts "my name is #{name}" # interpolation
puts "my name is "+name # concatenation
puts "my name is " << name # concatenation with shovel (concatenation operator)
# relational operations
== # equal
!= # not equal
< # less than
<= # less than or equal
> # greater than
>= # greater than or equal
# logical / boolean operators
&& # and (short circuit)
|| # or (short circuit)
! # not
# why does short circuit matter?
# -> when having || the order is important
# -> it can happen that you can avoid throwing an exception by correct order
# assignment shortcuts
num += 1 # num = num + 1
num -= 1 # num = num - 1
# shovel parameter <<
# to push something (push = add at the end)
# e.g. push a new value to an array
x = [1,2,3]
x.push(4,5,6)
x << 7 # push multiple values is not possible with shovel right?
x = [1,2,3]
x.push(4,5,6) # pushing multiple objects is easy with "push"
x << 7 << 8 << 9 # pushing one object is better with shovel
# conditional assignments!
||= # only assign value if there is no value assigned yet! (first checks the variable)
name = "asd" unless name.nil? # alternative to think about this operator
# EXAMPLE CODE
name = nil
name ||= "thomas" # name has not assigned a value yet (nil=no assignment), so it gets assigned
name ||= "sam" # since name is already assigned, nothing happens here
# Multiple operations on one line
print "Hello, "; puts "world!"; puts " three";
p "Hello"
p [1,2,3,4].to_s
# ARRAYS
array = [1,2,3,4,5] # create array with 5 numbers
array[0] # acces first element
array.push(12) # adds value to array at the end!
string_array = ["hello"," ","world","!"]
# MATRICES
matrix = [[1,2,3],[4,5,6],[7,8,9]]
matrix.each {|row| row.each {|x| puts x}} # iterate over all elements
# HASHES
my_hash = { # HASH ROCKET STYLE =>
key1 => value1, # seperated with comma!!!
key2 => value2, # seperated with comma!!!
key3 => value3 # no comma!!!
}
# creating hashes
my_hash = Hash.new(default_value) # without default value: Hash.new
my_hash[key1] = value1
my_hash[key2] = value2
my_hash[key3] = value3
# new syntax since ruby 1.9!!! (similar to javascript!)
movies = {
start_wars: "amazing film!",
titanic: "but this ship can't sink!!",
troja: "Heeeeectoooooorrrr!",
}
# call hash
my_hash[key1] # like an array
# iterate over hash
hash.each do |key,value|
print "key: #{key}, value: #{value}"
end
# hash default value
my_hash.each_key # iterate over all keys
my_hash.each_value # iterate over all values
# UNKLAR:
freq = {
"thomas" => 1,
"mark" => 323,
"alex" => 15
}
freq = freq.sort_by do |key, val|
val
end
freq.reverse!
# sorting by key or value
freq = freq.sort_by {|key, val| key}
# MATH OPERATIONS
2 + 2 # addition
2 - 4 # subtraction
2**3 # potenzbildung
2/3 # dividing (integer)
2.0/3 # dividing (float numbers)
36 % 6 # modulo: remainder = 0
37 % 6 # remainder = 1
"Hello," << " world" << "!" # concatenation operator (SHOVEL)
.round(n) # round with given precision precision (n = how many decimal places)
2.342.round # = 2
2.342.round(2) # = 2.34
.ceil
2.342.ceil # = 3
.floor
2.342.floor # = 2
# SYMBOLS
.object_id # gets the id of an object
:string # symbol "called" "string". starts with ":"
p :string.object_id == :string.object_id # true
p "string".object_id == "string".object_id # false
.to_s # converting symbol (or other types) to string
.to_sym # conversion to symbol
.intern # conversion to symbol (other variation doing the same thing)
# IF-ELSE
num = 0
if num<0
puts "negative number"
elsif num>0
puts "positive number"
else
puts "number equals 0"
end
# short IF
puts "Its true" if true
# ternary If ELSE -> NOT DOING ANYTHING, returning a result!!
condition = false
condition ? return_if_true : return_if_false
# SWITCH
case language
when "JS"
puts "Websites!"
when "Python"
puts "Science!"
when "Ruby"
puts "Web apps!"
else
puts "I don't know!"
end
# fast switch
case language
when "JS" then puts "web"
when "html" then puts "web"
when "ruby" then puts "rails"
else puts "Error!"
end
# UNLESS (opposite of "IF")
problem = false
unless problem # if not
puts "we have a problem"
else
puts "no problemo amigo!"
end
# unless shortcut (when no "else" is needed)
puts "we have no problem" unless problem # short notation (same code)
# UNLESS ONE LINER
puts "not true" unless true
# WHILE
i = 0
while i<5
puts i
i += 1
end
# UNTIL (opposite of "while")
i += 1
until i == 6
puts i
i += 1
end
# FOR-Loop
# include last number
for num in 1..10 # 2 dots!
puts num
end
# exclude last number
for num in 1...10 # 3 dots!
puts num
end
# with steps
for num in (1..100).sep(10) # 10er schritte
puts num
end
# NEXT
for i in 1..5
next if i % 2 == 0
print i
end
# DO WHILE
i = 1
loop do
puts i
i += 1
break if i > 5
end
# DO SHORTCUT
i = 1
loop { # "{" replaces "do"
puts i
i += 1
break if i > 5
} # "}" replaces "end"
# FOR EACH ELEMENT OF OBJECT
array = [1,2,3,4,5] # defining array
#version 1
array.each do |x|
puts x
end
# alternative version (same code)
array.each { |x| puts x }
array.sort # sorts array ins ASC order (works for strings and numbers)
# TIMES ITERATOR
n = 10
n.times { print "hello\n"}
# UPTO / DOWNTO BLOCKS
95.upto(100) {|x| p x}
15.downto(0) {|x| p x}
"A".upto("X") {|x| puts x}
# COLLECT /same as MAP
# manipulates each element of an object and returns the full object
array = [1,2,3,4]
puts array.collect {|x| x+1} # returns manipulated object (new one)
array.collect! {|x| x+1} # object manipulation (add +1 to each item in the same array)
array.map! {|x| x+1} # map does the same than collect!
# SELECT
# selects each element of object given condition
# .select! VS .select
# METHODS
# methods must be defined before calling them! ruby doesnt "search" for methods
# define method
def title(msg, n, del)
puts " #{msg} ".center(n, "#{del}")
end
title("title1", 20, "-") # call the method
# SPLAT arguments (not neccessary but possible)
def greeter(string, *friends)
friends.each {|friend| puts "#{string}, #{friend}"}
end
# default parameters
def my_reverse(val1, val2=false)
val1.reverse!
if val2
puts "msg to console enabled!"
end
# val2s default value is true
end
# IMPLICIT RETURN
# -> last executed action is returned
def add(a,b)
a + b
end
# BLOCKS (nameless methods)
10.times do
puts "hello!"
end
10.times {puts "hello!"}
# YIELDING
def yield_name(name)
puts "In the method! Let's yield."
yield("Kim")
puts "In between the yields!"
yield(name)
puts "Block complete! Back in the method."
end
yield_name("Eric") { |x| puts "My name is #{x}." }
# PROCS -> blocks as methods!
cube = Proc.new { |x| x ** 3 }
# converting procs into blocks with "&"
&cube # -> proc converted to Block
# LAMBDAS #similar to procs
# Like procs, lambdas are objects. The similarities don't stop there: with the exception
# of a bit of syntax and a few behavioral quirks, lambdas are identical to procs.
# syntax: lambda { |param| block }
lambda_name = lambda { puts "Im inside the lambda!"}
&lambda_name # converts lambda to a block
# LAMBDA VS PROC
# - when inside a method, Proc returns immediately, lambda returns to the calling method
# - lambda checks number of arguments! It will throw an error if it doesnt match. Procs dont do that
# CLASSES
# nameConvetion: CamelCase and Capitalized
class Person # class definition
@@person_count = 0
initialize(name) # constructor
@name = name # @name is an instance variable (non-static fields in java)
@@person_count += 1
end
# self. can be replaced by the Classname!
def self.number_of_instances # instance methods! NON STATIC METHODS. Class-Methods in Java
return @@person_count
end
end
# VARIABLES/METHOD VISIBILITY & CONCEPTS
$variable # global variables = making variables visible outside of its method
@variable # instance variables
@@variable # class variables: all instances of a class have access to THE SAME variable!
# INHERITANCE
# < is read as "inherits from" or "is a"
class Item
def say_smth
return "im an item"
end
end
class CD < item # CD inherits from item (is-a relationship)
def say_smth # when same class method names: overrides method of the "upper" class
return "im a cd"
end
end
# When you call super from inside a method, that tells Ruby to look in the superclass
# of the current class and find a method with the same name as the one from which super
# is called. If it finds it, Ruby will use the superclass' version of the method.
# ONLY ONE INHERITANCE IN RUBY
# Not allowing multiple inheritance
# object.method (object is the "RECIEVER" of the method "method")
# Setter & Getter
class Person
attr_reader :name
attr_accessor :job
attr_writer :password
def initialize(name, job, password)
@name = name
@job = job
@password = password
end
def name
@name
end
def job=(new_job) # ruby convention of setters: "name_of_method=" -> the equals sign belongs to the name
@job = new_job
end
end
attr_writer :name # setter function short. eg: Person.name="Mark"
attr_reader :name # getter function short. eg: Person.name
attr_accessor :name # setter + getter function initizalized!
# MODULES
# similar to objects, but you cant initialize instances of them, the just STORE things
module Circle
CONSTNAT_PI_ALL_CAPS = 3.14 # constants can be changed, but shouldnt! Ruby warns you if you want to do it
end
# accessing constant from outside the module (with two ":")
Circle::CONSTNAT_PI_ALL_CAPS
# importing modules
require 'circle' # import modules, always small_cases. You can acces the methods with Circle.method()
include Circle # only in class sphere, to import a module into a class!
# imports so we dont need to use the ModuleName::GLOBAL_VAR notation and can just write GLOBAL_VAR
# INCLUDING VS EXTENDING!
module ThePresent
def now; puts Time.now; end
end
class TheHereAnd
extend ThePresent
include ThePresent
end
TheHereAnd.now # access module method through extended (Class as whole acceses module method)
TheHereAnd.new().now # access module method through inclusion (instance of an object accesses method)
- library to create canvases (similar to JFrame in java)
# basic app
Shoes.app(title: "myApp") do
# todo
end
# stack (VERTIKAL)
stack(margin: 10) do # do something
end
# flow (HORIZONTAL)
flow(margin: 10) do # do something
end
# button
button("button label")
# paragraph
para("this is a paragraph")
# caption
caption("TITLE! (displayed bold and big)", margin: 10)
# info pane (OK)
alert("Hi, im an alert! You can only click OK to make me disappear!")
# get user input (OK | CANCEL)
my_name = ask("Please, enter your name:") # stores input in variable name
# colorpicker tool lets user pick a color
my_color = ask_color("Pick a background") # stores color in variable my_color
Shoes.app {background my_color}
# get content of a file
filename = ask_open_file
Shoes.app do
para File.read(filename)
end
# QUESTIONS RUBY
- Yielding -> what is it good for?
- FUNCTION CONFUSION: between .push(input) VS .includes? "asd" VS .collect {BLOCK}
- confusion around a lot of new concepts lambda, Procs, Blocks, Yielding and Modules
# PROC TO BLOCK CONVERSION IS CLEAR, but whats the : for?
# Converting method to a proc? ":" stands for symbols right? Example
numbers_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
strings_array = numbers_array.map(&:to_s)