CSC/ECE 517 Fall 2012/ch1b 1w54 go
SaaS Ruby 101
Introduction
The Coursera video series were created to give free college level lessons to anyone with internet access. The Saas video discussed in this wiki page is the Ruby 101 provided by California University. The video covers the fundamentals of the Ruby language and the basic concepts needed to write programs. More information about the language can be found at its Wikipedia page.
The sections below will highlight the key points of the video lecture and try to help provide further detail surrounding the concepts in the video. Some of the examples used below are taken directly from the lecture slides present in the coursera video for consistency.
What is Ruby
The Ruby language is an interpreted scripting language, meaning that there is no compile time as in other languages. Without the compile time, Ruby programs lose many warnings that programmers rely on for safety however as long as you stick to the Ruby conventions, these pitfalls can be avoided. It is an object oriented language as well. Ruby follows the object oriented paradigm so closely that everything in Ruby in an object. What this means is that all operations on objects are essentially method calls on objects. In addition this gives Ruby objects the ability to ask about themsevles via reflection. This is one of the keys to properly understanding Ruby.
Ruby is a dynamically typed language meaning that the type of some things may not be determinable until run time. All objects have types but variables do not have to have types associated with them. It is possible to see a variable that is given the value of 1 (Ex. x = 1) and then later in the code the variable is then given a string value (Ex. x = 'Hello World'). The fact that Ruby is a dynamic language gives the developer immense power and can be used to leverage code modification at runtime which is referred to as metaprogramming. The idea of metaprogramming is so pervasive in the language that you can consider all programming in Ruby to be metaprogramming.
For information on metaprogramming specifically applied to Ruby, please consult the references section.
Naming conventions and general syntax
Ruby makes use of two naming conventions that you might be familiar with from experience with other languages. Upper camel case and snake case are used to help differentiate class names and methods/variables. This helps someone who is reading Ruby code to know when you're referring to a class versus a method. In addition to these general naming conventions Ruby also allows you to leverage the question mark and exclamation mark characters to help signify what the method is doing. A question mark usually signifies a Boolean method where an exclamation mark signifies a dangerous method. Constants are always defined with full capitol letters and are scoped to only the places where they're defined, for example to the defining class or method. Global variables in Ruby are always defined with a leading dollar symbol ($). One item the video does not go over but will be helpful to Ruby programmers is that single line comments in ruby begin with the hash (#) character. Ruby also has multiline comments like other languages which are denoted with the tokens =begin and =end. Please see the referencessection for more information on comments in Ruby.
Naming Convention Examples
- UpperCamelCase
Conventionally used to define a class. Upper Cammel Case requires that the first letter of each word be capitolized.
Ex. class MyNewClass
- snake_case
Usually used to define methods or variables contains a snake character or underscore between words.
Ex. def learn_conventions
- def how_many_items?
The question mark added to the end of this method definition helps to signal the programmer who may be reading this code that this will return a Boolean or predicate value
- def save!
The question mark added to the end of this method definition helps to signal the programmer that this method does something destructive or can not be reversed.
When writing or learning about Ruby, you may hear the term "syntactic sugar". What this refers to is the parts of a "normal" declaration of code that may seem superfluous. In Ruby, this superfluous code can be ignored and as long as the code still makes relative sense, the interpreter will pick up the code and continue processing. This is a big deal because it helps Ruby code become more readable to someone who may not be familiar with programming and also makes the code flow better. An example of this is when dealing with a new line in Ruby. While the presence of a semicolon or the keyword end will always signal the end of a statement, a newline can be substituted in most cases. This is similar to the flexibility that Java provides with single statement if and while loops. The beginning and ending brace characters were not required because the Java compiler can skip over this. While it is true that you can reduce the code you write to make the code more humanly readable, there are times when you will want to still include some of the optional syntax in more complex methods. The point that Armando makes in the video lecture is that you want to be defensive with this, when in doubt add the optional syntax.
Syntactic Sugar Examples The sample code listed below is a factorial example from the references links below written with normal Ruby conventions of removing unneeded syntax. Notice that it is missing some of the elements that are common in other languages
def fact(n) if n == 0 1 else n * fact(n-1) end end
Variables
In Ruby local variables do not have a value until they are explicitly given one. This means that all local variables, this includes instance and class variables, must be assigned before use otherwise they are have the value of nil. The keyword nil in Ruby is exactly the same as null in other languages. Variable definitions are not valid in Ruby, you will never see a class name prior to a variable. Constant variables are always scoped to where they are defined (local or class) however, Global variables are accessible anywhere and at any time. In Ruby just like other languages you want to avoid the use of global variables if at all possible.
When working with variables in Ruby it is important to remember that in Ruby objects have types but the variables that you use do not. This can be a bit difficult to wrap your head around but, it is a fundamental aspect of how Ruby works. You can think of the variable you created as an untyped container and that while you can put any specific object into that container it does not make the container into that object.
Strings in Ruby are treated very similarly to how they are treated in Java. A string can be defined in a number of ways. You can leverage the single quote characters which will define that there are just characters in the string but, you can also combine the use of double quotes with the hash brace characters to include evaluated statements into your string. Ruby also of course includes a way to escape the double and single quote characters with the %Q{} and %q{} syntax respectively.
Ruby also includes a special type of string called a symbol. Symbols are essentially [en.wikipedia.org/wiki/Immutable_object immutable] strings and their value is just themselves. They begin with a colon and then a lowercase name, (e.g. :symbol is a symbol). Although symbols are a special type of string, they are not actually strings. A symbol and a string with the same name will not be equal to one another. Symbols are used to denote something as being special, it specifies that the name used is not arbitrary and is one of a fixed set.
Variable Examples
Valid variable declarations
x = 3 x = 'foo' x = [1, 'two', :three] #The three lines above are all valid because the variable x does not have a type DEBUG_MODE = true $DEBUG_MODE = true #Global variable - make every effort not to use this
Invalid declarations
Integer x Integer x = 1
String examples
mystring = 'Hello World' # Value: Hello World a = 1 # Integer value used in the next line's example mystring = "Hello World #{a+1}" # Value: Hello World 2 mystring = %Q{"Hello World"} # Value: "Hello World" mystring = %q{'Hello World'} # Value: 'Hello World'
An example of a Symbol
mystring = :hello
String and symbol interaction examples
:hello.to_s == "hello" "hello".to_sym == :hello :hello == "hello" #Always evaluates to false
Arrays and Hashes
Arrays are fairly similar to most other languages in that you have access to the usual properties although in Ruby they're actually method calls. A Ruby array can have any number of different types included in them. This is drastically different from other languages where you have to declare the type of objects that are stored in the array. Ruby also implements hashes and much like their array counterparts, have all of the normal hash methods defined but again do not have to have consistent types across keys and values. In practice, you generally try to keep the types consistent across the elements of your array or hash but, this is a convention and is not required by the compiler. In some programming cases, you will not be able to do this.
Array Examples
x = [1, 'two', :three] x[1] == 'two' x.length == 3
Hash Examples
w = {'a' => 1, :b => [2, 3]} w[:b][0] == 2 w.keys == ['a', :b]
Methods
In Ruby, everything in method calls is passed by reference except for fixnums. The last statement in a method call is returned at the end of the method call. This touches on the syntactic sugar that we mentioned before, it is not necessary to specify the keyword return although it may be helpful to do so in a more complex application. You can specify default values for your input parameters however, they must come after the variable input parameters otherwise the Ruby interpreter will not be able to properly parse the method definition. It is also possible to create a method on a single line if the method is short enough, you simply need to end each statement with a semicolon however, it is rare to see this in actual use.
Method examples
def foo(x,y) return [x, y+1] end
def foo(x, y=0) [x, y+1] end
Results of calling the above methods
a,b = foo(x,y) #a is assigned the value of x and b is assigned the value of y+1 a,b = foo(x) #a is assigned the value of x and b is assigned the value of 0+1 or 1
Comparisons and regular expressions
Ruby provides all of the normal comparison operators for use. This also includes the '=~' and '!~' operators that are used with regular expressions in Ruby. Ruby defines true, false and, nil as constants. False or nil are the only things in Ruby that evaluate to false everything else evaluates to true. This is different from other languages where the empty string or the value 0 will evaluate to false as well.
Ruby fully supports regular expressions the syntax used is borrowed from Perl, Python and, other languages. The =~ will compare to a regular expression and !~ will define a not equal. Please see the references section to find more information on Ruby regular expressions and a useful site that can help you generate your regular expressions in Ruby that is mentioned in the video. When working with regular expressions in Ruby, you're generally comparing to a string. There are various ways to represent a string in Ruby. Please refer to the variables section for more information on strings. A regular expression in Ruby will return false if there are no matches and will return a set of objects if true. The set of objects that is returned is from $1..$n parenthesized groups which are all of the groups that matched on the expression.
Regular expression example
"fox@berkeley.edu" =~ /(.*)@(.*)\.edu$/i #This code will capture ($1 == 'fox', $2 =='berkeley')
References
A helpful site that provides an easy to access interface to execute ruby code
This book discusses Ruby and its' syntax
Coursera - SaaS - 3.5 - Ruby Metaprogramming
Object oriented programming in Ruby
Rubular - This is a website that helps you generate regular expressions in Ruby
Ruby API documentation on regular expressions
Ruby regular expression tutorial