Saturday, January 14, 2012

Ruby in a day

What is Ruby?
Ruby is a general purpose object oriented scripting language. It is inspired by PERL with Smalltalk like features. It is also functional, dynamic, imperative and reflective in all sense. It hase dynamic type system and contains automatic memory management.
Ruby was conceived on Feb 24, 1993 by Yukihiro Matsumoto, who wished to create a new language that balanced functional programming with imperative programming.


Reference
http://www.ruby-lang.org/en/


Learning a programming language
There are different ways to learn new programming/scripting language. Understand the basics and start with a simple project, keep building on the project until all areas you read are implemented in the project one way or the other. Or you can learn it by going over the basic syntax for the language. One you have the basic syntax, you can develop small modules that help you understand the basics, you inch forward until you become fairly comfortable with the language. Different people tend to have different approaches, I prefer the later approach. Reason, you hardly get dedicated time these days to pick up a project, and work end-to-end. It may take days, and some times weeks to read 200 page book. Given these limitations the second approach works better (for me). Why am I saying all this, because, I am going to run this page with the later approach, pick up bits and pieces of the language, connecting the dots is left to you. I'll throw some simple programs with some basic comments you can understand, follow and come up with your conventions. If you find any of the programs/solutions are not correct, feel free to shout, I'll try to attend to the as fast as possible.


Do I have the right tools with me
There are so many tools available for you to start programming Ruby - IronRuby, Eclipse (check Eclipse.org), NetBeans, JRuby plugin for Eclipse, and the list goes on

Let's get started
Ruby programs can be done with


Why should I always say HelloWorld first
Because you are asked to do so :) Let's follow the legacy without any more question
HelloWorld sample and Let's name it HelloWorld.rb


class HelloWorld
def initialize
puts("\nHello World\n")
end
#MAIN
helloWorld = HelloWorld.new

Let me take a minute to go over this simple program. In the above code we have created a simple class that contains nothing more than a 'initialize' (equal to a constructor in other languages like C++, C#, etc). There are no main methods in Ruby code. Anything that's coded outside a class is considered to be the main method


There are multiple ways to print text, variables. 'print' and 'puts' methods are nice ways to output text. If you want to print a value of a variable you can always do that by following the simple syntax of #{variable_name}


Well, I know what you are think. Alright, Alright, how do I accept some input form the user to print it back or manipulate on. That's where the 'gets' method come's in. Try this one out
 def self.acceptNameAndSayHello
puts("\nYour name please: ")
name = STDIN.gets
puts("\n")
print %Q{Hello friend: #{name}}
puts("\n")
end

A simple class with definition
Let's do a little more now. What if I want to add more functions that accept parameters. Here's another sample of the same.


class HelloWorld
def initialize
puts("\nHello World\n")
end

def SayHello(name)
print %Q{Hello friend: #{name}}
puts("\n")
end

def self.SayHello
print %Q{Say hello}
puts("\n")
end
end

#MAIN
helloWorld = HelloWorld.new
HelloWorld.SayHello
helloWorld.SayHello("Krishnan")

Ruby by virtue of being a scripting language, does not have any data-types. That's right feel free to use variables of your choice. Variables are dynamically associated to their types based on how they are initialized. More on that later. For now, let's move on. One point you may want to remember is, Ruby is case sensitive. If you have initialized a variable "myName" and by mistake you use "MyName" else where in the code, consider you are out of luck. That won't work the way you wanted. So make sure what you type in


Remember the first function to execute in a class is 'initialize'.


Try out sample of code that returns a variety of data types - String, integer, floating value, boolean, etc


Basic conditions sample
Now that we have got some functions on the roll, how do I do some decision making - if, else if,switch statements at a glance

Simple If condition, and ternary operator

def SimpleIfCondition(name)
if(name != nil && name.length > 0) then
print "Name is not NIL!!!"
end
end
def SimpleIfElseIfCondition(designation)
if(designation == "Manager") then
puts("\nWelcome manager, hope you will have a nice day!")
elsif (designation == "Employee") then
puts("\nWelcome employee. Now shut-up and goto work!")
end
end

def SimpleTernaryOperation(name)
puts "\n Your name is #{name}"
isAdmin = (name == "Yukihiro Matsumoto") ? true : false
if(isAdmin) then
puts "\nWelcome administrator!"
else
puts "\nNot an administrator"
end
end



Switch case condition usage

def SimpleCaseCondition
print "\nEnter day today: "
day = STDIN.gets
day.chomp!
case day
when 1:
print "Sunday"
when 2:
print "Monday"
when 3:
print "Tuesday"
when 4:
print "Wednesday"
when 5:
print "Thursday"
when 6:
print "Friday"
else
print "Saturday"
end
end
end

Picking up a scripting language is pretty easy in early days and it can't get more simple than this. Let's keep rolling and move on to do some loops in Ruby




Basic loops sample
Loops help us to execute a single/set of statements multiple times or until a condition is satisfied. Ruby feeds developers with a lot of choices when it comes to loops, use them judiciously based on your needs - Until, while, for, Times, upto, downto and loop are the choices, example below may help you understand these easily




class SimpleLoopDemonstration
#until loop
def SimpleUntilLoop
x = 1
until x >= 10 do
puts x
x += 1
end
end
# while loop
def SimpleWhileLoop
x = 1
while x <= 10 do puts x x += 1 end end # for loop def SimpleForLoop x = 1 for x in 1..5 puts x end end # time's loop def TimesLoop 10.times { x PrintText(x) } end def SimpleUpTo PrintText("Simple Up To") 1.upto(10) { x PrintText(x) } end def SimpleDownTo PrintText("Simple Down To") 10.downto(1) { x PrintText(x) } end def simpleLoop x = 1 PrintText("Simple Loop") loop do x += 1 if x == 3 then break elsif x == 5 then next else PrintText(x) end end end def PrintText(someText) puts(someText) end end # MAIN part of the program puts "Hello World" simpleLoop = SimpleLoopDemonstration.new simpleLoop.SimpleWhileLoop puts "Until loop" simpleLoop.SimpleUntilLoop puts "for loop" simpleLoop.SimpleForLoop puts "10 times loop" simpleLoop.TimesLoop simpleLoop.SimpleUpTo simpleLoop.SimpleDownTo simpleLoop.simpleLoop








Now that we know the basic conditions and iterations, you can try different mathematical operations to get more comfortable in each of them


Here are some sample on string manipulation



class SimpleStringOperations
def initialize
@myText = "simple string manipulations"
end

def createString(str)
@myText = str
end

def concatenateText(attachText)
newText = @myText + attachText
return newText
end

def concatenateNumericValue(numericVal)
newText = @myText + numericVal.to_s
return newText
end

def removeLastChar
newText = @myText.chop
return newText
end

def findLength
return @myText.length
end

def reverseText
return @myText.reverse
end

def changeCase(toUpperCase)
return (toUpperCase == true) ? @myText.upcase : @myText.downcase
end

def self.printText(message)
print %Q{#{message}}
puts("\n")
end

def getText
return @myText
end

end

#MAIN part
stringOperations = SimpleStringOperations.new
stringOperations.createString("I love programming Ruby")
SimpleStringOperations.printText(stringOperations.getText)
newText = stringOperations.concatenateNumericValue(2.1)
SimpleStringOperations.printText(newText)
SimpleStringOperations.printText("Length of text is :" + stringOperations.findLength.to_s)
SimpleStringOperations.printText(stringOperations.reverseText)
SimpleStringOperations.printText(stringOperations.changeCase(true))
SimpleStringOperations.printText(stringOperations.changeCase(false))
SimpleStringOperations.printText(stringOperations.removeLastChar)



Want help on the function definitions, here's how you can get them


Simple mathematical operations
Integer and float point functions are used the same way we used string manipulation functions on string variables. Here are some functions that may come handy - abs, ceil, coerce, mod, floor, remainder, etc. There is one additional function that surprised me - next, succ. These 2 functions does an increment operation (similar to ++ in C++, C#). Here's a one simple implementation that you may not have seen so for. Note the way '?' has been used in the sample. That's how BOOLEAN functions are tested in RUBY


def valueIsInteger(inValue)
(inValue.integer? == true) ? printMessage("variable IS integer") : printMessage("variable IS NOT integer")
end



Object Oriented programming
If not for OOP, we can as well go ahead and so everything in something like Shell, Python and Perl. By virtue of being a scripting languages, Ruby does not support all features of OOP.
Here are a few of them that may help


Encapsulation & Abstraction
So far in all of the samples you may have noticed the usage of functions. Have we seen access-specifiers yet. Nope. We have 3 of them - 'public', 'private', 'protected'. As the name implies, Public is meant for complete access, private is meant for internal access only and protected is restricted access in hierarchal structure. A simple sample is added here, you can experiment more on them when you get a bit


Simple inheritence
Ruby supports single inheritence, meaning you can derive from a singular class only (unlike C++). I have created a simple sample to explain inheritence. Example is self-explanatory, and will give you an easy understanding of how inheritence works in Ruby. You may want to attempt some code changes like change the access specifiers, add functions, properties to the class and see how the overall behavior is




class LogMe
def self.Print(message)
print %Q{#{message}}
puts("\n")
end
end

class Person
public
attr_accessor :firstName, :lastName, :gender
private
attr_accessor :dateOfBirth
public
def initialize
end

def initialize(inFirstName, inLastName, inGender, inDateOfBirth)
@firstName = inFirstName
@lastName = inLastName
@gender = inGender
@dateOfBirth = inDateOfBirth
end

def getName
return @firstName + " " + @lastName
end

def getAge
# calculate Age from date of birth
return Time.now - @dateOfBirth
end

def personDetails
LogMe.Print("Name: " + getName + ", Age: " + getAge.to_s)
end
end
class Employee < Person protected attr_accessor :empId, :designation, :salary, :type public def initialize(inFirstName, inLastName, inGender, inDateOfBirth, inEmpId, inDesignation, inSalary, inType) super(inFirstName, inLastName, inGender, inDateOfBirth) @empId = inEmpId @designation = inDesignation @salary = inSalary @empType = inType end def provideEmployeeDetails personDetails LogMe.Print("Employee Id: " + @empId.to_s + ", Designation: " + @designation + ", Type: " + @empType) end end #MAIN part #person = Person.new "Bob", "Fredunberg", "Male", Time.local(1971, 3, 4) #LogMe.Print("Name: " + person.getName) #LogMe.Print("First Name: " + person.firstName) #LogMe.Print("Age: " + person.getAge.to_s) employee = Employee.new("Bob", "Fredunberg", "Male", Time.local(1971, 3, 4), 1, "Scintist", 300000, "Permanent") employee.provideEmployeeDetails






Polymorphism


Class, instance and global variables


Arrays
Handling arrays in RUBY is one of the most easiest to do. We have an in-built generic class 'Array'. Use Array class to instantiate a new instance for your case and use the tons of in-built functions to manipulate it. I have provided a simple example of a 'Family' were in persons are added, searched for, updated and removed. Hope this explains how Arrays work at a higher level. There are more functions available for the class please go through the RUBY manual to make effective use of them




class SimpleArray
attr_accessor :family

def initialize()
@family = ["Sam", "Bob", "Fred", "Smith"]
end

def AddPerson(person)
memberCount = @family.length;
@family.push(person)
end

def RemovePerson(person)
memberIndex = GetMemberIndex(person)
if(memberIndex > -1) then
@family.delete_at(memberIndex)
end
end

def RemoveAllMembers
@family = []
end

private
def GetMemberIndex(familyMember)
memberCount = 0
@family.each do member
if(familyMember == member) then
return memberCount
end
memberCount += 1
end
return -1
end

public
def Listfamily
if(@family == nil @family.length <= 0) then print %Q{@family is NIL. Please load values into @family} else puts(@family) end end private def searchFor(person) return @family.include?(person) end public def SearchPerson(person) if(@family == nil @family.length <= 0) then print %Q{There are no members in the family to search for.} return end if(searchFor(person) == true) then print %Q{Found the person. He's part of this family} else print %Q{Sorry, he's not a member of this family} end end def ReplacePersonWith(oldPerson, newPerson) if(searchFor(oldPerson) == true) print %Q{Found person: #{oldPerson}} end memberIndex = GetMemberIndex(oldPerson) if(memberIndex > -1) then
@family[memberIndex] = newPerson
print %Q{Member replaced!!!}
end
end
end

# MAIN part of the code
myfamily = SimpleArray.new()
myfamily.AddPerson("Mari")
puts("\n")
myfamily.Listfamily
myfamily.SearchPerson("Peter")

myfamily.ReplacePersonWith("Mari", "Mary")
puts("\n")
myfamily.Listfamily
myfamily.RemovePerson("Mary")
puts("\n")
myfamily.Listfamily




Maps
Arrays provide sequential access to a collection, what is you want to have a random access, Maps are the best alternative. use 'Hash' class to achieve the same. Take a look at the following sample to understand how to use it. In my sample I store name for a website (as key) and the website (as value). You can think of something that will make you understand better, if this does not suffice


class SimpleMaps
attr_accessor :urls
def initialize
@urls = Hash.new
print %Q{Hash map initialized}
end

def AddUrl(key, value)
LOG("\nAdd a URL #{key} with #{value}")
@urls[key] = value
end

def ListMap
LOG("\n Map List")
@urls.keys.each do key
LOG("\nKey is #{key}")
end
end

def SearchForUrl(inkey)
LOG("\nSearch for URL: #{inkey}")
@urls.keys.each do key
if(key == inkey) then
LOG("\nFound the #{inkey}")
end
end
end

def SearchForValue(invalue)
# check for contains too
LOG("\nSearch for value: #{invalue}")
@urls.keys.each do key
if(@url[key] == invalue) then
LOG("\nFound the #{invalue}")
end
end
end

private
def FindKey(inkey)
@urls.keys.each do key
if(key == inkey) then
return true
end
end
return false
end

public
def RemoveUrl(key)
LOG("\nRemove URL #{key}")
if(FindKey(key) == true) then
@urls.delete(key)
end
end

private
def LOG(message)
print %Q{#{message}}
end

end

# MAIN section
maps = SimpleMaps.new
maps.AddUrl("IT news", "www.zdnet.com")
maps.ListMap
maps.SearchForUrl("IT news")
maps.RemoveUrl("IT news")
maps.ListMap
Simple Regular expressions
Regular expression are life-lines for string manipulations. Any programmer who wishes cut short his work time on string manipulations should posses expertise in regular expression. It's an exciting subject, aptitude of a developer is intensely tested when working on complex regular expressions. Here are some samples to start with but you may want to build on these.


class LogMe
def self.PrintMessage(message)
print %Q{#{message}}
puts("\n")
end
end

class SimpleRegularExpressions

def initialize
end

def textContainsWord(inText, searchWord)
return (inText =~ /#{searchWord}/) ? true : false
end

def textContainsAnyOfWords(inText, inWord1, inWord2, inWord3)
return (inText =~ /#{inWord1} #{inWord2} #{inWord3}/) ? true : false
end

def doesTextStartWith(forWord)
return ("This is a sample text" =~ /^#{forWord}/i) ? true : false
end

def doesTextEndWithWord(withWord)
return ("This is a sample text" =~ /#{withWord}$/)
end

def doesMatchCollectionCharacters
if("This is a zample text" =~ /(svjk)ample/i) then
return true
end
return false
end

def someMoreSamples
string1 = "Steve was here"
# folowing condition will match for Steve, here too
if(string1 =~ /e.*e/) then
LogMe.PrintMessage("Found matching text")
end
# what if I want to find occurrences and information on them
string1 = "I will drill for well"
if(string1 =~ /(w.ll)/) then
print "Matched on ", $2, "\n"
end

string1 = "My phone number is (508)-001-1234"
if(string1 =~ /.\d{3}.{2}\d{3}.\d{4}/) then
LogMe.PrintMessage "Found a phone number"
end
end
end

# MAIN section
inText = "This is a sample text for RUBY regular expression sample"
regExp = SimpleRegularExpressions.new
if(regExp.textContainsWord(inText, "sample")) then
LogMe.PrintMessage("Found text match")
else
LogMe.PrintMessage("Sorry, canot find text")
end

if(regExp.textContainsAnyOfWords(inText, "PERL", "Python", "iOS")) then
LogMe.PrintMessage("Ah. Looks like the text is on scripting language")
else
LogMe.PrintMessage("Sorry, does not contain any message on scripting languages")
end

if(regExp.doesTextStartWith("This") == true) then
LogMe.PrintMessage("Start's with \"This\"")
else
LogMe.PrintMessage("Does not start with \"This\"")
end

if(regExp.doesTextEndWithWord("samples text")) then
LogMe.PrintMessage("Does end with \"sample\"")
else
LogMe.PrintMessage("Does not end with \"sample\"")
end

if(regExp.doesMatchCollectionCharacters) then
LogMe.PrintMessage("matches collection characters")
else
LogMe.PrintMessage("Does not match collection characters")
end
regExp.someMoreSamples







Simple file operations
Now that we have seen many areas of RUBY, one last step is handling files. How do I read, write into a file. RUBY provides us with 'File' class that has a variety of methods to create, open, read, write, rename, delete a file. In addition, it also allows us to query the type of file, check to see if the given path refers to a file or a directory, check to see if the location is valid and a lot more. I have provided a basic example, please refer to RUBY documentation to know more about this Object



class SimpleFileOperations
public
attr_accessor :file
attr_accessor :fileName

def initialize
@file = File.new("/Users/Rick/Private/Information.txt")
@fileName = "/Users/Rick/Private/Information.txt"
end

def closeFile
if(!@file.closed?) then
@file.close
end
end

def IsFileReadable
File.readable?(@fileName) ? true : false
end

def IsFileWritable
return File.writable?(@fileName) ? true : false
end

def IsFileExecutable
return File.executable?(@fileName) ? true : false
end

def fileSize
if(File.zero?(@fileName)) then
return 0
end
return File.size(@fileName)
end

def fileType
return File.fType(@fileName)
end

def someMetaInformation
print %Q{File Created on: #{File.ctime(@fileName)} and last modified on: #{File.mtime(@fileName)} and last accessed on: #{File.atime(@fileName)}}
end

def readFile
puts("Read File - #{@fileName}\n")
@fileName="test.dmp"
begin
@file = File.open(@fileName)
#@file.each {line puts(line)}
while(line = @file.gets)
puts(line)
end
@file.close
rescue => err
puts "Exception: #{err}"
err
end
end

end

# MAIN section
puts("Hello world")
fileOperations = SimpleFileOperations.new
puts("File options - Read: #{fileOperations.IsFileReadable}, Write: #{fileOperations.IsFileWritable}, Execute: #{fileOperations.IsFileExecutable}")
puts("File Size: #{fileOperations.fileSize}")
#puts("Type: #{fileOperations.fileType}")
puts("Some meta information")
fileOperations.someMetaInformation
fileOperations.readFile
What we/you may want to do next
I'll add more posts on the following sections
  1. Have a sample for OOP - develop a utility application
  2. More samples on regular expression
  3. More examples on File based operations
  4. Polymorphism explanation

No comments:

Post a Comment