Upload
heather-campbell
View
408
Download
2
Embed Size (px)
DESCRIPTION
Introduction to Ruby with accompanying code at https://github.com/heatherjc07/RubyIntroduction. Covers flow control, methods, classes and types
Citation preview
Syntactic
SugarProductiveDevelopers
• Everything is an Expression
• Everything is an Object
• Supports Dynamic Reflection
GETTING STARTED
current_count = 5final_salary = 30000.00
Snake CaseReadable
String.methods.sortString.instance_methods.sort
Methods
my_array.empty?person.retired?
True or False
str.upcase vs str.upcase!
Create New vs Modify Existing
io.rb
print “Enter your name: ”name = getsputs name.strip + “ is learning Ruby”
Input / Output
[4,2,3,5].sort.map{ |e| e * e}.join(',')# "4,9,16,25"
Method Chaining
• Write some code to ask a user to input a number. Take the number multiply it by 10 and display it back to the user
• Find a method to capitalize a string
• Check the class of 1. (using the .class method) then find a method to check if the number is even
Exercises
TYPES
true.class# TrueClass
false.class# FalseClass
true.to_s# "true"
Boolean
1.class# Fixnum
Fixnum.superclass# Integer
111_000_000.class# Fixnum
Numbers
1111111111.class# Bignum
Bignum.superclass# Integer
1.2345.class# Float
String.method.count# Lots of helpful methods!"Ruby" * 4# "RubyRubyRubyRuby""Ruby" + " " + "Ruby"# "Ruby Ruby"a = "I don’t know Ruby"a["don’t"] = "do"# "I do know Ruby"
String
number_of_girls = 4number_of_boys = 6
puts "number of girls #{number_of_girls}"puts "number of boys #{number_of_boys}"puts "number of people #{number_of_boys + number_of_girls}"
Interpolation
phone = "(028 90)454 545"phone.gsub!(/\D/, "") puts "Phone Number : #{phone}"# "02890454545"
puts "Heather Campbell".gsub(/([a-zA-Z]+) ([a-zA-Z]+)/, "\\2, \\1")# "Campbell, Heather"
Regex
attr_accessor :driver
:small :medium :large
a = :smallb = :smalla.object_id == b.object_id# true
:small.to_s# "small "
"small".to_sym# :small Symbols
arr = [1,2,'three', :big]arr.size # 4arr.empty? # falsearr[1] # 2arr[-1] # :bigarr[1..3] # [2,'three', :big]arr[4..5] = [:east, :west]# [1,2,'three', :big, :east, :west]arr << 10# [1,2,'three', :big, :east, :west,10]
Arrays
[1,2,3].map { |e| e * e}# [1,4,9]
[2,2,3].reduce{|total,v| total * v}# 12
['act', 'bat', 'them'] .all? { |w| w.length >= 3 }# true
Enumerable
h = {'France' => 'Paris', 'Ireland' => 'Dublin' }h = {France: 'Paris', Ireland: 'Dublin' }
h[:France]# 'Paris‘
h[:Italy] = 'Rome' # h = {France: 'Paris', Ireland: 'Dublin', Italy: # 'Rome' }
h.each {|k,v| puts "key: #{k} \t value: #{v}"}
h.any? { |k,v| v == 'Rome' }
Hashes
(1..5).each{|v| p v}# 1,2,3,4,5
(1…5).each{|v| p v}# 1,2,3,4
(10..20).include?(19) # true
(2..5).end # 5
("aa".."ae").each{|v| p v}# "aa","ab","ac","ad","ae"
Ranges
def get_values; [1,2,3,4]; end;
first, _, _, last = get_values# first = 1, last = 4
a, *b, c = get_values# a = 1, b = [2,3],c = 4
r = (0..5)a = [1,2,*r]# a = [1,2,0,1,2,3,4,5]
Splat Operator
• Separate an array [1,2,3,4] into 2 variables one holding the head of the array (i.e 1) and the other the rest of the array [2,3,4]
• Create a hash of months and days in a month e.g. {January: 31, ..}. For each month print out the month name and number of days. Then print out totals days in year by summing the hashes values
Exercises
FLOW CONTROL
if mark > 75 report = "great"elsif mark > 50 report = "good"else report = "needs work"end
if else
report = if mark > 75 then "great"elsif mark > 50 then "good"else "needs work"end
if !order.nil? order.calculate_taxend
unless
order.calculate_tax unless order.nil?
speed = 60limit = 40
speed > limit ? puts("Speeding!") : puts("Within Limit")
ternary operator
mark = 42 && mark * 2# translates to mark = (42 && mark) * 2
mark = 42 and mark * 2# returns 84
post = Posts.locate(post_id) and post.publish# publishes post if it is located
and / or
if engine.cut_out? engine.restart or enable_emergency_powerend
grade = case markwhen 90..100 "A"when 70..89 "B"when 60..69 "C"when 50..59 "D"when 40..49 "E"else "F"end case
case unitwhen String puts "A String!" when TrueClass puts "So True!"when FalseClass puts "So False!" end
while count < max puts "Inside the loop. count = #{count}" count +=1end
while
puts "count = #{count += 1}" while count < max
until count > max puts "Inside the loop. count = #{count}" count +=1end
until
array = [1,2,3,4,5,6,7]array.pop until array.length < 3
begin puts "Inside the loop. count = #{count}" count +=1end while count < max
looping block
for count in (1..10) puts "Inside the loop: count = #{count}"end
for
animals = {cat: "meow ", cow: "moo "}
animals.each do |k,v| puts "The #{k} goes #{v}"end
iterators
animals = {cat: "meow ", cow: "moo "}
animals.each {|k,v| puts "The #{k} goes #{v} "}
magic_number = 5; found = false; i = 0; input = 0;while i < 3 print "Please enter a number between 1 and 10: " input = gets.to_i unless input.between?(1,10) print "invalid number"; redo end if input == magic_number found = true; break end i += 1endfound ? put "found! " : put " bad luck "
flow control
def display_content(name) f = File.open(name, 'r') line_num=0 # raise 'A test exception.' f.each {|line| print "#{line_num += 1} #{line}"}rescue Exception => e puts "ooops"; puts e.message; puts e.backtraceelse puts "\nSuccessfully displayed!"ensure if f then f.close; puts "file safely closed"; endend
exception handling
def get_patients() patients = API.request("/patients")rescue RuntimeError => e attempts ||= 0 attempts += 1 if attempts < 3 puts e.message + ". Retrying request. “ retry else puts "Failed to retrieve patients" raise endend
exception handling
• Write some conditional logic to capitalize a string if it is not in uppercase
• Print out your name 10 times• Print the string “This is sentence number 1”
where the number 1 changes from 1 to 10• Write a case statements which outputs
“Integer” if the variable is an integer, “Float” if it is a floating point number or else “don’t know!”
Exercises
CLASSES
class Vehicle
def drive(destination) @destination = destination end
end
Classes
class Vehicle
attr_accessor :destination
def drive(destination) self.destination = destination # do more drive stuff end
endAccessors
Accessors
attr_accessor
attr_reader
attr_writer
class Vehicle attr_accessor :colour, :make
def initialize(colour, make) @make = make @colour = colour end
end
Constructor
class SuperCar < Vehicle
def drive(destination) self.destination = destination
puts 'driving super fast' end
end
Inheritance
class SuperCar < Vehicle
attr_accessor :driver
def drive(circuit, driver) self.destination = destination
self.driver = driver puts 'driving super fast'
endend
Inheritance
Duck Typing
“If it walks like a duck and talks like a duck, it must be a duck”
class Person def quack() puts 'pretends to quack' endend
class Duck def quack() puts 'quack quack' endend
Duck Typing
def call_quack(duck) duck.quackend
call_quack(Duck.new)# quack quack
call_quack(Person.new)# pretends to quack
Duck Typing
class Vehicle
def crash() explode end
private def explode() puts "Boom!" endend
Method Visibility
class Vehicle
def crash() explode end
def explode() puts "Boom!" end private :explodeend
class SuperCar < Vehicle def explode() puts "Massive Boom!" endend
Method Visibility
result = class Test answer = 7+5 puts " Calculating in class: " + answer.to_s answerend
puts "Output of the class: " + result.to_s
Executable
class Rocket ….
end
r = Rocket.new
class Rocket def land() puts "Back on Earth" endend
r.land
Open Classes
class String def shout self.upcase! self + "!!!" end
def empty? true endend
Monkey Patching
a = "abc"b = ac = "abc"a.equal?(b)# truea.equal?(c)# falsea == b# truea == c# true
Equality
• Create a class to represent a Computer• Create an instance of the Computer called
computer• Add a starting_up method• Create a class WindowsComputer which
inherits from Computer• Create an instance of the WindowsComputer
called wcomputer and call starting_up on it• Alter WindowsComputer to allow the user to
set a name value when they create an instance. Allow the user to set and get the name attribute
Exercises
METHODS
# Javapublic Car() { …}public Car(String make) { }public Car(String make, String model) { }public Car(String make, String model, String colour) { }
# Rubydef initialize (make = :Ford, model = Car.get_default_model(make), colour = (make == :Ferrari ? 'red' : 'silver') ) …end
Overloading Methods
def create_car (make = :Ford, model = get_default_model(make), colour) …end
create_car('red' )
Method Parameters
def produce_student(name, *subjects) …end
produce_student('June Black', 'Chemistry', 'Maths', 'Computing' )
subject_list = ['Chemistry', 'Maths', 'Computing']produce_student('June Black', *subject_list)
Variable Length Param List
class Meteor attr_accessor :speed
def initialize() @speed = 0 end
def +(amt) @speed += amt end
def -(amt) @speed > amt ? (@speed -= amt) : (@speed = 0) endend
Operators
class Roman def self.method_missing name, *args roman = name.to_s roman.gsub!("IV", "IIII") roman.gsub!("IX", "VIIII") roman.gsub!("XL", "XXXX") roman.gsub!("XC", "LXXXX") (roman.count("I") + roman.count("V") * 5 + roman.count("X") * 10 + roman.count("L") * 50 + roman.count("C") * 100) endend
Method Missing
handlers = { up_arrow: :tilt_up, down_arrow: :tilt_down, left_arrow: :turn_left, right_arrow: :turn_right}
ship.__send__(handlers[input])
Send
• Alter the WindowsComputer class you created in the last exercise to make the name parameter optional
• Try creating an instance with and without a name value
• Add a mandatory attribute called owner to the class and alter initialize to set it.
• Try creating a new instance with no, 1 and 2 parameter values. What happens?
• add a method display_details to output the name and owner of the machine and try calling it using __send__
• now make display_details private and try calling it directly and using __send__. Notice anything odd?
Exercises
OTHER FEATURES
def block_exampleputs 'Optional block example.'if block_given?
yield "Heather" else puts 'No block. Very Empty' end puts 'End of example'end
Blocks
def with_timingstart = Time.nowif block_given?
yield puts 'Time taken: #{Time.now - start}' endend
Blocks
def add_numbers(x, y) x + yend
alter the above method to accept a block and execute it if one is supplied. Call it with a block to provide debug i.e. displaying the method name and values passed
Exercises
TESTING
Test
Driven
Development
Behaviour
Driven
Development
MiniTest
require 'minitest/autorun'require '../lib/People'class TestEmployee < MiniTest::Unit::TestCase
def setup @employee = Employee.new end
def test_employer assert_equal "Kainos", @employee.employer end
end
MiniTest
require "minitest/autorun"
describe Employee do before do @employee = Employee.new end
describe "when asked for an employer" do it "must provide one" do @employee.employer.must_equal "Kainos" end end end
RSpec
# bowling_spec.rbrequire 'bowling'
describe Bowling, "#score" do it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should eq(0) end
end
Cucumber
# division.feature
Feature: Division In order to avoid silly mistakes Cashiers must be able to calculate a fraction
Scenario: Regular numbers * I have entered 3 into the calculator * I have entered 2 into the calculator * I press divide * the result should be 1.5 on the screen
Cucumber
#calculator_steps.rb
Before do @calc = Calculator.newend
Given /I have entered (\d+) into the calculator/ do |n| @calc.push n.to_iend
When /I press (\w+)/ do |op| @result = @calc.send opend
Want to Learn More?
Codecademy http://www.codecademy.com/tracks/ruby
CodeSchool https://www.codeschool.com/paths/ruby
Seven Languages in Seven Weeks pragprog.com/book/btlang/seven-languages-in-seven-weeks
Want to Learn More?
Programming Ruby pragprog.com/book/ruby/programming-rubyFirst edition available for free online at http://ruby-doc.com/docs/ProgrammingRuby/
Ruby Koans http://rubykoans.com
Pluralsight
Any Questions?