Ruby Notes

#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)

Ruby Loops

# 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)

Ruby Shoes

  • 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

# 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)