Saturday, October 15, 2011

Checking for pallindrome in ruby

Non-recursive
def is_palindrome(s)
s == s.reverse
end
Recursive
def is_palindrome_r(s)
if s.length <= 1
true
elsif s[0] != s[-1]
false
else
is_palindrome_r(s[1..-2])
end
end
Testing Note that the recursive method is much slower -- using the 2151 character palindrome by Dan Hoey here, we have:
str = "A man, a plan, a caret, [...2110 chars deleted...] a canal--Panama.".downcase.delete('^a-z')
puts is_palindrome(str) # => true
puts is_palindrome_r(str) # => true
 
require 'benchmark'
Benchmark.bm do |b|
b.report('iterative') {10000.times {is_palindrome(str)}}
b.report('recursive') {10000.times {is_palindrome_r(str)}}
end
output
true
true
user system total real
iterative 0.062000 0.000000 0.062000 ( 0.055000)
recursive 16.516000 0.000000 16.516000 ( 16.562000)

Converting between values and char

// character to ASCII value: use ?
?a     # => 97
?\n # => 10


// string to integer: use []
'a'[0]        # => 97
'hallo'[1] # => 97


// integer / number to character: use .chr
97.chr     # => "a"
10.chr # => "\n"

Friday, October 14, 2011

Ruby from perspective of other programming languages

  • Don't confuse object attributes and local variables. If you are accustomed to C++ or Java, you might forget this. The variable @my_var is an instance variable (or attribute) in the context of whatever class you are coding, but my_var, used in the same circumstance, is only a local variable within that context.
  • Many languages have some kind of for loop, as does Ruby. The question sooner or later arises as to whether the index variable can be modified. Some languages do not allow the control variable to be modified at all (printing a warning or error either at compile time or runtime), and some will cheerfully allow the loop behavior to be altered in midstream by such a change. Ruby takes yet a third approach. When a variable is used as a for loop control variable, it is an ordinary variable and can be modified at will; however, such a modification does not affect the loop behavior! The for loop sequentially assigns the values to the variable on each iteration without regard for what may have happened to that variable inside the loop. For example, this loop will execute exactly 10 times and print the values 1 through 10:
    for var in 1..10
    puts "var = #{var}"
    if var > 5
    var = var + 2
    end
    end
  • Variable names and method names are not always distinguishable "by eye" in the immediate context. How does the parser decide whether an identifier is a variable or a method? The rule is that if the parser sees the identifier being assigned a value prior to its being used, it will be considered a variable; otherwise, it is considered to be a method name. (Note also that the assignment does not have to be executed but only seen by the interpreter.)
  • ARGV[0] is truly the first of the command-line parameters, numbering naturally from zero; it is not the file or script name preceding the parameters, like argv[0] in C.

Also the difference lines w.r.t operators and primary types

Primary types in Ruby

Character
A character in Ruby truly is an integer. It is not a type of its own, as in Pascal, and is not the same as a string of length 1. This is slated to change in ruby1.9 so that a character constant will be much the same as a string. As of the time of this writing, this has not happened yet. Consider the following code fragment:
>> a = "0123"
=> "0123"
>> a[0]
=> 48

But in ruby 1.9, output will be 0 rather than 48. But in case of older versions, you can do following to get char rather than integer or its ascii values:
Conver to character
a[0].chr

Or Try a[0,1] instead of a[0].

Boolean
There is no Boolean type such as many languages have. TRueClass and FalseClass are distinct classes, and their only instantiations are TRue and false.
Some may be used to thinking that a false value may be represented as a zero, a null string, a null character, or various other things. But in Ruby, all of these are true; in fact, everything is true except false and nil.

Comparison of operators with c or other languages

  • Many of Ruby's operators are similar or identical to those in C. Two notable exceptions are the increment and decrement operators (++ and --). These are not available in Ruby, neither in "pre" nor "post" forms.
  • The modulus operator is known to work somewhat differently in different languages with respect to negative numbers. The two sides of this argument are beyond the scope of this book; Ruby's behavior is as follows:
    puts (5 % 3)    # Prints 2
    puts (-5 % 3) # Prints 1
    puts (5 % -3) # Prints -1
    puts (-5 % -3) # Prints -2
  • Most of Ruby's operators are really methods; the "punctuation" form of these methods is provided for familiarity and convenience. The first exception is the set of reflexive assignment operators (+=, -=, *=, and so on); the second exception is the following set: = .. ... ! not && and || or != !~.
  • Like most (though not all) modern languages, Boolean operations are always short-circuited; that is, the evaluation of a Boolean expression stops as soon as its truth value is known. In a sequence of or operations, the first true will stop evaluation; in a string of and operations, the first false will stop evaluation.
  • The simpler Fixnum type is passed as an immediate value and thus may not be changed from within methods. The same is true for true, false, and nil.
  • Do not confuse the && and || operators with the & and | operators. These are used as in C; the former are for Boolean operations, and the latter are for arithmetic or bitwise operations.
  • The and-or operators have lower precedence than the &&-|| operators. See the following code fragment:
    a = true
    b = false
    c = true
    d = true
    a1 = a && b or c && d # &&'s are done first
    a2 = a && (b or c) && d # or is done first
    puts a1 # Prints false
    puts a2 # Prints true
  • Additionally, be aware that the assignment "operator" has a higher precedence than the and and or operators! (This is also true for the reflexive assignment operators +=, -=, and the others.) For example, in the following code x = y or z looks like a normal assignment statement, but it is really a freestanding expression (equivalent to (x=y) or z, in fact). The third section shows a real assignment statement x = (y or z), which may be what the programmer really intended.
    y = false
    z = true

    x = y or z # = is done BEFORE or!
    puts x # Prints false

    (x = y) or z # Line 5: Same as previous
    puts x # Prints false

    x = (y or z) # or is done first
    puts x # Prints true
  • Some operators can't be overloaded because they are built into the language rather than implemented as methods. These are: = .. ... and or not && || ! != !~. Additionally, the reflexive assignment operators (+=, -=, and so on) cannot be overloaded. These are not methods, and it can be argued they are not true operators either.
  • There is never any assignment with the scope operator; for example, the assignment Math::PI = 3.2 is illegal.

Things to remember for ruby

The Ruby parser is complex and relatively forgiving. It tries to make sense out of what it finds instead of forcing the programmer into slavishly following a set of rules. However, this behavior may take some getting used to. Here is a list of things to know about Ruby syntax:
  • Parentheses are usually optional with a method call. These calls are all valid:
    foobar
    foobar()
    foobar(a,b,c)
    foobar a, b, c
  • Given that parentheses are optional, what does x y z mean, if anything? As it turns out, this means, "Invoke method y, passing z as a parameter, and pass the result as a parameter to method x." In short, the statement x(y(z)) means the same thing.
  • Let's try to pass a hash to a method:
    my_method {a=>1, b=>2}
    This results in a syntax error, because the left brace is seen as the start of a block. In this instance, parentheses are necessary:
    my_method({a=>1, b=>2})
  • Now let's suppose that the hash is the only parameter (or the last parameter) to a method. Ruby forgivingly lets us omit the braces:
    my_method(a=>1, b=>2)
    Some people might think that this looks like a method invocation with named parameters. Really it isn't, though it could be used as such.
  • There are other cases in which blank spaces are semi-significant. For example, these four expressions may all seem to mean the same:
    x = y + z
    x = y+z
    x = y+ z
    x = y +z
    And in fact, the first three do mean the same. However, in the fourth case, the parser thinks that y is a method call and +z is a parameter passed to it! It will then give an error message for that line if there is no method named y. The moral is to use blank spaces in a reasonable way.
  • Similarly, x = y*z is a multiplication of y and z, whereas x = y *z is an invocation of method y, passing an expansion of array z as a parameter.
  • In constructing identifiers, the underscore is considered to be lowercase. Thus an identifier may start with an underscore, but it will not be a constant even if the next letter is uppercase.
  • In linear nested-if statements, the keyword elsif is used rather than else if or elif as in some languages.
  • Keywords in Ruby are not really reserved words. When a method is called with a receiver (or in other cases where there is no ambiguity), a keyword may be used as a method name. Do this with caution, remembering that programs should be readable by humans.
  • The keyword then is optional (in if and case statements). Those who want to use it for readability may do so. The same is true for do in while and until loops.
  • The question mark and exclamation point are not really part of the identifier that they modify but should be considered suffixes. Thus we see that although, for example, chop and chop! are considered different identifiers, it is not permissible to use these characters in any other position in the word. Likewise, we use defined? in Ruby, but defined is the keyword.
  • Inside a string, the pound sign (#) is used to signal expressions to be evaluated. That means that in some circumstances, when a pound sign occurs in a string, it has to be escaped with a backslash, but this is only when the next character is a { (left brace), $ (dollar sign), or @ (at sign).
  • Because of the fact that the question mark may be appended to an identifier, care should be taken with spacing around the ternary operator. For example, suppose we have a variable my_flag, which stores either TRue or false. Then the first line of code shown here will be correct, but the second will give a syntax error:
    x = my_flag ? 23 : 45   # OK
    x = my_flag? 23 : 45 # Syntax error
  • The ending marker =end for embedded documentation should not be considered a token. It marks the entire line and thus any characters on the rest of that line are not considered part of the program text but belong to the embedded document.
  • There are no arbitrary blocks in Ruby; that is, you can't start a block whenever you feel like it as in C. Blocks are allowed only where they are neededfor example, attached to an iterator. The exception is the begin-end block, which can be used basically anywhere.
  • Remember that the keywords BEGIN and END are completely different from the begin and end keywords.
  • When strings bump together (static concatenation), the concatenation is of a lower precedence than a method call. For example:
    str = "First " 'second'.center(20)     # Examples 1 and 2
    str = "First " + 'second'.center(20) # are the same.
    str = "First second".center(20) # Examples 3 and 4
    str = ("First " + 'second').center(20) # are the same.
  • Ruby has several pseudovariables, which look like local variables but really serve specialized purposes. These are self, nil, true, false, __FILE__, and __LINE__.

Thursday, October 13, 2011

Methods and attributes

As we've seen, methods are typically used with simple class instances and variables by separating the receiver from the method with a period (receiver.method). In the case of method names that are punctuation, the period is omitted. Methods can take arguments:
Time.mktime(2000, "Aug", 24, 16, 0)

Because every expression returns a value, method calls may typically be chained or stacked:
3.succ.to_s
/(x.z).*?(x.z).*?/.match("x1z_1a3_x2z_1b3_").to_a[1..3]
3+2.succ

Note that there can be problems if the cumulative expression is of a type that does not support that particular method. Specifically, some methods return nil under certain conditions, and this usually causes any methods tacked onto that result to fail. (Of course, nil is an object in its own right, but it will not have all the same methods that, for example, an array would have.)

Certain methods may have blocks passed to them. This is true of all iterators, whether built-in or user-defined. A block is usually passed as a do-end block or a brace-delimited block; it is not treated like the other parameters preceding it, if any. See especially the File.open example:
my_array.each do |x|
some_action
end

File.open(filename) { |f| some_action }

Named parameters will be supported in a later Ruby version like 1.9. These are called keyword arguments in the Python realm; the concept dates back at least as far as the Ada language. See here for named parameters.

Methods may take a variable number of arguments:
receiver.method(arg1, *more_args)

In this case, the method called treats more_args as an array that it deals with as it would any other array. In fact, an asterisk in the list of formal parameters (on the last or only parameter) can likewise "collapse" a sequence of actual parameters into an array:
def mymethod(a, b, *c)
print a, b
c.each do |x| print x end
end

mymethod(1,2,3,4,5,6,7)

# a=1, b=2, c=[3,4,5,6,7]

Ruby has the capability to define methods on a per-object basis (rather than per-class). Such methods are called singletons; they belong solely to that object and have no effect on its class or superclasses. As an example, this might be useful in programming a GUI; you can define a button action for a widget by defining a singleton method for the button object.
Here is an example of defining a singleton method on a string object:
str = "Hello, world!"
str2 = "Goodbye!"

def str.spell
self.split(/./).join("-")
end

str.spell # "H-e-l-l-o-,- -w-o-r-l-d-!"
str2.spell # error!

Be aware that the method is defined on the object, not the variable.
It is theoretically possible to create a prototype-based object system using singleton methods. This is a less traditional form of OOP without classes. The basic structuring mechanism is to construct a new object using an existing object as a delegate; the new object is exactly like the old object except for things that are overridden. This enables you to build prototype/delegation-based systems rather than inheritance based, and, although we do not have experience in this area, we do feel that this demonstrates the power of Ruby.