Ruby overview
-
System Ruby (apt-get, brew)
- RVM (Ruby Version Manager)
Installation
RVM
- Install
- $ rvm list known
- $ rvm install
- $ rvm use --default ruby-1.9.3
- $ rvm use jruby
- .rvmrc file
IRB (Interactive Ruby)
$ irb
Everything is an Object
No Primitives
> 'c'.upcase
'C'
> "cat".reverse
"tac"
> 12.even?
true
> x.nil?
true
Scripting language
#!/usr/bin/ruby
def foo
bar
end
def bar
...
end
foo
Dynamically typed language
- No type declarations / Duck typing
-
Message passing
"If it looks like a duck and quacks like a duck, it's a duck"
Dynamic typing - Example
parser = CsvParser.new(file)
parser.parse
parser = XlsParser.new(file)
parser.parse
Strings vs Symbols
> ["north", "south", "east", "west"]
> [:north, :south, :east, :west]
> {"a" => 1, "b" => 2}
> {a: 1, b: 2}
> "foo".object_id
> :foo.object_id
Conditionals
if c1
...
elsif c2
...
else
...
end
unless c
...
end
while c
...
end
until c
...
end
Statement modifiers
send_email if subscribed?
show_popup unless subscribed?
wait while queue.empty?
process until queue.empty?
Array
> []
> a = [1, 2, 3]
> a = [:foo, 5, "bar"]
> a << 42
> b = [5, 10, 15]
> b.each {|element| puts element}
> c = ['foo', 'bar', 'baz']
> c.map {|s| s.upcase}
Hash
> h = {"x" => 1, "y" => 2, "z" => 3}
> h = {x: 1, y: 2, z: 3}
> h.keys
> h.values
> h[:x]
> h[:a] = 0
> h.each {|k,v| puts "#{k} = #{v}"}
Printing
> p (short for print)
> puts
> pp (short for pretty print)
Class and Object
class Book def initialize(isbn, title, author) @isbn = isbn @title = title @author = author end def author @author end def author=(name) @author = name end endcatch22 = Book.newcatch22.author = "Joseph"catch22.author
Class and Object
class Book
attr_reader :isbn
attr_writer :title
attr_accessor :author
def self.search(params)
...
end
def contents
end
end
Open classes
class String
def palindrome?
self == reverse
end
end
> "stats".palindrome?
> 10.times do ... end
> 7.days.ago
> 5.days.from_now
Inheritance
class Animal
def make_sound
...
end
end
class Cat < Animal
def make_sound
meow
end
end
class Dog < Animal
def make_sound
bark
end
end
Modules/Mixins
module Printable
def print
end
def self.remove_non_printable_chars(str)
end
end
class Document
include Printable
end
class Book
include Printable
end
include / extend / included hook
module Printable
def self.included(klass)
klass.extend(ClassMethods)
end
def print ... end
module ClassMethods
def print_with(options={})
end
end
end
class Document
include Printable
print_with header: "---", footer: "---"
end
Functional programming - each
> [5,10,15,20,25].each do |num|
puts num * 10
end
> [5,10,15,20,25].each {|num| puts num * 10}
> # for loop is syntactic sugar for each
for num in nums
puts num * 10
end
collect / map
> [5,10,15,20,25].collect do |num|
num / 5
end
[1,2,3,4,5]
> [5,10,15,20,25].map {|num| num / 5}
[1,2,3,4,5]
> [1,4,9,16,25].map(&:sqrt) # convert method to block
[1,2,3,4,5]
select / reject
> [5,10,15,20,25].select {|num| num.even? }
[10, 20]
> [5,10,15,20,25].reject {|num| num.odd? }
[10, 20]
inject / reduce
> (1..100).inject(0) {|sum, num| sum + num} 5050 > (1..100).inject(&:+) 5050 > (1..5).reduce(:*) 120
each_with_index / each_with_object
> [5,10,15].each_with_index do |num, index|
puts "#{index} = #{num}"
end
> ["foo", "bar", "baz"].each_with_object({}) do |s, scores|
scores[s] = s.score
end
{"foo" => 5, "bar" => 12, "baz" => 13}
blocks
class Bookstore
def change_prices(&block)
books.each do |book|
book.price = yield(book.price)
end
end
end
book_store.change_prices do |price|
price * 1.10
end
book_store.change_prices do |price|
price * 0.5
end
yield - before/after/around
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("foo.txt"), "utf-8"));
writer.write("foo");
} catch (IOException ex) {
// report
} finally {
try {writer.close();} catch (Exception ex) {}
}
vs
File.open("foo.txt", 'w') {|f| f.write "foo"}
block, lambdas, proc
# blocks are passes as last arg to a function
> matrix.apply {|num| num * 2}
# lambdas can be stored in vars and passed around as values
> square = lambda {|num| num * num}
> matrix.apply(square)
# procs are similar to lambdas except for return
> cube = Proc.new {|num| num * num * num}
> matrix.apply(cube)
dynamic methods
Book.find_by_author_and_publisher("Joseph", "Penguin")Book.find_by_title_and_publisher("Catch22", "Penguin")
Metaprogramming - define_method
class CreditCard
attr_reader :number, :name, :cvv
[:number, :name, :cvv].each do |attr|
define_method "encrypted_#{attr}" do
#...
end
end
end
> card.encrypted_cvv
> card.encrypted_name
Metaprogramming - send
class CreditCard
def to_json(keys=[:number, :name, :address])
keys.each_with_object({}) do |key, hash|
hash[key] = send("encrypted_#{key}")
end
end
end
Metaprogramming - method_missing
class Book < ActiveRecord::Base
end
class ActiveRecord::Base
def method_missing(method_name, *args, &block)
if method_name.to_s =~ /^find_by_(.+)$/
query($1.split("_and_"), *args, &block)
else
super
end
end
end
Book.find_by_title_and_publisher("Catch22", "Penguin")
DSLs
class Vehicle state_machine :state, :initial => :parked do event :park do transition :first_gear => :parked end event :ignite do transition :parked => :first_gear end event :shift_up do transition :first_gear => :second_gear, :second_gear => :third_gear end end end> car.ignite > car.shift_up
Gems - Libraries
$ gem install rails
$ gem search -ar rails
$ gem list rails
Bundler - dependency management
Gemfile
Gemfile.lock
$ bundle install
$ bundle update
$ bundle gem
Other topics
- Strings
- Regexes
- Testing/Debugging
- Exception handling
- eval, instance_eval, class_eval
References
-
Pragmatic Ruby
-
RubyMonk.com
- Ruby Koans https://github.com/neo/ruby_koans
- Ruby object model and metaprogramming
http://pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming -
APIDock http://apidock.com/ruby
deck
By sathish316
deck
- 247