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['toast'] = 'honeydew'
	=> "honeydew"
Reversing lines of the poem
methods (lines, bytes, chars)
Get lines collections, turn into array, reverse array, join elements
>	poem.lines.to_a.reverse.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.delete! "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.include? "My"
		=>	True
Hash EQUALS Dictionary
Saving and retrieving from a hash, key value pairs, non-ordered,
> books
=> {}
> books["Gravity's Rainbow"] = :splendid
=> :splendid
> books
=> {"Gravity's Rainbow"=>:splendid}
> books["Gravity's Rainbow"]
=> :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.entries "/"
	=> [".", "..", "Home", "Libraries", "MouseHole", "Programs", "Tutorials", "comics.txt"]
	> Dir["/*.txt"]
	=> ["/comics.txt"]
Open file
	> print File.read("/comics.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/comics.txt", "a") do |f|
	.. f << "Cat and girl: http://catandgirl.com"
	.. end
	=> #<File:/Home/comics.txt (closed)>
Last changed on
	> File.mtime("/Home/comics.txt")
	=> 2015-09-12 06:42:23 UTC
	> File.mtime("/Home/comics.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.foreach(path) do |line|
	.... name, url = line.split(': ')
	.... comics[name] = url.strip
	.... 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.com"
Making links using popup
Links
	> Popup.make{
	.. h1 "My Links"
	.. link "Go to Bing", "http://bing.com"
	.. }
Todo
	> Popup.make do
	.. h1 "Thing To Do"
	.. list do
	.... p "Try out Ruby"
	.... p "Ride a tiger"
	.... p "(down River Euphrates"
	.... end
	.. end
Generate links from comics file
	> Popup.make do
	.. h1 "Comics on the Web"
	> list do
	.... comics.each do |name, url|
	...... link name, url
	...... end
	.... end
	.. end
	> def show()
	.. Popup.make do
	.... h1 "Comics on the Web"
	.... list do
	...... comics.each 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