We have now covered variables, and constants, the next common area of any programming language is being able to use these variables and constants in logical procedures to receive a required functionality. Computers, and the programs which run on them are not intelligent at all. People are actually intelligent, and the folks who program firmware, and low-level drivers, operating systems and such are pure geniuses. A program, including your Ruby code only does what you tell it to. In life, we make decisions, not only do we make decisions, we examine scenarios and base our decisions on reasoning. This method of action can be implemented pragmatically. This is called Flow Control. Lets review some logical scenarios and convert them to ruby code. We will also cover some of the logical constructs which make up the Ruby language. After this posting, you should be able to write some Ruby code!! =) If/Elsif/Else and Unless What makes a statement true? This is hard to explain in English to me. But take for instance the following statements and their preceding labels. #True 5+5 = 10 #False 5+5 = 5 #True "This" == "This" #False "This" == "That" #Get the point? Truth means the statement checks out. In ruby an if statement starts with the keyword if, immediately following if is a condition. After your condition you are testing for truth, comes the code you want to execute. The if statement requires an end statement to close the block. A elsif or else keyword is not required. However elsif follows the same logic as if, with the keyword elsif followed by a condition to test, followed by the code to execute if a truth is met. The else statement does NOT have a condition following it, it simply says which code to run if all else is not true. Again we always close these blocks with the keyword end. See below examples. 1) If you are 10 years old or older you can get a ticket, if you are under 10, you are not allowed to buy tickets.
2) If you are 10 years old older you can get a ticket, if you are between 7 and 9 you can not get a ticket however you can get an ice cream , if you are under 5 you are too young. #in the case the age is 7.
It should be noted that there is also another syntax of an if statement which makes use of something called an operator. The format for this version of an if statement is below: [condition to test] ? <code to execute if true> : <code if false> so lets rewrite our code using this syntax which is way shorter. >> age >=10 ? puts("old enough") : puts("not old enough get a life buddy")old enoughLoads quicker no? There is also an unless statement which is the opposite of an if statement. Testing for false conditions. => 10>> unless age >= 20>> puts "yes">> endyes=> nilAs we see the age is set to 10, and the test is for age being greater than 20 to be FALSE, in plain English it would read, unless age is greater than or equal to 20, print "yes". Case/When Ruby has another control statement named case. Case can prove useful if you find your self writing endless elsif statements in an if/elsif/else block. Take this comparison into consideration. First the if/elsif/else version of this code. >> today = "monday"=> "monday">> if today == "monday">> puts "i hate mondays">> elsif today == "tuesday">> puts "i hate tuesday more than monday">> elsif today == "wednesday">> puts "its hump day!!">> elsif today == "thursday">> puts "it's payday,, atleast for me">> elsif today == "friday">> puts "THANK BABY JESUS ITS FRIDAY">> else?> puts "have a nice weekend">> endi hate mondays=> nilWe can save ourselves some typing by using case/when >> today = "monday"=> "monday">> case today >> when "monday">> puts "i hate mondays">> when "tuesday">> puts "i hate tuesday more than monday">> when "wednesday">> puts "its hump day!!">> when "thursday">> puts "payday">> when "friday">> puts "tgif!!!">> else?> puts "have a nice weekend">> endi hate mondays=> nilWhile/Until We can also do more traditional loops with the while statement in ruby. Remember while is still testing for a condition to be true similar to if. Lets see by an example, lets see what while does and how it always looping and testing a condition, we will see a infinite loop here, this is generally NOT what you want to do, however for a point to be proven see below. counter = 1while counter < 20puts "The factor of #{counter} and #{counter} is equal to #{counter * counter}"executing this code, loops indefinitely, it does so because we are testing a counter variable to be less than 20, if it's less than 20 we print to screen the sum of the counter multiplied by itself. HOWEVER notice, our counter variable at no point is actually changing here, so as the counter is ALWAYS 1, the loop will not stop until you hit CTRL+C >> counter = 1 => 1>> while counter < 20>> puts "The factor of #{counter} and #{counter} is equal to #{counter * counter}">> endThe factor of 1 and 1 is equal to 1The factor of 1 and 1 is equal to 1The factor of 1 and 1 is equal to 1The factor of 1 and 1 is equal to 1IRB::Abort^C: abort then interrupt!!from /usr/lib/ruby/1.8/irb.rb:89:in `irb_abort'from /usr/lib/ruby/1.8/irb.rb:255:in `signal_handle'from /usr/lib/ruby/1.8/irb.rb:66:in `start'from (irb):78:in `call'from (irb):78:in `write'from (irb):78:in `puts'from (irb):78Lets fix this up and actually INCREMENT our variable properly so that the loop test finally becomes false and the looping completes. This will also make our calculations the numbers more interesting as they will change on each iteration. >> counter = 1=> 1>> while counter < 20>> puts "The factor of #{counter} and #{counter} is equal to #{counter * counter}">> counter += 1>> endThe factor of 1 and 1 is equal to 1The factor of 2 and 2 is equal to 4The factor of 3 and 3 is equal to 9The factor of 4 and 4 is equal to 16The factor of 5 and 5 is equal to 25The factor of 6 and 6 is equal to 36The factor of 7 and 7 is equal to 49The factor of 8 and 8 is equal to 64The factor of 9 and 9 is equal to 81The factor of 10 and 10 is equal to 100The factor of 11 and 11 is equal to 121The factor of 12 and 12 is equal to 144The factor of 13 and 13 is equal to 169The factor of 14 and 14 is equal to 196The factor of 15 and 15 is equal to 225The factor of 16 and 16 is equal to 256The factor of 17 and 17 is equal to 289The factor of 18 and 18 is equal to 324The factor of 19 and 19 is equal to 361=> nilNotice the only change is the addition of an increment method. += is shorthand for typing "counter + 1". It is saying increment this value by 1 or add one to this numeric value if you will. When the variable reaches the value of 19 and goes to the next execution it is tested and 20 is seen, therefore the loop exits as the condition is less than 20. A completely reverse way of looking at things is to introduce the until statement. Lets look at it. >> counter = 1=> 1>> until counter == 20>> puts "The factor of #{counter} and #{counter} is equal to #{counter * counter}">> counter += 1>> endThe factor of 1 and 1 is equal to 1The factor of 2 and 2 is equal to 4The factor of 3 and 3 is equal to 9The factor of 4 and 4 is equal to 16The factor of 5 and 5 is equal to 25The factor of 6 and 6 is equal to 36The factor of 7 and 7 is equal to 49The factor of 8 and 8 is equal to 64The factor of 9 and 9 is equal to 81The factor of 10 and 10 is equal to 100The factor of 11 and 11 is equal to 121The factor of 12 and 12 is equal to 144The factor of 13 and 13 is equal to 169The factor of 14 and 14 is equal to 196The factor of 15 and 15 is equal to 225The factor of 16 and 16 is equal to 256The factor of 17 and 17 is equal to 289The factor of 18 and 18 is equal to 324The factor of 19 and 19 is equal to 361While and Until provide looping constructs. As with the if statement, they can be typed on one line, as well they are completed with an end statement. Iterators & Enumerable Objects To iterate is to proceed through a series or collection. Enumerable is an attribute which means countable. Ruby lets you very easily perform both using it's built in controlling methods. 1) upto - this is an iterator method. It returns an enumerable object, a code block can be called to process per iteration. Ex: >> 1.upto(100) {|number| puts "Half of #{number.to_s} is #{number / 2}" } Half of 1 is 0 Half of 2 is 1 Half of 3 is 1 Half of 4 is 2 Half of 5 is 2 Half of 6 is 3 Half of 7 is 3 Half of 8 is 4 ... This actually goes up until 100 but I truncated the output here for brevity. One thing you may notice is the fact that the math is incorrect. Slap! That is Ruby again and it's classes. Remember we are working with whole numbers here, no decimal places. We go from 1 - 100. So when we perform a mathematical calculation dividing an odd number by 2, we are expecting a number with a decimal place. However as stated, these are Fixed Number classes, and not Floating point. If we wanted exact math however, we can get it, lets convert the numbers to float so that our math is correct and people don't think we are idiots =) Ex: (redone) >> 1.upto(100) {|number| puts "Half of #{number.to_s} is #{number.to_f / 2.0}" } Half of 1 is 0.5 Half of 2 is 1.0 Half of 3 is 1.5 Half of 4 is 2.0 Half of 5 is 2.5 Half of 6 is 3.0 Half of 7 is 3.5 Half of 8 is 4.0 Half of 9 is 4.5 Half of 10 is 5.0 Half of 11 is 5.5 Half of 12 is 6.0 Half of 13 is 6.5 Half of 14 is 7.0 Half of 15 is 7.5 Half of 16 is 8.0 Half of 17 is 8.5 Half of 18 is 9.0 Half of 19 is 9.5 Half of 20 is 10.0 ... Good deal? 2) downto - We will not stick on this one long as it is the exact inverse of the previous iterator method I have shown. It is called downto, it's usage is synonymous with that of the upto method. 3) step - Step allows you to count by a certain number. Like by 2's for instance. You simply supply the max number and the stepping number. Ex: >> 0.step(10,2) {|x| puts x} 0 2 4 6 8 10 => 0 4) times - times is a simple looping construct. If you have ever used zsh, it is similar to the repeat function. Ex: >> 2.times { puts "yes"} yes yes => 2 Simple enough yes? Enclosures Enclosures, or code blocks in ruby are denoted by the code between do and end it can also be enclosed in surrounding curly brackets {}. We can see this below. Something else you will see is a brief example of dealing with an array. Code blocks receive data from other calls and iterate over that data. Actually the Array class comes with methods specifically for iterating it's members. Lets look at this... #This is how to statically define an array. There are other ways to create Array objects with Array.new being one. This Array is stored in a variable called Array. >> array = [4,5,6]=> [4, 5, 6]#We call the each method on our array variable, we call class on the returned object. This object is of Enumeberable::Enumerator class, it is a class inside of a module. We will cover modules and classes more in other posts. >> array.each.class => Enumerable::Enumerator #Iterating the enumerator object and printing the members as strings. >> array.each do |i|?> puts i.to_s>> end456=> [4, 5, 6]So we know what the returned object is, it's an Enumerator object, so this means we can then call the each method upon this object directly. Each method takes each member in the array variable and sends it to our code block. The |i| is called a "chute" it is saying to put the data from *this* iteration of each, into the variable defined between the chute. We then go on to print each member (which is actually a FixNum class) as a string, by calling the to_s method on each member as we step through iterations. The end statement denotes the end of this processing. As previously stated, do and end is interchangeable with {}. Lets see it in action. >> array.each {|i| puts i.to_s }456=> [4, 5, 6]There is a way to actually save a code block and call on it at a later time by referencing the variable and a call statement. This is possible by way of a method named lambda. Lambda creates a Proc object which is "saved code block" in object form. More on this later, but a taster below. >> multiply_by_myself = lambda {|x| puts x * x }=> #<Proc:0x00007f5333429248@(irb):55>>> multiply_by_myself.call(5)25Code Blocks in ruby 1.8.x share the same scope as their calling code, however in ruby 1.9.2 there is a change and code blocks have their own scope. Methods Methods are very similar to functions in procedural programming with the exception that methods by programmatic definition act on objects. Ruby methods indeed act on objects however one could simply write his own methods in the global scope of ruby without using the notion of classes or objects. This would be counter productive but it is possible. Methods (as well as constants, variables, and etc) reside inside of classes & modules in ruby. This of course is due the object oriented nature of the language. Just about every function you use in Ruby comes from a class. In the previous sections you may have seen us calling functions directly on objects or on variables holding an object. We use the "." to denote that we are calling the function after the dot on the object preceding the dot. However IF the class or module is already available to the present scope of the program... there is no need to specify the dot and what is previous to it. For instance. Lets take Kernel module. And lets look at the puts and gets methods. >> puts "test"test=> nil>> getsdata=> "data\n" How is it that I am able to call puts and gets with no object preceding and no dot delimiter for the object and method? Simple as previously stated the Kernel module is always present. The methods gets, and puts come from this module. The Kernel module is "Mixed In" with the Object class. We will talk about modules and mix in's in another post. A module is very much like a class however objects are not created from modules. However methods and even other classes can reside inside of a Module. First lets reiterate calling a function on an object. #Calling the inspect method on the Object Object (yes I said that twice, it is an object of the object class) >> Object.inspect=> "Object"#Calling a method in the KERNEL MODULE (not class). >> Kernel.puts("Si Senor")Si Senor=> nilYou can see it is the same methodology. And the Kernel modules puts method can be called without referencing the module. #Calling puts directly without referencing the module. >> puts "test"test=> nil#calling INSPECT directly without referencing an object >> inspect=> "main"Both above examples are capable because the Kernel Module and Object Class is available to all code in Ruby. We have covered how to use methods in Ruby however lets look at how to make them. Methods are defined by the def keyword and they end with the end keyword. all code between is legal code. Lets look at a simple example of creating a method. >> def say_your_name>> puts "your name">> end=> nil>> say_your_nameyour name=> nil We defined a very simple method which simply prints a string to the screen. There is no logic involved. A method similar to a command line program (or any program for that matter) can process arguments. Arguments are additional data passed into a method that the method can process or use to control processing. Methods which take arguments are most likely more scalable and usable than those which don't. Lets make our silly method a little less silly now. >> def say_your_name(name)>> puts name>> end=> nil>> say_your_name("Aaron Samuel")Aaron Samuel=> nil We have now introduced a way for our method to process arguments. And boy does it make the code less stupid? You can also see how reusable this is. If the requirement was only for the program to say your name,, there you have it. Not only can we provide arguments, but we can provide default values for those arguments. >> def say_your_name(name="Aaron Samuel")>> puts name>> end=> nil>> say_your_name() Aaron Samuel=> nil Notice that without providing an argument the method returns Aaron Samuel. This is because we defined a default value for the local variable name. (Which as discussed in our variables talk is a local variable and local in scope to the say_your_name method). Another thing you may notice is I call say_your_name with empty parenthesis. In Ruby a function can be called with parenthesis enclosing it's arguments or you can also omit them. It is purely up to the developer or coder. However sometimes no parenthesis can look odd. There are also some edge cases where you will need to use parenthesis to not confuse the interpreter. You now know about methods, ruby flow control and logic statements, and enclosures. Have fun moving forward with my postings. |
