Ruby 2 Arrays

An Array is just a list of items in order (like mangoes, apples, and oranges). Every slot in the list acts like a variable: you can see what object a particular slot points to, and you can make it point to a different object. You can make an array by using square brackets In Ruby, the first value in an array has index 0. The size and length methods return the number of elements in an array. The last element of the array is at index size-1. Negative index values count from the end of the array, so the last element of an array can also be accessed with an index of -1. If you attempt to read an element beyond the end of an array (with an index >= size) or before the beginning of an array (with an index < -size), Ruby simply returns nil and does not throw an exception. Ruby's arrays are mutable - arrays are dynamically resizable; you can append elements to them and they grow as needed. Let us look at the following examplep018arrays.rb. Please go through the program carefully.
  1. # p018arrays.rb  
  2. # Arrays  
  3.   
  4. # Empty array  
  5. var1 = []  
  6. # Array index starts from 0  
  7. puts var1[0]  
  8.   
  9. # an array holding a single number  
  10. var2 = [5]  
  11. puts var2[0]  
  12.   
  13. # an array holding two strings  
  14. var3 = ['Hello''Goodbye']  
  15. puts var3[0]  
  16. puts var3[1]  
  17.   
  18. flavour = 'mango'  
  19. # an array whose elements are pointing  
  20. # to three objects - a float, a string and an array  
  21. var4 = [80.5, flavour, [truefalse]]  
  22. puts var4[2]  
  23.   
  24. # a trailing comma is ignored  
  25. name = ['Satish''Talim''Ruby''Java',]  
  26. puts name[0]  
  27. puts name[1]  
  28. puts name[2]  
  29. puts name[3]  
  30. # the next one outputs nil  
  31. # nil is Ruby's way of saying nothing  
  32. puts name[4]  
  33. # we can add more elements too  
  34. name[4] = 'Pune' 
  35. puts name[4] 
  36. # we can add anything! 
  37. name[5] = 4.33 
  38. puts name[5] 
  39. # we can add an array to an array 
  40. name[6] = [1, 2, 3] 
  41. puts name[6] 
  42.  
  43. # some methods on arrays 
  44. newarr = [45, 23, 1, 90] 
  45. puts newarr.sort 
  46. puts newarr.length 
  47. puts newarr.first 
  48. puts newarr.last 
  49.  
  50. # method each (iterator) - extracts each element into loc 
  51. # do end is a block of code 
  52. # we shall talk about blocks soon here - 
  53. # /satishtalim/ruby_blocks_and_procs.html 
  54. # variable loc refers to each item in the array as it goes through the loop 
  55. locations = ['Pune', 'Mumbai', 'Bangalore'] 
  56.  
  57. locations.each do |loc| 
  58.   puts 'I love ' + loc + '!' 
  59.   puts "Don't you?"  
  60. end  
  61.   
  62. # delete an entry in the middle and shift the remaining entries  
  63. locations.delete('Mumbai')  
  64. locations.each do |loc|  
  65.   puts 'I love ' + loc + '!'  
  66.   puts "Don't you?"  
  67. end  
The method each (for any object) allows us to do something (whatever we want) to each object the array points to. In the example, we are able to go through each object in the array without using any numbers. Here are a few things to remember:
  • The variable loc inside the "goalposts" refers to each item in the array as it goes through the loop. You can give this any name you want, but make it memorable.
  • The do and end identify a block of code that will be executed for each item. Blocks are used extensively in Ruby.
Here's an interesting example of a method that returns an array. Example p019mtdarry.rb
  1. # p019mtdarry.rb  
  2. # if you give return multiple parameters,  
  3. # the method returns them in an array  
  4. # The times method of the Integer class iterates block num times,  
  5. # passing in values from zero to num-1  
  6.   
  7. def mtdarry  
  8.   10.times do |num|  
  9.     square = num * num  
  10.     return num, square if num > 5  
  11.   end  
  12. end  
  13.   
  14. # using parallel assignment to collect the return value  
  15. num, square = mtdarry  
  16. puts num  
  17. puts square  
The output is:
  1. >ruby p019mtdarry.rb  
  2. 6  
  3. 36  
  4. >Exit code: 0  
The times method of the Integer class iterates block num times, passing in values from zero to num-1. As we can see, if you give return multiple parameters, the method returns them in an array. You can use parallel assignment to collect this return value.

Parallel Assignment

To explain this, we'll use the terms lvalue and rvalue. An lvalue is something that can appear on its own on the left-hand side of an assignment (a variable, constant, or attribute setter method). An rvalue is something that can appear on its own on the right hand side. Ruby lets you have a comma-separated list of rvalues. Once Ruby sees more than one rvalue in an assignment, the rules of parallel assignment come into play. First, all the rvalues evaluated, left to right, and collected into an array (unless they are already an array). This array will be the eventual value returned by the overall assignment. Next, the left hand side (lhs) is inspected. If it contains a single element, the array is assigned to that element.
  1. a = 1, 2, 3, 4 # => a == [1, 2, 3, 4]  
  2. b = [1, 2, 3, 4] # => b == [1, 2, 3, 4]  
If the lhs contains a comma, Ruby matches values on the rhs against successive elements on the lhs. Excess elements are discarded.
  1. a, b = 1, 2, 3, 4 # => a == 1, b == 2  
  2. c, = 1, 2, 3, 4 # => c == 1  

Environment Variables

An environment variable is a link between our program and the outside world. An environment variable is essentially a label referring to a piece of text; and can be used to store configuration information such as paths, usernames, and so on. You can access operating system environment variables using the predefined variable ENVENV is simply a hash.
  1. ENV.each {|k,v| puts "#{k}: #{v}"}  
Ruby sets ENV to the environment variables. After that, iteration proceeds with each. This time, the block takes two parameters: k (key) and v (value). Blocks are a completely general mechanism and can take any number of arguments.
The values of some environment variables are read by Ruby when it first starts. These variables modify the behavior of the interpreter, as shown below.
Environment Variables
A Ruby program may write to the ENV object. On most systems this changes the values of the corresponding environment variables. However, this change is local to the process that makes it and to any subsequently spawned child processes. A subprocess changes an environment variable, and this change is inherited by a process that it then starts. However, the change is not visible to the original parent. (This just goes to prove that parents never really know what their children are doing.)
  1. ENV["course"] = "FORPC101"  
  2. puts "#{ENV['course']}"  
As of Ruby 1.9, setting an environment variable's value to nil removes the variable from the environment.

Command-line arguments

If you're starting a program from the command line, you can append parameters onto the end of the command and the program processes them.

You can do the same with your Ruby application. Ruby automatically places any parameters that are appended to the command line when you launch your Ruby program into a special array called ARGV. If your program is:
  1. f = ARGV[0]  
  2. puts f  
You can execute this program from the command line as:
  1. ruby tmp.rb 23  
The program should display 23.

Library GetoptLong

Class GetoptLong supports command-line option parsing. Options may be a minus sign (-) followed by a single character, or two minus signs (--) followed by a name (a long option). Options may be given in any order. A single internal option may have multiple external representations. For example, the option to control verbose output could be any of -v, --verbose, or --details. Some options may also take an associated value. Each internal option is passed toGetoptLong as an array, containing strings representing the option's external forms and a flag. The flag specifies how GetoptLong is to associate an argument with the option (NO_ARGUMENT, REQUIRED_ARGUMENT, or OPTIONAL_ARGUMENT).

Suppose I want to call a Ruby program as:
  1. ruby tsftpc.rb -hftp.ibiblio.org -n21 -uanonymous -ps@s.com  
Here's the code to do so:
  1. require 'getoptlong'  
  2.   
  3. # Call using "ruby tsftpc.rb -hftp.ibiblio.org -n21 -uanonymous -ps@s.com"  
  4. # The parameters can be in any order  
  5. unless ARGV.length == 4  
  6.   puts "Usage: ruby tsftpc.rb -hftp_site_url -nport_no -uuser_name -ppassword"  
  7.   exit  
  8. end  
  9.   
  10. host_name = port_no = user_name = password = ''  
  11. # specify the options we accept and initialize  
  12. # the option parser  
  13. opts = GetoptLong.new(  
  14. "--hostname""-h", GetoptLong::REQUIRED_ARGUMENT ],  
  15. "--port""-n", GetoptLong::REQUIRED_ARGUMENT ],  
  16. "--username""-u", GetoptLong::REQUIRED_ARGUMENT ],  
  17. "--pass""-p", GetoptLong::REQUIRED_ARGUMENT ]  
  18. )  
  19. # process the parsed options  
  20. opts.each do |opt, arg|  
  21.   case opt  
  22.     when '--hostname'  
  23.       host_name = arg  
  24.     when '--port'  
  25.       port_no = arg  
  26.     when '--username'  
  27.       user_name = arg  
  28.     when '--pass'  
  29.       password = arg  
  30.   end  
  31. end  
require gives you access to the many extensions and programming libraries bundled with the Ruby programming language-as well as an even larger number of extensions and libraries written independently by other programmers and made available for use with Ruby. We shall be studying require in more detail, later on. Also, later on, we shall study how to access constant using ::
How do I convert objects into an Array? If you want to wrap objects in an Array, you can use a special Kernelmodule Array method (that starts with a capital letter and looks like a class). This special method converts its one argument into an array. For example:
  1. str = 'hello'  
  2. print Array(str).class # Array  
Another example:
  1. str = 'hello\nworld'  
  2. print Array(str) # ["hello\\nworld"]  
What are the ancestors of Array? Run the following program, to find that out:
  1. a = [1,2,3,4]  
  2. print a.class.ancestors  
You should see:
  1. [Array, Enumerable, Object, Kernel, BasicObject]