Showing posts with label Ruby. Show all posts
Showing posts with label Ruby. Show all posts

Sunday, November 16, 2008

|| and && operators may not be doing what you expect

When you use || and &&, you may think that you are playing with true/false values. For instance, a condition that uses || or && will give you back true or false.

I found out recently that this is sometimes true (and sometimes not)! Now, what am I talking about? I always thought that if you evaluate (true || true), the expression evaluates to true because at least one of them is true. Well, apparently, it does evaluate to true, but not for the reason I had thought.

In Ruby, when you evaluate (true || true), what it is actually doing is evaluating the first condition. If it is truthy (ie. not false or nil) you get the first condition back. If it is falsy (ie. false or nil), you get the second condition back. So the following occurs:

('blah' || true) #=> 'blah' - not true!
(false || 'blah') #=> 'blah' again!

For &&, if the first condition is falsy, you get the first condition back. If it is truthy, you get the second condition back. Check it out:

(true && 'blah') #=> 'blah'
(nil && true) #=> nil - not false!

Using || and && still work in 'if' statements as expected, but it doesn't work the way as first thought. With this new insight, you can use || and && for shortcuts.

Instead of:

if options[:product].nil?
product = Product.new
else
product = options[:product]
end

You could do:

product = options[:product] || Product.new

And instead of:

unless product.nil?
name = product.name
end

You coud do:

name = product && product.name

Obviously, use these shorthands with caution, as it can convolute readability for other readers. On another note, JavaScript also follows this evaluation. Have fun!


W

Saturday, October 18, 2008

Ruby: Time made easy

Here's another example of how Ruby just makes things simple. Imagine you're working with time and you have to figure out the difference between 2 times and whether they fall within a certain range. In most languages, you have to figure out how many seconds exist in your time range. For example, 1 minute would have 60 seconds and 1 day would have 86,400 seconds. That's not too hard to figure out, but imagine the readability!

t2 - t1 < 86400

That just begs the question, "Where does 86400 come from?". Imagine you had to explicitly put down the number for 1 week?

Well, Ruby is awesome in that it concentrates on readability. Since everything in Ruby is an object, numbers are just Fixnum (or Bignum). Either way, that means we can use certain methods associated with the object. Check this out:

t2 - t1 < 1.second
t2 - t1 < 1.minute
t2 - t1 < 1.hour
t2 - t1 < 1.day
t2 - t1 < 1.week
t2 - t1 < 1.month
t2 - t1 < 1.year

Now how readable is that?


W

Tuesday, September 30, 2008

initialize + super

Here's a word of caution to those using inheritance and calling super in the initialize method. Consider this:

def initialize(name, price)
super
@name = name
@price = price
end

Which parent method does it call? I was surprised to find out that without () after super, it automatically calls the initialize in the parent that has the parameters (name, price), rather than the one without parameters. If your intention was to call the parent's initialize without parameters, than you must do:

super()


W

Tuesday, September 23, 2008

Stack and Queue Implementation

Array in Ruby already has built in push and pop function you can use, but if you want to make it more strict and idiot proof, here's how you can implement it.

class Stack

def initialize
@stack = []
end

def push(x)
@stack.push(x)
end

def pop
@stack.pop unless is_empty?
end

def peek
@stack.last
end

def is_empty?
@stack.empty?
end

end

class Queue

def initialize
@queue = []
end

def enqueue(x)
@queue << x
end

def dequeue(x)
@queue.shift
end

def peek
@queue.first
end

def is_empty?
@queue.empty?
end

end


J

Fun with String

This is why Ruby is amazing :D

1. converting strings to numbers

"123".to_i => 123
Duh, everyone knows that

but how bout
"123stfu".to_i => 123

or

" 123stfu ".to_i => 123

you can even indicate the base of your conversion

"111".to_i(2) => 7 # treat it as a binary number
"111".to_i(8) => 73 # treat it as an octal

split a string and convert it to an interger

"123 456 789".split.map {|m| m.to_i} => [123, 456, 789]

2. Replacing text

we can implement the lame rot13 encryption scheme in one line :)

class String; def rot13; self.tr("A-Ma-mN-Zn-z", "N-Zn-zA-Ma-m");end;end

"Please hide this line".rot13 => "Cyrnfr uvqr guvf yvar"

3. Counting Characters

s1 = "abcabcabcde"
s1.count("c") => 3
s1.count("abc") => 9
s1.count(s1) => 11

count can handle negation

s1.count("^abc") => 2
s1.count("^a") => 8

and range of chars

s1.count("a-c") => 9
s1.count("^a-z") => 0

4. Reversing a String

Microsoft loves to ask interviewee to reverse the word order of a String during an interview, it takes around 15 - 20 lines to implement the function in Java or C++, but we can do it in one :)

phrase = "This is a joke"
phrase.split.reverse.join(" ") => "joke a is This"

so next time you goto an interview, asks if they'll let you do it in Ruby ;)

5. Removing Duplicate Characters

string = "aaaaaaaaaaaaaaaaaaa".squeeze => "a"
string = "aaaaaaaaaaaaaaaaaaB".squeeze => "aB"
string = "hehe....".squeeze(".") => "hehe."


J

List of reflective methods

I find the following commands very useful from time to time, but I kept forgetting their names. So I'm creating this post to help remind myself.

a.class
# returns the class of an object a

a.superclass
# returns the superclass of an object a

a.instance_of? A
# determines if a.class == A

a.is_a? A
#determines whether a is an instance of c, or of any of its subclass, or of any modules.

a.respond_to? :something
#determines if a has a public or protected method with the specified name.


J

Monday, September 22, 2008

Duck Typing and Type Checking

Consider the following example:

class A
attr_accessor :x

def initialize
@x = 0
end

def +(other)
a = A.new
a.x = @x + other.x
return a
end
end

class B
attr_accessor :x

def initialize
@x = 0
end
end

a = A.new
a.x = 10
b = B.new
b.x = 5
puts (a+b).x # this will return 15

Ruby is a very dynamic language, the addition function doesn't care if the argument passed in is of type A, as long as it looks and behaves like A. This is called duck typing, name after the phase "if it walks like a duck and quacks like a duck, it must be a duck!"

if you want to ensure the object passed into the + function has to have an x accessor, you can add this to def +(other)

raise "error" unless other.respond_to? :x

or if you want to ensure object passed into the + function has to be of class A, you can add this instead:

raise "error" unless other.is_a? A


J

Instance Variable

Java and C++ programmers are used to declaring their variables in a class, and they think they should do the same in Ruby. WRONG!

For example:

class Animal
@age = 0
@name = ""

def initialize(age, name)
@age = age
@name = name
end
end

In this example, two sets of @age, @name are created. When the initialize method is called, self holds an instance of the Animal class. But the code outside of that function are executed as part of the definition of the Animal class. When @age and @name are executed, it refers to the Animal class, not the object instance. Hence @age, @name inside the initialize function are different from the @age, @name on the outside.


J

Sunday, September 21, 2008

Variable Parameters

Sometimes we want a method that can take any number of parameters.
One way to do it is to pass in a hash, but this can be annoying. Another method is to put an * before the method's parameter. Within the body of the method, list will be treated as an array with 0 or more elements.

For example:

def average(*list)
x = 0
list.each {|l| x+= l}
l/list.size
end

irb>average 1,2,3,4,5,6,7,8,9
=> 5

J

Copying Objects

When you use =, clone, or dup to copy an object, only the object reference is copied,
not the referenced object itself (Shallow Copy).

In order to do a deep object copy, we can use the marshaling trick by dumping and
loading the object.

For example:

def deepcopy(something)
Marshal.load(Marshal.dump(something))
end

irb>b = "abcd"
=> "abcd"
irb>a = b
=> "abcd"
irb>a.upcase!
=>"ABCD"
irb>b
=>"ABCD" # see how b changes too
irb>b = deepcopy(a)
=>"ABCD"
irb>b.downcase!
=>"abcd"
irb>a
=>"ABCD" # a stayed the same this time

J

Saturday, September 20, 2008

More on enumerable

In ruby, I use .each alot to visit every elements in the array.
Did you know there's a .step(x) function that allows you to visit
every x th element in the array?

For example:

r = 0..3
r.each {|l| prints l.to_s + ' ' } # Prints 0 1 2 3

r.step(2) {|l| prints l.to_s + ' '} # Prints 0 2


J

Thousands Seperator

In ruby, underscore can be inserted into integer literals as thousands separator.

For example:

1_000 will be interpreted as 1000
1_000 + 1_000 will equal 2000
1_000_000_000 will be interpreted as 1 billion

the same technique works for float number as well

For example:

1_000.1 will be interpreted as 1000.1


J