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.

Named parameters in ruby

Ever forget whether the name or email parameter is first on a method like this?

signup(name,email)

Named parameters can help out so that you don't have to remember the order of parameters. As a fringe benefit the code can read a bit nicer and you can add in new optional parameters without breaking existing code.

Ruby as a language doesn't support named parameters to functions. But it does support converting named pairs into a hash if you provide an argument for it.


def signup(params)
name=params[:name]
email=params[:email]
...
end

This takes a little more work on the function declaration but it's not too bad. Now we can call the function like this:

signup(:name=>'Me', :email=>'me@net.com')

Suppose you wanted your name parameter to be optional and default to the email parameter. You can easily set default values for one or more of your expected parameters:

def signup(params)
email=params[:email]
name=params[:name]||email
...
end


With named parameters it often behooves you to do a bit more parameter checking.

def signup(params)
email=params[:email] || raise("email parameter is required!")
name=params[:name]||email
...
end

To make all parameters optional, set a default value for your parameter to {}.

def optional(params={})

Creating Classes

Ruby has numerous built-in classes, and additional classes may be defined in a Ruby program. To define a new class, the following construct is used:
class ClassName
# ...
end

The name of the class is itself a global constant and thus must begin with an uppercase letter. The class definition can contain class constants, class variables, class methods, instance variables, and instance methods. Class data are available to all objects of the class, whereas instance data are available only to the one object.
By the way: Classes in Ruby do not strictly speaking have names. The "name" of a class is only a constant that is a reference to an object of type Class (since in Ruby, Class is a class). There can certainly be more than one constant referring to a class, and these can be assigned to variables just as we can with any other object (since in Ruby, Class is an object). If all this confuses you, don't worry about it. For the sake of convenience, the novice can think of a Ruby class name as being like a C++ class name.

We have already learned how to define functions in ruby. Now lets make a complete greeter class to handle greetings:
class Greeter
#initialize
def initialize(name = "world")
@name=name
end

def sayHi
puts "Hello #{@name}"
end

def sayBye
puts "Bye #{@name}"
end
end
The new keyword here is class. This defines a new class called Greeter and a bunch of methods for that class. Also notice @name. This is an instance variable, and is available to all the methods of the class. As you can see it’s used by say_hi and say_bye.

Creating the object:
g=Greeter.new("k2")
g.sayHi
g.sayBye

Instance variables in Class
Instance variables are hidden away inside the object. They’re not terribly hidden, you see them whenever you inspect the object, and there are other ways of accessing them, but Ruby uses the good object-oriented approach of keeping data sort-of hidden away.

puts Greeter.instance_methods

Output:
"method", "send", "object_id", "singleton_methods",
"__send__", "equal?", "taint", "frozen?",
"instance_variable_get", "kind_of?", "to_a",
"instance_eval", "type", "protected_methods", "extend",
"eql?", "display", "instance_variable_set", "hash",
"is_a?", "to_s", "class", "tainted?", "private_methods",
"untaint", "say_hi", "id", "inspect", "==", "===",
"clone", "public_methods", "respond_to?", "freeze",
"say_bye", "__id__", "=~", "methods", "nil?", "dup",
"instance_variables", "instance_of?"

Whoa. That’s a lot of methods. We only defined two methods. What’s going on here? Well this is all of the methods for Greeter objects, a complete list, including ones defined by ancestor classes. If we want to just list methods defined for Greeter we can tell it to not include ancestors by passing it the parameter false, meaning we don’t want methods defined by ancestors.

Greeter.instance_methods(false)

Output this time is:
"say_bye", "say_hi"

Class level variables in ruby
Getters and setters in ruby
Self in ruby


self: Referencing to the current receiver

 Within the instance methods of a class, the pseudovariable self can be used as needed. This is only a reference to the current receiver, the object on which the instance method is invoked.

eg.
class Book
def self.title
true
end

def title
true
end
end

self refers to the object depends on its context. self.title in the above example will be invoked by the (current) object, Book. While title will be invoked by the object, Book.new. Therefore, to determine the value of self, you need to think around where the self resides.

There are only 2 things that change what self points to: There are only 2 things that change what self points to:
  1. Explicit receiver of method call
    puts self #self is "main", the top-level object instance
    Object.new #self is temporarily changed to the class Object,
    but then back to main

  2. class/module definition
    puts self #Again, self is "main"
    class Foo
    puts self #self is now Foo
    end
    #self is back to being main
Source:Paul Berry

So to define a method as a class method, prefix the method name with the self keyword. The scope of self varies depending on the context. Inside an instance method, self resolves to the receiver object. Outside an instance method, but inside a class definition, self resolves to the class.

Now consider this example:
class SelfStudy
attr_accessor :name

def self
@name
end

def self.name
@name
end

def self.name=(name)
@name = name
end

def self.default_name
self.name = "ClassName"
end

def default_name
self.name = "InstanceName"
end
end


Now playing with this class:
puts SelfStudy.name
#=> nil
puts SelfStudy.default_name
#=> ClassName

me = SelfStudy.new
puts me.name
#=> nil
puts me.default_name
#=> InstanceName

puts SelfStudy.name
#=> ClassName
puts SelfStudy.default_name
#=> ClassName

Please note the I just want to play up with self in the above example. So instead of defining @name in self method. As you should already know, you may simply replace it with
@name = nil

Getters and setters in Ruby class

Now consider this fragment, and pay attention to the getmyvar, setmyvar, and myvar= methods:

class MyClass

NAME = "Class Name" # class constant
@@count = 0 # Initialize a class variable
def initialize # called when object is allocated
@@count += 1
@myvar = 10
end

def MyClass.getcount # class method
@@count # class variable
end

def getcount # instance returns class variable!
@@count # class variable
end

def getmyvar # instance method
@myvar # instance variable
end

def setmyvar(val) # instance method sets @myvar
@myvar = val
end
def myvar=(val) # Another way to set @myvar
@myvar = val
end
end

Now lets create instance of this class:
foo = MyClass.new # @myvar is 10
foo.setmyvar 20 # @myvar is 20
foo.myvar = 30 # @myvar is 30

Here we see that getmyvar returns the value of @myvar, and setmyvar sets it. (In the terminology of many programmers, these would be referred to as a getter and a setter.) These work fine, but they do not exemplify the Ruby way of doing things. The method myvar= looks like assignment overloading (though strictly speaking, it isn't); it is a better replacement for setmyvar, but there is a better way yet.

The class called Module contains methods called attr, attr_accessor, attr_reader, and attr_writer. These can be used (with symbols as parameters) to automatically handle controlled access to the instance data. For example, the three methods getmyvar, setmyvar, and myvar= can be replaced by a single line in the class definition:

attr_accessor :myvar

This creates a method myvar that returns the value of @myvar and a method myvar= that enables the setting of the same variable. Methods attr_reader and attr_writer create read-only and write-only versions of an attribute, respectively.

Class level variables in ruby

We should use @@ to create such variables, they are similar to static variables we see in java or cpp.

class MyClass

@@count = 0 # Initialize a class variable

def initialize # called when object is allocated
@@count += 1
@myvar = 10
end
end

Wednesday, October 12, 2011

initialize in Ruby vs constructor in Java or cpp

Since class-level data is accessible throughout the class, it can be initialized at the time the class is defined. If a method named initialize is defined, it is guaranteed to be executed right after an instance is allocated. The initialize is similar to the traditional concept of a constructor, but it does not have to handle memory allocation. Allocation is handled internally by new, and deallocation is handled transparently by the garbage collector.

Defining functions in ruby

Defining functions in ruby is quite easy:

def sayHello
puts "Hello world"
end

Calling the function:
sayHello()

Output: Hello world
The first line of the function defines the function called sayHello. The next line is the body of the method, the same line we saw earlier: puts "Hello World". Finally, the last line end tells Ruby we’re done defining the method. Ruby’s response => nil tells us that it knows we’re done defining the method.

Taking the arguments in functions:
def sayName(name)
puts "Hello #{name}"
end

Calling the function:
sayName("k2")

Output : Hello k2
(Note how name is printed with #{} in "" via puts)
Defining the function with default arguments:
def sayDefault(name = "Wolf")
puts "Hello #{name.capitalize}"
end

Calling the function:
sayDefault()

Output: Hello World

Calling with arguments:
sayDefault("k2")



Modules and Mixins

Many built-in methods are available from class ancestors. Of special note are the Kernel methods mixed-in to the Object superclass; because Object is universally available, the methods added to it from Kernel are also universally available. These methods form an important part of Ruby.

The terms module and mixin are nearly synonymous. A module is a collection of methods and constants that is external to the Ruby program. It can be used simply for namespace management, but the most common use of a module is to have its features "mixed" into a class (by using include). In this case, it is used as a mixin.

This term was apparently borrowed most directly from Python. (It is sometimes written as mix-in; but we write it as a single word.) It is worth noting that some LISP variants have had this feature for more than two decades.
Do not confuse this usage of the term module with another usage common in computing. A Ruby module is not an external source or binary file (though it may be stored in one of these). A Ruby module instead is an OOP abstraction similar to a class.
An example of using a module for namespace management is the frequent use of the Math module. To use the definition of pi, for example, it is not necessary to include the Math module; you can simply use Math::PI as the constant.

A mixin is a way of getting some of the benefits of multiple inheritance without dealing with all the difficulties. It can be considered a restricted form of multiple inheritance, but the language creator Matz has called it single inheritance with implementation sharing.
Note that include appends features of a namespace (a module) to the current space; the extend method appends functions of a module to an object. With include, the module's methods become available as instance methods; with extend, they become available as class methods.

We should mention that load and require do not really relate to modules but rather to nonmodule Ruby sources and binaries (statically or dynamically loadable). A load operation essentially reads a file and inserts it at the current point in the source file so that its definitions become available at that point. A require operation is similar to a load, but it will not load a file if it has already been loaded.
The Ruby novice, especially from a C background, may be tripped up by require and include, which are basically unrelated to each other. You may easily find yourself doing a require followed by an include to use some externally stored module.

Built-in classes in Ruby

More than 30 built-in classes are predefined in the Ruby class hierarchy. Like many other OOP languages, Ruby does not allow multiple inheritance, but that does not necessarily make it any less powerful. Modern OO languages frequently follow the single inheritance model. Ruby does support modules and mixins, which are discussed in the next section. It also implements object IDs, as we just saw, which support the implementation of persistent, distributed, and relocatable objects.

Some points to cover are:

Tuesday, October 11, 2011

Symbol in ruby

A symbol in Ruby refers to a variable by name rather than by reference. In many cases, it may not refer to an identifier at all but rather acts like a kind of immutable string. A symbol can be converted to a string with the to_s method.
Hearts   = :Hearts   # This is one way of assigning
Clubs = :Clubs # unique values to constants,
Diamonds = :Diamonds # somewhat like an enumeration
Spades = :Spades # in Pascal or C.

puts Hearts.to_s # Prints "Hearts"

Symbol class in Ruby contains one class method all_symbols and instance methods id2name, inspect, to_i, to_int, to_s and to_sym.


The "enumeration" trick we reference here probably made more sense in the earlier days of Ruby, when there was no Symbol class, and applying the colon to an identifier yielded a simple integer. If you do use this trick, don't rely on the actual symbol values being regular or predictable; just use them as constants whose value is irrelevant.

Making immutable objects

Mutable objects are objects whose state can change. Immutable objects are objects whose state never changes after creation.

Immutable objects have many desirable properties:
  • Immutable objects are thread-safe. Threads cannot corrupt what they cannot change.
  • Immutable objects make it easier to implement encapsulation. If part of an object's state is stored in an immutable object, then accessor methods can return that object to outside callers, without fear that those callers can change the object's state.
  • Immutable objects make good hash keys, since their hash codes cannot change.
In Ruby, Mutability is a property of an instance, not of an entire class. Any instance can become immutable by calling freeze.

Freezing Objects

The freeze method in class Object prevents you from changing an object, effectively turning an object into a constant. After we freeze an object, an attempt to modify it results in TypeError. The following program p050xfreeze.rb illustrates this:
  1. str = 'A simple string. '  
  2. str.freeze  
  3. begin  
  4.   str << 'An attempt to modify.'  
  5. rescue => err  
  6.   puts "#{err.class} #{err}"  
  7. end  
  8. # The output is - TypeError can't modify frozen string  
However, freeze operates on an object reference, not on a variable. This means that any operation resulting in a new object will work. This is illustrated by the following example:
  1. str = 'Original string - '  
  2. str.freeze  
  3. str += 'attachment'  
  4. puts str  
  5. # Output is - Original string - attachment  
The expression str + 'attachment' is evaluated to a new object, which is then assigned to str. The object is not changed, but the variable str now refers to a new object.

frozen?

A method frozen? tells you whether an object is frozen or not. Let's take an example here:
  1. a = b = 'Original String'  
  2. b.freeze  
  3. puts a.frozen? # true  
  4. puts b.frozen? # true  
  5. a = 'New String'  
  6. puts a  
  7. puts b  
  8. puts a.frozen? # false  
  9. puts b.frozen? # true  
Let us understand what we are doing here - a and b are two variables both of which are pointing to a string object - Original String. We then freeze the object Original String. Hence both a and b are now pointing to the frozen object Original String. This is verified by the statements puts a.frozen? and puts b.frozen?. Next, we create a new string object New String and make variable a point to this new object New String. Variable b is still pointing to the frozen object while a is not. This verified by the last 2 statements of the program.

Usage:
Ruby sometimes copies objects and freezes the copies. When you use a string as a hash key, Ruby actually copies the string, freezes the copy, and uses the copy as the hash key: that way, if the original string changes later on, the hash key isn't affected.

Ruby's internal file operations work from a frozen copy of a filename instead of using the filename directly. If another thread modifies the original filename in the middle of an operation that's supposed to be atomic, there's no problem: Ruby wasn't relying on the original filename anyway. You can adopt this copy-and-freeze pattern in multi-threaded code to prevent a data structure you're working on from being changed by another thread.

Another common programmer-level use of this feature is to freeze a class in order to prevent future modifications to it.

Note: Whenever an object in Ruby has no reference to it, then that object is marked for removal and the garbage collector will remove that object based on its algorithm. There is no way to access an un-referenced object.

Variables as reference to objects

Variables are used to hold references to objects. As previously mentioned, variables themselves have no type, nor are they objects themselves; they are simply references to objects.
x = "abc"

An exception to this is that small immutable objects of some built-in classes, such as Fixnum, are copied directly into the variables that refer to them. (These objects are no bigger than pointers, and it is more efficient to deal with them in this way.) In this case assignment makes a copy of the object, and the heap is not used.
Variable assignment causes object references to be shared.
y = "abc"
x = y
x # "abc"

After executing x = y, variables x and y both refer to the same object:
x.object_id     # 53732208
y.object_id # 53732208

If the object is mutable, a modification done to one variable will be reflected in the other:
x.gsub!(/a/,"x")
y # "xbc"

Reassigning one of these variables has no effect on the other, however:
# Continuing previous example...
x = "abc"

y # still has value "xbc"

Creating an object in ruby

To create an object from an existing class, the new method is typically used:
myFile = File.new("textfile.txt","w")
myString = String.new("This is a string object")

This is not always explicitly required, however. In particular, you would not normally bother to call new for a String object as in the previous example:
yourString = "This is also a string object"
aNumber = 5 # new not needed here, either

Objects in Ruby


In Ruby, all numbers, strings, arrays, regular expressions, and many other entities are actually objects. Work is done by executing the methods belonging to the object:
3.succ                 # 4
"abc".upcase # "ABC"
[2,1,5,3,4].sort # [1,2,3,4,5]
someObject.someMethod # some result

In Ruby, every object is an instance of some class; the class contains the implementation of the methods:
"abc".class        # String
"abc".class.class # Class

In addition to encapsulating its own attributes and operations, an object in Ruby has an identity:
"abc".object_id   # 53744407

This object ID is usually of limited usefulness to the programmer.

Ruby Loops

 As for looping mechanisms, Ruby has a rich set. The while and until control structures are both pretest loops, and both work as expected: One specifies a continuation condition for the loop, and the other specifies a termination condition. They also occur in "modifier" form such as if and unless. There is also the loop method of the Kernel module (by default an infinite loop), and there are iterators associated with various classes.

# Loop 1 (while)
i=0
while i < list.size do
print "#{list[i]} "
i += 1
end

# Loop 2 (until)
i=0
until i == list.size do
print "#{list[i]} "
i += 1
end

# Loop 3 (for)
for x in list do
print "#{x} "
end

# Loop 4 ('each' iterator)
list.each do |x|
print "#{x} "
end

# Loop 5 ('loop' method)
i=0
n=list.size-1
loop do
print "#{list[i]} "
i += 1
break if i > n
end

# Loop 6 ('loop' method)
i=0
n=list.size-1
loop do
print "#{list[i]} "
i += 1
break unless i <= n
end

# Loop 7 ('times' iterator)
n=list.size
n.times do |i|
print "#{list[i]} "
end

# Loop 8 ('upto' iterator)
n=list.size-1
0.upto(n) do |i|
print "#{list[i]} "
end

# Loop 9 (for)
n=list.size-1
for
i in 0..n do
print "#{list[i]} "
end

# Loop 10 ('each_index')
list.each_index do |xt
print "#{list[x]} "
end

Sample Program in Ruby

Here is a small interactive console-based program to convert between Fahrenheit and Celsius temperatures:

print "Please enter a temperature and scale (C or F): "
str = gets
exit if str.nil? or str.empty?
str.chomp!
temp, scale = str.split(" ")

abort "#{temp} is not a valid number." if temp !~ /-?\d+/

temp = temp.to_f
case scale
when "C", "c"
f = 1.8*temp + 32
when "F", "f"
c = (5.0/9.0)*(temp-32)
else
abort "Must specify C or F."
end

if f.nil?
print "#{c} degrees C\n"
else
print "#{f} degrees F\n"
end

Here are some examples of running this program. These show that the program can convert from Fahrenheit to Celsius, convert from Celsius to Fahrenheit, and handle an invalid scale or an invalid number:
 Please enter a temperature and scale (C or F): 98.6 F 
37.0 degrees C 


Now, as for the mechanics of the program: We begin with a print statement, which is actually a call to the Kernel method print, to write to standard output. This is an easy way of leaving the cursor "hanging" at the end of the line.
Following this, we call gets (get string from standard input), assigning the value to str. We then do a chomp! to remove the trailing newline.
Note that any apparently "free-standing" function calls such as print and gets are actually methods of Object (probably originating in Kernel). In the same way, chop is a method called with str as a receiver. Method calls in Ruby usually can omit the parentheses; print "foo" is the same as print("foo").
The variable str holds a character string, but there is no reason it could not hold some other type instead. In Ruby, data have types, but variables do not. A variable springs into existence as soon as the interpreter sees an assignment to that variable; there are no "variable declarations" as such.
The exit is a call to a method that terminates the program. On this same line there is a control structure called an if-modifier. This is like the if statement that exists in most languages, but backwards; it comes after the action, does not permit an else, and does not require closing. As for the condition, we are checking two things: Does str have a value (is it non-nil), and is it a non-null string? In the case of an immediate end-of-file, our first condition will hold; in the case of a newline with no preceding data, the second condition will hold.
The same statement could be written this way:
exit if not str or not str[0]

The reason these tests work is that a variable can have a nil value, and nil evaluates to false in Ruby. In fact, nil and false evaluate as false, and everything else evaluates as true. Specifically, the null string "" and the number 0 do not evaluate as false.
The next statement performs a chomp! operation on the string (to remove the trailing newline). The exclamation point as a prefix serves as a warning that the operation actually changes the value of its receiver rather than just returning a value. The exclamation point is used in many such instances to remind the programmer that a method has a side effect or is more "dangerous" than its unmarked counterpart. The method chomp, for example, returns the same result but does not modify its receiver.
The next statement is an example of multiple assignment. The split method splits the string into an array of values, using the space as a delimiter. The two assignable entities on the left-hand side will be assigned the respective values resulting on the right-hand side.
The if statement that follows uses a simple regex to determine whether the number is valid; if the string fails to match a pattern consisting of an optional minus sign followed by one or more digits, it is an invalid number (for our purposes), and the program exits. Note that the if statement is terminated by the keyword end; though it was not needed here, we could have had an else clause before the end. The keyword then is optional; we tend not to use it in this book.
The to_f method is used to convert the string to a floating point number. We are actually assigning this floating point value back to temp, which originally held a string.
The case statement chooses between three alternativesthe cases in which the user specified a C, specified an F, or used an invalid scale. In the first two instances, a calculation is done; in the third, we print an error and exit.
Ruby's case statement, by the way, is far more general than the example shown here. There is no limitation on the data types, and the expressions used are all arbitrary and may even be ranges or regular expressions.
There is nothing mysterious about the computation. But consider the fact that the variables c and f are referenced first inside the branches of the case. There are no declarations as such in Ruby; since a variable only comes into existence when it is assigned, this means that when we fall through the case statement, only one of these variables actually has a valid value.
We use this fact to determine after the fact which branch was followed, so that we can do a slightly different output in each instance. Testing f for a nil is effectively a test of whether the variable has a meaningful value. We do this here only to show that it can be done; obviously two different print statements could be used inside the case statement if we wanted.
The perceptive reader will notice that we used only "local" variables here. This might be confusing since their scope certainly appears to cover the entire program. What is happening here is that the variables are all local to the top level of the program (written toplevel by some). The variables appear global because there are no lower-level contexts in a program this simple; but if we declared classes and methods, these top-level variables would not be accessible within those.

Operators and precedence in Ruby

Now that we have established our most common data types, let's look at Ruby's operators. They are arranged here in order from highest to lowest precedence:

::
Scope
[]
Indexing
**
Exponentiation
+ - ! ~
Unary pos/neg, not, ....
* / %
Multiplication, division, ....
+ -
Addition/subtraction
<< >>
Logical shifts, ...
&
Bitwise and
| ^
Bitwise or, xor
> >= < <=
Comparison
== === <=> != =~ !~
Equality, inequality, ....
&&
Boolean and
||
Boolean or
.. ...
Range operators
= (also +=, -=, ...)
Assignment
?:
Ternary decision
not
Boolean negation
and or
Boolean and, or


Some of the preceding symbols serve more than one purpose; for example, the operator << is a bitwise left shift but is also an append operator (for arrays, strings, and so on) and a marker for a here-document. Likewise the + is for numeric addition as well as for string concatenation. As we shall see later, many of these operators are just shortcuts for method names.

Comment in Ruby

Comments in Ruby begin with a pound sign (#) outside a string or character constant and proceed to the end of the line:

x = y + 5 # This is a comment.
# This is another comment.
print "# But this isn't."

Embedded documentation is intended to be retrieved from the program text by an external tool. From the point of view of the interpreter, it is like a comment and can be used as such. Given two lines starting with =begin and =end, everything between those lines (inclusive) is ignored by the interpreter. (These can't be preceded by whitespace.)
=begin
The purpose of this program
is to cure cancer
and instigate world peace.
=end

Variables in Ruby

Variables and other identifiers normally start with an alphabetic letter or a special modifier. The basic rules are as follows:
  • Local variables (and pseudovariables such as self and nil) begin with a lowercase letter or an underscore.
  • Global variables begin with a $ (dollar sign).
  • Instance variables (within an object) begin with an @ (at sign).
  • Class variables (within a class) begin with two @ signs.
  • Constants begin with capital letters.
  • For purposes of forming identifiers, the underscore (_) may be used as a lowercase letter.
  • Special variables starting with a dollar sign (such as $1 and $/) are not dealt with here.
Here are some examples of each of these:
  • Local variables alpha, _ident, some_var
  • Pseudovariables self, nil, __FILE__
  • Constants K6chip, Length, LENGTH
  • Instance variables @foobar, @thx1138, @NOT_CONST
  • Class variable @@phydeaux, @@my_var, @@NOT_CONST
  • Global variables $beta, $B12vitamin, $NOT_CONST
There are no declarations of variables in Ruby. It is good practice, however, to assign nil to a variable initially. This certainly does not assign a type to the variable and does not truly initialize it, but it does inform the parser that this is a variable name rather than a method name.

Ruby Keywords

alias defined? __FILE__ not then
and do for or true
BEGIN else if redo undef
begin elsif in rescue unless
break END __LINE__ retry until
case end module return when
class ensure next self while
def false nil super yield