Ruby

Basics

Playing with strings

	> "Jimmy".reverse
	=> ymmiJ

	> "Jimmy".length
	=> 5

	> "Jimmy" * 5
	=> "JimmyJimmyJimmyJimmyJimmy"

	> 40.to_s.reverse
	=> "04"

Useful functions

  • strings: to_s
  • integers: to_i
  • arrays: to_a

Arrays

	> [12, 45, 12].max
	=> 45
	ticket  = [12, 45, 12]
	ticket.sort!

Printing

	print poem
	=> "My toast has flown from my hand
	And my toast has gone to the moon.
	But when I saw it on television,
	Planting our flag on Halley's comet,
	More still did I want to eat it."


	> poem['toas­t'] = 'hone­ydew'
	=> "honeydew"
Reversing lines of the poem

methods (lines, bytes, chars)

Get lines collections, turn into array, reverse array, join elements

>	poem.lines­.to_a.reve­rse.join
	"More still did I want to eat it.\
	Planting our flag on Halley's comet,\
	But when I saw it on television,\
	And my toast has gone to the moon.\
	My honeydew has flown from my hand\
	"

String manipulation

Find all string methods here

  • Exclamation Points.
    Methods may have exclamation points in their name, which just means to impact the current data, rather than making a copy. No big deal.
	poem.delet­e! "My"

Square Brackets.
With these, you can target and find things. You can even replace them if necessary.

Chaining methods
lets you get a lot more done in a single command. Break up a poem, reverse it, reassemble it: poem.lines.to_a.reverse.join

	>	poem.inclu­de? "My"
		=>	True

Hash EQUALS Dictionary

Saving and retrieving from a hash, key value pairs, non-ordered,

> books
=> {}
> books["Gra­vity's Rainb­ow"] = :splendid
=> :splendid

> books
=> {"Gravity's Rainbow"=>:splendid}
> books["Gra­vity's Rainb­ow"]
=> :splendid

> books.keys­
=> ["Gravity's Rainbow"]

New hash with all new ratings set to zero

> ratings = Hash.­new(0)
=> {}

Count your reviews

return all unique values in books.. into keys within the new ratings hash

	> books.values.each { |rate| ratings[rate] += 1 }
	=> [:splendid]
	> ratings
	=> {:splendid=>1}

Blocks

	> 5.times {print "Odelay!"}
	=> "OdelayOdelayOdelayOdelayOdelay"

Review

Hashes.
The little 'dictionary' with the curly braces: {}.

Symbols.
Tiny, efficiently reusable code words with a colon: :splendid

Blocks.
Chunks of code which can be tacked on to many of Ruby's methods. Here's the code you used to build a scorecard:

	> books.values.each { |rate| ratings[rate] += 1 }

Directories

Checking files in a directory, and using wildcards

	> Dir.entrie­s "/"
	=> [".", "..", "Home", "Libraries", "MouseHole", "Programs", "Tutorials", "comics.txt"]

	> Dir["/*.tx­t"]
	=> ["/comics.txt"]

Open file

	> print File.­read("/com­ics.txt")
	=> "Achewood: http://achewood.com/
	Dinosaur Comics: http://qwantz.com/
	Perry Bible Fellowship: http://cheston.com/pbf/archive.html
	Get Your War On: http://mnftiu.cc/
	"

Copying a file

	FileUtils.cp('/comics.txt', '/Home/comics.txt')

Append mode

	> File.open(­"/Home/com­ics.txt", "a") do |f|
	.. f << "Cat and girl:­ http:­//catandgi­rl.com"
	.. end
	=> #<File:/Home/comics.txt (closed)>

Last changed on

	> File.mtime­("/Home/co­mics.txt")­
	=> 2015-09-12 06:42:23 UTC
	> File.mtime­("/Home/co­mics.txt")­.hour
	=> 6

Review

  • Files.

Lots of methods exist for editing files and looking around in directories.

  • Arguments.

Arguments are a list of things sent into a method, separated by commas.

  • Block Changes.

You can use do and end as another way to make a code block.

Methods

	> def load_­comics (path­)
	.. comics = {}
	.. File.forea­ch(path) do |line­|
	.... name, url = line.­split(': ')
	.... comics[nam­e] = url.s­trip
	.... end
	.. comics
	.. end
	=> nil	

Use it

	comics = load_comics('/comics.txt').
  • File.foreach

This method opens a file and hands each line of the file to the block. The line variable inside the do...end block took turns with each line in the file.

  • split

A method for strings which breaks the string up into an array, removing the piece you pass in. An axe is laid on the colon and the line is chopped in half, giving us the data to be stored in url and name for each comic.

  • strip

This quick method removes extra spaces around the url. Just in case.

Require

	> require 'popup'
	> Popup.goto­ "http­://bing.co­m"

Links

	> Popup.make­{
	.. h1 "My Links­"
	.. link "Go to Bing"­, "http­://bing.co­m"
	.. }

Todo

	> Popup.make­ do
	.. h1 "Thin­g To Do"
	.. list do
	.... p "Try out Ruby"­
	.... p "Ride­ a tiger­"
	.... p "(dow­n River­ Euphr­ates"
	.... end
	.. end

Generate links from comics file

	> Popup.make­ do
	.. h1 "Comi­cs on the Web"
	> list do
	.... comics.eac­h do |name­, url|
	...... link name,­ url
	...... end
	.... end
	.. end
	> def show(­)
	.. Popup.make­ do
	.... h1 "Comi­cs on the Web"
	.... list do
	...... comics.eac­h do |name­, url|
	........ link name,­ url
	........ end
	...... end
	.... end
	.. end
	> show()

CODING EXPRESSIONS

UNLESS

BAD CODE

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

AWESOME CODE

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

BAD CODE

	unless tweets.empty?
		puts "Timeline":
		puts tweets
	else
		put "No tweets"
	end

AWESOME CODE

	if tweets.empty?
		put "No tweets"
	else
		puts "Timeline":
		puts tweets
	end

NIL IS FALSE-Y

BAD CODE

	if attachment.file_path !=nil
		attachment.post
	end

AWESOME CODE

	if attachment.file_path
		attachment.post
	end

ONLY NIL IS FALSE-Y

- "" is `true`
- 0 is `true`
- [] is `true`

WORSE CODE

	# Never evaluated
	unless name.length
		warn "required!"
	end

INLINE CONDITIONALS

BAD CODE

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

GOOD CODE

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

SHORT-CIRCUIT "AND"

BAD CODE

	if user
		if user.signed_in?
			#...
		end
	end

GOOD CODE

	#if user is null, second part never runs
	if user && user.signed_in?
		#...
	end

SHORT-CIRCUIT ASSIGNMENT

result equals 1 in all cases

	result = nil || 1
	result = 1 || nil
	result = 1 || 2

DEFAULT VALUES - "OR"

BAD CODE

	tweets = timeline.tweets
	tweets = [] unless tweets

GOOD CODE

	# if nill, default to empty array
	tweets = timeline || []

SHORT CIRCUIT EVALUATION

Second function not evaluated unless current session is nill

	def sign_in
		current_session || sign_user_in
	end

If then could be more readable

CONDITIONAL ASSIGNMENT

Use to set defauls if no existing value

	i_was_set = 1
	i_was_set ||= 2

	puts i_was_set
	> 1

	i_was_not_set ||= 2
	puts i_was_not_set
	> 2

CONDITIONAL ASSIGNMENT

Set defaults if nil
BAD CODE

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

GOOD CODE

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

CONDITIONAL RETURN VALUES

BAD CODE

	if list_name
		options[:path] = "/#{username}/#{list_name}"
	else
		options[:path] = "/#{user_name}"
	end

Assing the value of the if statement

GOOD CODE

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

REFACTORING

BAD CODE

	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

GOOD CODE

	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

CASE STATEMENT VALUE

	client_url = case client_name
		when "web"
			"http://twitter.com"
		when "Facebook"
			"http://facebook.com/twitter"
		else
			nil
	end

CASE - RANGES

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

CASE - REGEXPS

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

equivalent form (more readable)

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

Challenge 1


# using unlesss

	games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
	unless games.empty?
	  puts "Games in your vast collection: #{games.count}"
	end

# inline unless

games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
puts "Games in your vast collection: #{games.count}" unless games.empty?


# nil is false-y

search = "Contra"
games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
search_index = games.find_index(search)
if search_index
  puts "Game #{search} Found: #{games[search_index]} at index #{search_index}."
else
  puts "Game #{search} not found."
end

# short circuit conditional AND

search = "Super Mario Bros."
games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
matched_games = games.grep(Regexp.new(search))

# Found an exact match
if matched_games.length > 0 && matched_games.include?(search)
    puts "Game #{search} found."
end


# conditionaal assignment

## REPLACE: search = "" unless search
## WITH:
search ||= ""

games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
matched_games = games.grep(Regexp.new(search))
puts "Found the following games..."
matched_games.each do |game|
  puts "- #{game}"
end

# setting search result only once

search = "Contra"
games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
search_index = games.find_index(search)

search_result = if search_index
  "Game #{search} found: #{games[search_index]} at index #{search_index}."
else
  "Game #{search} not found."
end

puts search_result


# remove search variable altogether

def search(games, search_term)
  search_index = games.find_index(search_term)
  if search_index
    "Game #{search_term} found: #{games[search_index]} at index #{search_index}."
  else
    "Game #{search_term} not found."
  end
end

games = ["Super Mario Bros.", "Contra", "Metroid", "Mega Man 2"]
puts search(games, "Contra")



# reduce method below to one line 

def search_index(games, search_term)
  search_index = games.find_index(search_term)
  if search_index
    search_index
  else
    "Not Found"
  end
end


def search_index(games, search_term)
  games.find_index(search_term) || "Not found"
end