You are on page 1of 109

EXPRESSIONS

ICONS

Bad Code

Worse Code

Good Code

Awesome Code

EXPRESSIONS
UNLESS
if ! tweets.empty?
puts "Timeline:"
puts tweets
end

Unless is more intuitive


unless tweets.empty?
puts "Timeline:"
puts tweets
end

EXPRESSIONS
UNLESS WITH ELSE
unless tweets.empty?
puts "Timeline:"
puts tweets
else
puts "No tweets found - better follow some people!"
end

Unless with else is confusing


if tweets.empty?
puts "No tweets found - better follow some people!"
else
puts "Timeline:"
puts tweets
end
NIL IS FALSE-Y
if attachment.file_path != nil
attachment.post
end

nil treated as false

if attachment.file_path
attachment.post
end

EXPRESSIONS
ONLY NIL IS FALSE-Y
"" treated as true!
0 treated as true!
[] treated as true!

unless name.length
warn "User name required"
end

will never be false!


EXPRESSIONS
INLINE CONDITIONALS
if password.length < 8
fail "Password too short"
end
unless username
fail "No user name set"
end

try inline if/unless


fail "Password too short" if password.length < 8
fail "No user name set" unless username

EXPRESSIONS
SHORT-CIRCUIT - AND
if user
if user.signed_in?
#...
end
end

use && instead


e r i s n i l
if user && user.signed_in? if us er run s
#... h a l f n ev
s e c on d
end

EXPRESSIONS
SHORT-CIRCUIT ASSIGNMENT
result = nil || 1 1
result = 1 || nil 1
result = 1 || 2 1

EXPRESSIONS
DEFAULT VALUES - OR
tweets = timeline.tweets
tweets = [] unless tweets

if nil, default to empty array


tweets = timeline.tweets || []

EXPRESSIONS
SHORT-CIRCUIT EVALUATION
def sign_in
current_session || sign_user_in
end

not evaluated unless


but consid current session is nil
er wheth
if/then w er
ould be mo
re legible
!
EXPRESSIONS
CONDITIONAL ASSIGNMENT
i_was_set = 1
F th e r e s
i_was_set ||= 2
as s i g n s I
i n g va l ue
puts i_was_set 1 no e x i s t

i_was_not_set ||= 2

puts i_was_not_set 2

EXPRESSIONS
CONDITIONAL ASSIGNMENT
options[:country] = 'us' if options[:country].nil?
options[:privacy] = true if options[:privacy].nil?
options[:geotag] = true if options[:geotag].nil?

use conditional assignment


options[:country] ||= 'us'
options[:privacy] ||= true
options[:geotag] ||= true

EXPRESSIONS
CONDITIONAL RETURN VALUES
if list_name
options[:path] = "/#{user_name}/#{list_name}"
else
options[:path] = "/#{user_name}"
end

assign the value of the if statement


options[:path] = if list_name
"/#{user_name}/#{list_name}"
else
"/#{user_name}"
end
CONDITIONAL RETURN VALUES
def list_url(user_name, list_name)
if list_name
url = "https://twitter.com/#{user_name}/#{list_name}"
else
url = "https://twitter.com/#{user_name}"
end
url
end

EXPRESSIONS
CONDITIONAL RETURN VALUES
def list_url(user_name, list_name)
if list_name
"https://twitter.com/#{user_name}/#{list_name}"
else
"https://twitter.com/#{user_name}"
end
end

EXPRESSIONS
CASE STATEMENT VALUE
client_url = case client_name
when "web"
"http://twitter.com"
when "Facebook"
"http://www.facebook.com/twitter"
else
nil
end

EXPRESSIONS
CASE - RANGES
popularity = case tweet.retweet_count
when 0..9
nil
when 10..99
"trending"
else
"hot"
end

EXPRESSIONS
CASE - REGEXPS
tweet_type = case tweet.status
when /\A@\w+/
:mention
when /\Ad\s+\w+/
:direct_message
else
:public
end

EXPRESSIONS
CASE - WHEN/THEN
tweet_type = case tweet.status
when /\A@\w+/ then :mention
when /\Ad\s+\w+/ then :direct_message
else :public
end

EXPRESSIONS
EXPRESSIONS
METHODS AND CLASSES
OPTIONAL ARGUMENTS
def tweet(message, lat, long)
#...
end
tweet("Practicing Ruby-Fu!", nil, nil)

location isnt always used, so lets add defaults


def tweet(message, lat = nil, long = nil)
#...
end
tweet("Practicing Ruby-Fu!")

location is now optional


METHODS
NAMED ARGUMENTS - HASH
def tweet(message, lat = nil, long = nil, reply_id = nil)
#...
end
long parameter list
tweet("Practicing Ruby-Fu!", 28.55, -81.33, 227946)

calls to it are hard to read


tweet("Practicing Ruby-Fu!", nil, nil, 227946)

have to keep placeholders for


METHODS arguments youre not using
HASH ARGUMENTS
def tweet(message, options = {}) hash argument
status = Status.new
status.lat = options[:lat]
status.long = options[:long]
status.body = message
status.reply_id = options[:reply_id]
status.post
end

reference keys
from hash

METHODS
HASH ARGUMENTS
def tweet(message, options = {})

tweet("Practicing Ruby-Fu!",
:lat => 28.55,
:long => -81.33,
:reply_id => 227946 all combined into
) keys show meaning options argument
NAMED ARGUMENTS - HASH
Using Ruby 1.9 hash syntax
tweet("Practicing Ruby-Fu!",
lat: 28.55 ,
long: -81.33 ,
reply_id: 227946 COM BO X2 !
)

Repositioning the keys


tweet("Practicing Ruby-Fu!",
reply_id: 227946,
lat: 28.55 ,
long: -81.33
COM BO X3 !
)
NAMED ARGUMENTS - HASH
Keys are optional
tweet("Practicing Ruby-Fu!",
reply_id: 227946
) COM BO X4 !

Complete hash is optional


tweet("Practicing Ruby-Fu!")
COM BO X5 !
EXCEPTIONS
def get_tweets(list)
if list.authorized?(@user)
list.tweets
else
[] magic return value
end
end

tweets = get_tweets(my_list)
if tweets.empty?
alert "No tweets were found!" +
"Are you authorized to access this list?"
end
cant be sure its an error
EXCEPTIONS
def get_tweets(list)
unless list.authorized?(@user)
raise AuthorizationException.new
end
list.tweets
end

raise an Exception instead


begin
tweets = get_tweets(my_list)
rescue AuthorizationException
warn "You are not authorized to access this list."
end

caller KNOWS theres a problem


SPLAT ARGUMENTS
def mention(status, *names)
tweet("#{names.join(' ')} #{status}")
end

status names[0] names[1] names[2]

mention('Your courses rocked!', 'eallam', 'greggpollack', 'jasonvanlue')

eallam greggpollack jasonvanlue Your courses rocked!

METHODS
YOU NEED A CLASS WHEN...
user_names = [
["Ashton", "Kutcher"],
["Wil", "Wheaton"],
["Madonna"]
]
user_names.each { |n| puts "#{n[1]}, #{n[0]}" }

O UTP U T :
your users shouldnt
Kutcher, Ashton
Wheaton, Wil have to deal with
, Madonna edge cases

CLASSES
YOU NEED A CLASS WHEN...
class Name
def initialize(first, last = nil)
@first = first state!
@last = last
end
def format
[@last, @first].compact.join(', ')
end
end

behavior!
CLASSES
YOU NEED A CLASS WHEN...
user_names = []
user_names << Name.new('Ashton', 'Kutcher')
user_names << Name.new('Wil', 'Wheaton')
user_names << Name.new('Madonna')
user_names.each { |n| puts n.format }

O UTP U T :
Kutcher, Ashton
Wheaton, Wil
Madonna edge case handled!

CLASSES
OVERSHARING?
class Tweet attr_accessor :baz

same as
attr_accessor :status, :created_at
def initialize(status) def baz=(value)
@status = status @baz = value
@created_at = Time.new end
end def baz
end @baz
end

tweet = Tweet.new("Eating breakfast.")


tweet.created_at = Time.new(2084, 1, 1, 0, 0, 0, "-07:00")

shouldnt be able to do this!


CLASSES
OVERSHARING?
class Tweet doesnt define a
attr_accessor :status
attr_reader :created_at setter!
def initialize(status)
@status = status
@created_at = Time.new
end
end

tweet = Tweet.new("Eating breakfast.")


tweet.created_at =
Time.new(2084, 1, 1, 0, 0, 0, "-07:00")

undefined method 'created_at='


CLASSES
RE-OPENING CLASSES
tweet = Tweet.new("Eating lunch.")
puts tweet.to_s

#<Tweet:0x000001008c89e8> not so r ea da bl e. . .

class Tweet
def to_s
-op en t h e
"#{@status}\n#{@created_at}" so just re
de f i n e i t!
end
end
class and re
tweet = Tweet.new("Eating lunch.")
puts tweet.to_s

Eating lunch.
2012-08-02 12:20:02 -0700
RE-OPENING CLASSES
You can re-open and change any class.
Beware! You don't know who relies on the old functionality.
You should only re-open classes that you yourself own.

CLASSES
SELF
class UserList list = UserList.new('celebrities')
attr_accessor :name list.name
def initialize(name)
name = name e
re -s e t s t h
end
this j us t
end
oc a l va r i a bl e ! nil
nam e l

class UserList list = UserList.new('celebrities')


attr_accessor :name list.name
def initialize(name)
self.name = name
end
a l l s n a me =
end but th i s c
e n t ob j ec t "celebrities"
on the c ur r
METHODS AND CLASSES
CLASSES
ENCAPSULATION
send_tweet("Practicing Ruby-Fu!", 14)

def send_tweet(status, owner_id)


retrieve_user(owner_id)
...
end

should not be responsible for


retrieving a user

CLASSES
ENCAPSULATION
Passing around data as strings and numbers breaks encapsulation.
Places using that data need to know how to handle it.
Individual changes require updates at various places.

CLASSES
ENCAPSULATION
tweet = Tweet.new
class Tweet
tweet.status = "Practicing Ruby-Fu!"
attr_accessor ...
tweet.owner_id = current_user.id
def owner
send_tweet(tweet)
retrieve_user(owner_id)
end
end
one parameter!

def send_tweet(message)
message.owner
...
end

CLASSES
ENCAPSULATION
May not be worth the overhead of a class if all you have is data.
An option hash might suce.
When you have behavior to go with the data, it's time to introduce a class.

CLASSES
VISIBILITY
class User
joe = User.new 'joe'
leo = User.new 'leo'
def up_vote(friend)
bump_karma
joe.up_vote(leo)
friend.bump_karma
end
karma up for joe
def bump_karma
karma up for leo
puts "karma up for #{name}"
end

end

should not be part


of the public API
VISIBILITY
class User
joe = User.new 'joe'
leo = User.new 'leo'
def up_vote(friend)
bump_karma
joe.up_vote(leo)
friend.bump_karma
end
private method 'bump_karma' called
private for #<User:0x10ad1f6b8>
def bump_karma
puts "karma up for #{name}"
end
private methods cannot be
end
called with explicit receiver
VISIBILITY
class User
joe = User.new 'joe'
leo = User.new 'leo'
def up_vote(friend)
bump_karma
joe.up_vote(leo)
friend.bump_karma
end
karma up for joe
protected karma up for leo
def bump_karma
puts "karma up for #{name}"
end hidden from outside but accessible
end from other instances of same class
INHERITANCE
class Image f un c ti on a l i ty !
attr_accessor :title, :size, :url duplicated
def to_s
"#{@title}, {@size}"
end
end

class Video
attr_accessor :title, :size, :url
def to_s
"#{@title}, {@size}"
end
end
INHERITANCE
class Attachment class Video < Attachment
attr_accessor :title, :size, :url attr_accessor :duration
def to_s end
"#{@title}, #{@size}"
end
D R Yer! e s
end much e th o d on l y m a k
class Image < Attachment
if a m bc l a s s ,
or on e s u
end sense f
t h e r e .
class Video < Attachment put it
end
SUPER
class User class Follower < User
def initialize(name) def initialize(name, following)
@name = name @following = following
end end
end def relationship

does n t c a l l "#{@name} follows #{@following}"


end
n i ti a l i z e
User#i end

follower = Follower.new("Oprah", "aplusk")


follower.relationship

no @ n a m e !
" follows aplusk"
CLASSES
SUPER
class User class Follower < User
def initialize(name) def initialize(name, following)
@name = name @following = following
end super(name)
end end
Calls def relationship
n i ti a l i z e "#{@name} follows #{@following}"
User#i end
end

follower = Follower.new("Oprah", "aplusk")


follower.relationship

"Oprah follows aplusk"


CLASSES
SUPER
class Grandparent
def my_method child = Child.new
"Grandparent: my_method called" puts child.my_method
end
end

class Parent < Grandparent


end Grandparent: my_method called
not here Child: my_method called
class Child < Parent
def my_method
string = super
"#{string}\nChild: my_method called"
end
end
SUPER
class Grandparent
def my_method(argument) child = Child.new
"Grandparent: '#{argument}'" puts child.my_method('w00t!')
end
end

Grandparent: 'w00t!'
class Child < Parent Child: 'w00t!'
def my_method(argument)
string = super
"#{string}\nChild: '#{argument}'"
end
end

r ( a r gumen t)
me a s s upe
CLASSES
sa
OVERRIDING METHODS
class Attachment
def preview
case @type
when :jpg, :png, :gif typi c a l c a s e
thumbnail
when :mp3 th e oddb a l l
player
end
end
end

This i s s l ow
CLASSES
OVERRIDING METHODS
class Attachment class Audio < Attachment
def preview def preview
new
thumbnail player subc l a s s !
end end
h a n dl i n g
end
the default end special

CLASSES
HIDE INSTANCE VARIABLES
class User
def tweet_header
[@first_name, @last_name].join(' ')
end
def profile
[@first_name, @last_name].join(' ') + @description
end
end

a lot of repetit
ion when
working with the
se...
CLASSES
HIDE INSTANCE VARIABLES
class User
def display_name
[@first_name, @last_name].join(' ')
end
def tweet_header
display_name
end
def profile
display_name + @description
end
end

you can use an a


ccessor metho
even within the d,
CLASSES
s a me class
HIDE INSTANCE VARIABLES
class User
def display_name
title = case @gender COM BO X2 !
when :female
married? ? "Mrs." : "Miss"
when :male
"Mr."
end
[title, @first_name, @last_name].join(' ')
end
end

t o c h a n g e t h e l og ic
if you n eed
it in j us t o n e pla c e!
CLASSES later, you c a n d o
ACTIVESUPPORT
ACTIVESUPPORT
Install It
$ gem install activesupport
not a dependency,
$ gem install i18n
but it is helpful

Load It
require 'active_support/all'

ACTIVESUPPORT
CORE EXTENSIONS: ARRAY

array = [0, 1, 2, 3, 4, 5, 6]

array.from(4) [4, 5, 6]
array.to(2) [0, 1, 2]
array.in_groups_of(3) [[0, 1, 2], [3, 4, 5], [6, nil, nil]]
array.split(2) [[0, 1], [3, 4, 5, 6]]

removes the pads with


element it s n il
plits on

ACTIVESUPPORT
CORE EXTENSIONS: DATE
apocalypse = DateTime.new(2012, 12, 21, 14, 27, 45)

Fri, 21 Dec 2012 14:27:45 +0000

apocalypse.at_beginning_of_day

Fri, 21 Dec 2012 00:00:00 +0000

apocalypse.at_end_of_month

Mon, 31 Dec 2012 23:59:59 +0000

apocalypse.at_beginning_of_year

Sun, 01 Jan 2012 00:00:00 +0000


ACTIVESUPPORT
CORE EXTENSIONS: DATE
apocalypse = DateTime.new(2012, 12, 21, 14, 27, 45)

Fri, 21 Dec 2012 14:27:45 +0000

apocalypse.advance(years: 4, months: 3, weeks: 2, days: 1)

Wed, 05 Apr 2017 14:27:45 +0000

apocalypse.tomorrow

Sat, 22 Dec 2012 14:27:45 +0000

apocalypse.yesterday

Thu, 20 Dec 2012 14:27:45 +0000


ACTIVESUPPORT
CORE EXTENSIONS: HASH
options = {user: 'codeschool', lang: 'fr'}
new_options = {user: 'codeschool', lang: 'fr', password: 'dunno'}

difference between
options.diff(new_options)
two hashes
{:password=>"dunno"}

options.stringify_keys turn keys into strings


{"user"=>"codeschool", "lang"=>"fr"}

ACTIVESUPPORT
CORE EXTENSIONS: HASH
options = { defaults = {
lang: 'fr', lang: 'en',
user: 'codeschool' country: 'us'
} }

options.reverse_merge(defaults)

{
values from lang: 'fr',
user: 'codeschool',
this hash win country: 'us'
}

ACTIVESUPPORT
CORE EXTENSIONS: HASH
new_options = {user: 'codeschool', lang: 'fr', password: 'dunno'}

new_options.except(:password) remove these keys


{:user=>"codeschool", :lang=>"fr"}

new_options.assert_valid_keys(:user, :lang)

Unknown key(s): password (ArgumentError)

throws an exception if the hash contains


any keys besides those listed here
CORE EXTENSIONS: INTEGER
def background_class(index) determine odd and
return 'white' if index.odd?
return 'grey' if index.even? even numbers
end
tweets.each_with_index do |tweet, index|
puts "<div class='#{background_class(index)}'>#{tweet}</div>"
end

<div class='grey'>I had eggs for breakfast.</div>


<div class='white'>@codeschool pwns.</div>
<div class='grey'>Shopping!</div>
<div class='white'>Bedtime.</div>

ACTIVESUPPORT
INFLECTOR
"#{1.ordinalize} place!"

"1st place!"
ordinalize numbers
"#{2.ordinalize} place."
to strings
"2nd place."

"#{23.ordinalize} place."

"23rd place."

ACTIVESUPPORT
INFLECTOR
pluralize and
"user".pluralize
singularize strings
"users"

"women".singularize it knows common special c


ases
"woman"

"octopus".pluralize and even some uncommon ones!


"octopi"

ACTIVESUPPORT
INFLECTOR
"ruby bits".titleize capitalize every word
"Ruby Bits"

"account_options".humanize add spaces and capitalize


"Account options" first word

ACTIVESUPPORT
MODULES
NAMESPACE
IMAG E _ U T ILS.RB

def preview(image)
pollutes global namespace
end

def transfer (image, destination )


potential conflicts with
end methods with same name

R UN. R B
require 'image_utils'

image = user.image
preview(image)
NAMESPACE
IMAG E _ U T ILS.RB
module ImageUtils
def self.preview(image)
end

def self.transfer( image, destination)


end
end

R UN. R B
require 'image_utils'

image = user.image
ImageUtils.preview(image)
MIXIN
IMAG E _ U T ILS.RB
module ImageUtils
def preview
end
can access properties
def transfer( destination) on objects from host class
end
end

A VAT A R . R B
Included as instance methods
require 'image_utils' RUN .RB
class Image
image = user.image
include ImageUtils
image.preview
end
ANCESTORS
class Image
include ImageUtils
Adding module to Images
end ancestors chain

Image.ancestors
[Image, ImageUtils, Object, Kernel, BasicObject]

Image.included_modules
[ImageUtils, Kernel]

modules only
MIXINS VS CLASS INHERITANCE
class Post class Shareable
def share_on_facebook end
end
end

class Image
def share_on_facebook
end
end

class Tweet
def share_on_facebook
end
end
MIXINS VS CLASS INHERITANCE
class Post < Shareable class Shareable
end def share_on_facebook
end
end

class Image < Shareable


end A class can only have one superclass.
Inheritance suggests specialization.
class Tweet < Shareable Some behaviors are not t for classes.
end
MIXINS VS CLASS INHERITANCE
class Post module Shareable
include Shareable def share_on_facebook
end end
end

class Image
include Shareable
end

class Tweet
include Shareable
end
MIXINS VS CLASS INHERITANCE
class Post module Shareable
include Shareable def share_on_facebook
include Favoritable end
end end

class Image
include Shareable module Favoritable
include Favoritable def add_to_delicious
end end
end
class Tweet
include Shareable
include Favoritable
end
MIXIN
class Tweet module Searchable
extend Searchable def find_all_from(user)
end end
end

Included as class methods

Tweet.find_all_from('@GreggPollack')
MIXIN
class Tweet class Image
extend Searchable include ImageUtils
end end

use extend to expose use include to expose


methods as class methods methods as instance methods
image = user.image
Tweet.find_all_from('@GreggPollack') image.preview
MIXIN
class Image
module ImageUtils
end
def preview
end
image = Image.new
end
image.extend(ImageUtils)
image.preview
an object is extending the module

the module will not be available in other objects


image = Image.new
image.preview
NoMethodError: undefined method `preview' for #<Image:0x10b448a98>
HOOKS - SELF.INCLUDED
module ImageUtils class Image
include ImageUtils
def preview extend ImageUtils::ClassMethods
end end

def transfer(destination)
end

module ClassMethods
def fetch_from_twitter(user)
end image = user.image
end image.preview
end
Image.fetch_from_twitter('gregg')
HOOKS - SELF.INCLUDED

module ImageUtils class Image


include ImageUtils
def self.included(base) extend ImageUtils::ClassMethods
base.extend(ClassMethods) end
end

def preview sellf.included is called by Ruby


end
when a module is included in a class
def transfer(destination) image = user.image
end image.preview

module ClassMethods Image.fetch_from_twitter('gregg')


def fetch_from_twitter(user)
end
end in this case, the module
end name can be anything
ACTIVESUPPORT::CONCERN

module ImageUtils class Image


include ImageUtils
def self.included(base)
end
base.extend(ClassMethods)
base.clean_up
end

module ClassMethods
def fetch_from_twitter(user)
end

def clean_up
end
end
end
ACTIVESUPPORT::CONCERN
gem install activesupport
require 'active_support/concern'
class Image
module ImageUtils include ImageUtils
extend ActiveSupport::Concern
end

included do
clean_up } included block is executed in
end the context of the Image class
module ClassMethods
def fetch_from_twitter(user)
end
ActiveSupport::Concern looks
def clean_up
end for a module named ClassMethods
end
end
ACTIVESUPPORT::CONCERN
module ImageUtils class Image
def self.included(base) include ImageUtils
base.extend(ClassMethods) include ImageProcessing
end end
module ClassMethods
def clean_up; end ImageProcessing depends
end
end
on ImageUtils
base is Image class

module ImageProcessing
def self.included(base) calls method on
base.clean_up
end Image class
end
ACTIVESUPPORT::CONCERN
module ImageUtils class Image
def self.included(base) include ImageProcessing
base.extend(ClassMethods)
end
end
module ClassMethods
def clean_up; end
end
end
base is ImageProcessing module
module ImageProcessing

include ImageUtils

def self.included(base)
base.clean_up undefined method error
end
end
ACTIVESUPPORT::CONCERN
module ImageUtils class Image
def self.included(base) include ImageProcessing
base.extend(ClassMethods)
end
end
module ClassMethods
def clean_up; end
end
Dependencies are
end properly resolved
module ImageProcessing base is Image class
extend ActiveSupport::Concern
include ImageUtils
def self.included(base)
base.clean_up
end
end
ACTIVESUPPORT::CONCERN
module ImageUtils class Image
extend ActiveSupport::Concern include ImageProcessing
module ClassMethods end
def clean_up; end
end
end Dependencies are
properly resolved
module ImageProcessing
extend ActiveSupport::Concern
include ImageUtils
included do
clean_up
end
end
MODULES
BLOCKS
USING BLOCKS
words = ['Had', 'eggs', 'for', 'breakfast.']
for index in 0..(words.length - 1)
puts words[index]
end

words = ['Had', 'eggs', 'for', 'breakfast.']


words.each { |word| puts word }

BLOCKS
DECLARING BLOCKS
s i f th e bl oc k
words.each { |word| puts word } br a c e
is a s i n g le li n e

words.each do |word| if i t s
backward_word = word.reverse do/e n d
puts backward_word mul ti p l e l i n e s
end

h e F IR S T
this is t
o c on ve n ti on s !
of tw

BLOCKS
DECLARING BLOCKS
n d if t h e blo c k
words.each do |word| do / e
m e th i n g
puts word
D OES s o )
end
a s i de e f f e c t
( h a s
s i f y ou r e
brace
backward_words = words.map { |word| word.reverse }
i n g t o u s e
just go
u r n v a l ue
D its ret
is th e SE C O N
this
n ve n ti on s !
of two co

BLOCKS
YIELD
def call_this_block_twice
yield
yield
end

twitter
call_this_block_twice { puts "twitter" }
twitter
tweet
call_this_block_twice { puts "tweet" }
tweet

BLOCKS
YIELD - ARGUMENTS
def call_this_block
yield "tweet"
end

call_this_block { |myarg| puts myarg } tweet

call_this_block { |myarg| puts myarg.upcase } TWEET

BLOCKS
YIELD - RETURN VALUE
def puts_this_block
puts yield
end

puts_this_block { "tweet" } tweet

BLOCKS
YIELD
def call_this_block
"foo" "oof"
"oof"
block_result = yield "foo"
puts block_result "oof"
end

call_this_block { |arg| arg.reverse }

BLOCKS
USING BLOCKS
class Timeline a t i o n ,
def list_tweets same ite r
@user.friends.each do |friend| differe n t l og i c
friend.tweets.each { |tweet| puts tweet }
end
end
def store_tweets
@user.friends.each do |friend|
friend.tweets.each { |tweet| tweet.cache }
end
end
end

BLOCKS
YOUR OWN EACH
class Timeline
def each er a ti on
@user.friends.each do |friend|
re-use it
friend.tweets.each { |tweet| yield tweet }
end
end
end vary logic

timeline = Timeline.new(user)
timeline.each { |tweet| puts tweet }
timeline.each { |tweet| tweet.cache }

BLOCKS
ENUMERABLE
e m e n t e d
class Timeline you impl
def each n o w m i x i n
...
each,
end E n umer a bl e
include Enumerable
end

timeline.sort_by { |tweet| tweet.created_at }


timeline.map { |tweet| tweet.status }
timeline.find_all { |tweet| tweet.status =~ /\@codeschool/ }

a ll th es e meth ods , a n d mor e!


you instantly g et

BLOCKS
EXECUTE AROUND
def update_status(user, tweet) def get_list(user, list_name)
begin begin
sign_in(user) sign_in(user)
post(tweet) retrieve_list(list_name)
rescue ConnectionError => e rescue ConnectionError => e
logger.error(e) logger.error(e)
ensure ensure
sign_out(user) sign_out(user)
end end
end end

b ut th e c or e
everyt h i n g
i s d u p l ic a te d!
logi c
BLOCKS
EXECUTE AROUND
def while_signed_in_as(user) while_signed_in_as(user) do
begin post(tweet)
sign_in(user) end
yield
rescue ConnectionError => e
logger.error(e) tweets = while_signed_in_as(user) do
ensure retrieve_list(list_name)
sign_out(user) end
end
end

n j us t c a ll th e
now y ou c a
d w i th a b l oc k !
single me t h o
BLOCKS
EXECUTE AROUND
def while_signed_in_as(user)
sign_in(user)
yield COM BO X2 !
rescue ConnectionError => e
logger.error(e)
ensure
sign_out(user)
end

f or be g i n / en d
no nee d
m eth od!
within a
BLOCKS
BLOCKS

You might also like