Register

If this is your first visit, please click the Sign Up now button to begin the process of creating your account so you can begin posting on our forums! The Sign Up process will only take up about a minute of two of your time.

Results 1 to 9 of 9
  1. #1
    Senior Member
    Join Date
    Jun 2005
    Location
    Atlanta, GA
    Posts
    4,146
    Member #
    10263
    Liked
    1 times
    Who Should Read This?

    This tutorial is meant specifically for people who have experience with programming in general, and object-oriented programming in particular. It is extremely fast, and meant solely as a way for experienced OOPers to get acclimated to Ruby's implementation of common concepts. A few of Ruby's special tricks are, however, introduced, including its iteration principles, which are different from typical implementations.

    Because I'm familiar with Java, PHP, and C++, I'll tend to explain things with respect to these. I don't know any Perl or Python, so I'm afraid I can't make comparisons to those most of the time. I'll also try and point out influences from other languages (especially Lisp and Smalltalk) where I can as a matter of interest, but I can only do so much :-)

    Why Read This?

    Well, I'd advise reading it to switch quickly from PHP or Java into Ruby, but I'm mostly writing it because I want to write a tutorial for Ruby on Rails, and I don't want to leave people hanging on how to deal with Ruby when I start explaining how Rails works.

    Introduction

    Ruby has been in quiet development since the early 1990s, and more or less exploded in popularity in the mid 2000s when Ruby on Rails came out. The interesting thing about Ruby is that its development follows the `Principle of Least Surprise'. More specifically, it follows the `Principle of Matz's Least Surprise', Matz being the creator of Ruby. It can then be inferred that Ruby is essentially run in a `benevolent dictatorship' style, similar to the way that the Linux kernel is run.

    Installing

    On Linux, find the package for your distro and install it. On Gentoo an `emerge ruby' will do you good. On Windows, the One-Click Ruby Installer
    will do the trick. And on Mac OS X, it technically comes with the OS, but of course that version is broken. While you should be able to go through this tutorial with no trouble, Rails will have trouble with OS X's version. They advise you go through
    this little guide to fix it. It also covers installing Rails, but the only part you need to be concerned with is the part on Ruby, and possibly RubyGems.

    [minicode]irb[/minicode] and [minicode]ri[/minicode]
    irb is Ruby's interactive interpreter, and ri is Ruby's online information system. Irb is fairly simple to use; go to the command-line and run [minicode]irb[/minicode]. You'll get a prompt something like this:
    Code:
    irb(main):001:0>
    Type some Ruby and rock on! irb is usually equipped with GNU Readline support, (unless you're running the default OS X version), so hit `up' and you'll see your previous statements, `down' and you'll see later ones, just like a regular shell. In addition, if you run [minicode]irb -r irb/completion[/minicode], you get the magic that is automatic tab-completion. It is modelled after BASH rather than Windows's cmd, so if you type, say `"power".' and hit Tab, nothing will show up. If you hit Tab twice, though, you'll get a list of all methods that match.

    To use ri, you can type `ri classname' to get the documentation on that class. For example, [minicode]ri String[/minicode]. Unless you have [minicode]more[/minicode] or [minicode]less[/minicode] installed (usually yes on Linux and OS X, and no on Windows), you'll get a dump of text. If you have the above two, you can scroll through the output. If you have an ANSI compatible terminal and less/more support it (cmd is not ANSI compatible), you can run [minicode]ri -f ansi ClassName[/minicode] and you'll get colorized output. Finally, if you want to check out instance method documentation, you can type [minicode]ri ClassName#methodName[/minicode] to get to that.

    Note that on Windows, the program fxri is a UI for both ri and irb that allows you better access to the documentation than ri on the command-line does.

    That said, let's dive in!

  2.  

  3. #2
    Senior Member
    Join Date
    Jun 2005
    Location
    Atlanta, GA
    Posts
    4,146
    Member #
    10263
    Liked
    1 times
    Object Orientation

    Ruby is fantastically object-oriented. This isn't Java's everything-is-an-object-unless-I-don't-want-it-to-be. It isn't PHP's well-you-could-use-objects-but-you-can-do-fine-without-them. And it isn't C++'s use-objects-but-you-don't-have-to-if-you-want-to-save-on-performance. This is pure, absolute object orientation. Everything is an object. What do we mean when we say everything? We mean everything. Examples:
    Code:
    >> 5.3.ceil
    => 6
    >> 4.gcd( 10 )
    => 2
    >> "power".length
    => 5
    Numbers and strings, though they are primitives in other languages, as you can see, are objects in Ruby.

    As with any language, there is a value for `null' or `nonexistent'. In Ruby, it is called `nil' (influence: Lisp). But remember, we said everything is an object! And, sure enough:
    Code:
    >> nil.class
    => NilClass
    So, when we say everything is an object, we mean *everything is an object*. More examples of that later.

    The Messenger Shall Unto the Receiver Deliver

    In Ruby, the concepts from Java, C++, and PHP of `objects' and `methods' carry over perfectly well. As exhibited above, the syntax for method invocation is also similar. Conceptually speaking, however, Rubyists like to think of method calls as the equivalent of sending the objects signals (influence: Smalltalk). One interesting side-effect of this is a special method-calling syntax:
    Code:
    >> 4.gcd( 10 )
    => 2
    >> 4.gcd 10
    => 2
    As you can see, if you don't want to chain method calls, you can pass arguments without parentheses as delimiters. Chaining method calls can often be used in Ruby, though, and in those cases the parentheses are required until the last method invocation in the chain.

    Return Values and Typing

    Returning values in Java, C++, and PHP is always done via a `return' statement that looks something like this:
    Code:
    C++/Java: return myVariable;
    PHP: return $myVariable;
    In addition, in C++ and Java, your method will be declared something like this:
    Code:
    public int myMethod() {} // Java
    public:
        int myMethod(); // C++
    So you specify a return type.

    Like PHP, however, Ruby is dynamically typed. Thus, functions are defined without a return type, variables are defined without a type, and function parameters also don't have a type. All they have is a name. Unlike PHP, however, variable names are not prefixed by a `$' (with one exception; that comes later).

    This leads us to the way return statements work in Ruby. A return statement is perfectly doable:
    Code:
    def myFunction
        return 5
    end
    However, in Ruby, even if there is no return statement, whatever the last statement in the function evaluates to is what is returned (influence: Lisp and Smalltalk). So, the above could be rewritten:
    Code:
    def myFunction
        5
    end
    Basically, the last (and only) thing evaluated in this function is `5', which evaluates to itself, which means the function returns `5'.

    By extension, every function evaluates to *something*, even if that something is `nil'.

    Function and Class Definitions

    Function and class definitions are more or less simple:
    Code:
    def myFunction( param0, param1, param2 )
    end
    
    class myClass
        def myMethod( param0, param1, param2 )
        end
    end
    A constructor in Ruby is the method with the special name `initialize':
    Code:
    >> class MyClass
    >> def initialize
    >> puts "This is the constructor."
    >> end
    >> end
    => nil
    >> MyClass.new
    This is the constructor.
    => #<MyClass:0xb7a24fc8>
    As you saw above, even the class declaration evaluated to `nil'. Clearly, as is visible above, instantiation of a class is done by sending the `new' signal to the `MyClass' class object. Yes, even the class itself is an object, of type Class:
    Code:
    >> MyClass.class
    => Class
    Also visible in the definition of the initialize method is that if your function takes no parameters, you do not have to put empty parentheses after the function declaration.

    Ruby also went the smart way and supports both function overloading *and* the concept of optional parameters:
    Code:
    def myFunction( tester, testerPower )
    end
    
    def myFunction( tester, testerPower, superCoolness, defaultCoolness = 0 )
    end
    defaultCoolness in the second myFunction will get the default value of 0 if none is passed in, i.e., if the function is called like so:
    Code:
    myFunction( 1, 2, 3 )
    Stunning. A few more details of methods bear mentioning. First of all, like C++, Ruby supports operator overloading -- namely, making classes react to certain operators in their own way. So, for example, the string class has its own implementation of the `*' operator:
    Code:
    >> "test" * 5
    => "testtesttesttesttest"
    This is done with fair ease:
    Code:
    >> class MyClass
    >> def ==( other )
    >> print "Adding " + other.to_s
    >> end
    >> end
    => nil
    >> MyClass.new == OtherClass.new
    This is the constructor.
    This is the constructor.
    Adding #<MyClass:0xb7a1931c>=> nil
    First of all, what just happened? Haven't we already defined MyClass? Yes. A moment, and we'll get back to that. Here, we see that overloading an operator is merely a matter of defining a method with a name that is the operator (==, +, *, /, %, etc). In addition, we see both constructor calls, followed by the printing of the statement we had in the operator, followed by the result of evaluating the operator, which is nil (since `print' evaluates to nil).

    Now, back to the redefinition of the class. Ruby allows you to do the above trick. The truly awesome thing about this trick is that it doesn't redefine the class, it *adds to it*. So I just added the == operator to MyClass. This is why we see the constructor we defined before still running happily. This doesn't just work with your classes, though. You can add behaviors to Ruby's built-in classes, as well:
    Code:
    >> class String
    >> def magicness
    >> puts "POWAH!!"
    >> end
    >> end
    => nil
    >> "test".magicness
    POWAH!!
    => nil
    The final point to be made about methods is that they can have some pretty strange characters in their names. Two characters in particular come up repeatedly -- ? and !. This is a side-effect of looking at the method invocation as the passing of a message. I want to ask a String if it's a type of Integer or a kind of Object:
    Code:
    >> "test".kind_of? Integer
    => false
    >> "test".kind_of? Object
    => true
    The exclamation point, on the other hand, is generally used to differentiate between a destructive and a nondestructive version of the same method:
    Code:
    >> test = "power"
    >> test.gsub "po", ""
    => "wer"
    >> test
    => "power"
    >> test.gsub! 'po', ''
    => "wer"
    >> test
    => "wer"
    The second call, as you see, modified the test object as well as returning the result of the replacement. Also notice that one of the method calls used '' instead of "". Like in PHP, this is perfectly acceptable.

    Side note: also as in PHP, the double-quoted form allows embedding of variables:
    Code:
    >> test = 5
    >> "This is a test: #{test}."
    => "This is a test: 5."

  4. #3
    Senior Member
    Join Date
    Jun 2005
    Location
    Atlanta, GA
    Posts
    4,146
    Member #
    10263
    Liked
    1 times
    Enforced Style

    Ruby essentially enforces coding style. What does that mean? Well, let's look at some other languages; specifically, let's look at Java and C++. In these two languages, you generally declare member variables with their visibility:
    Code:
    private int magicalMemberVariable; // Java
    private:
        int magicalMemberVariable; // C++
    Leaving off the visibility can result in strange visibilities being applied. In Java, the default visibility is `package protected', which is the somewhat odd idea of accessible to everything in that package, inaccessible for everything outside. In C++, visibility defaults to private in classes and public in structs.

    Still, in both of these languages, it is often a good idea to put the visibility down explicitly to make it clear what visibility it is (although in Java this is partly impossible, since package protected cannot be explicitly declared).

    In addition to the above, certain other stylistic tendencies have come up in the C++ and Java worlds. Constants, for example, tend to be all uppercase:
    Code:
    public static final int MY_CONSTANT_FIELD = 5; // Java
    Instance variables will often be prefixed by some character, such as `m', to indicate that they are members of the class:
    Code:
    int mMagicVariable; // C++
    Finally, there doesn't really seem to be a set way to differentiate class (or `static') variables as far as naming conventions are concerned. In Java, the differentiation between normal variables, instance variables, and static variables is often left to the IDE to do, since most modern Java IDEs such as Eclipse and IDEA provide special highlighting for these different kinds of variables based on code analysis.

    Ruby, as you might have noticed until now, doesn't exactly love being verbose. It's not a `shorten-everything' language like C (the fact that we use the `end' keyword instead of curly braces to indicate the end of a block should be indication of that), but it does try to save you typing where possible. In addition, Ruby enforces code style.

    What does that mean? Well, take an instance variable, for example. Obviously, variables aren't declared in Ruby. So how would you indicate an instance variable? Turns out, as with any other variable, you just use it. But if you're not declaring it, how do you say it's an instance variable? Ruby deals with this by imposing a convention: all instance variables begin with an `@' symbol. Thus, this code:
    Code:
    class Magic
        def myMagic
            @power = 3
        end
    end
    Is similar to this code:
    Code:
    public class Magic
    {
        private int power;
        
        public void myMagic()
        {
            power = 3;
        }
    }
    There is, of course, a difference between the two. In Ruby, before you call myMagic, whatever instance of the Magic class you just created doesn't have a `@power' instance variable. It's only *after* you call it that it exists. But that doesn't matter too much, since all instance variables are private.

    So that's one enforced convention. What else is there? Class variables. Class variables (static variables in Java) are variables that are shared between instances of a class. These variables start with two `@' symbols:
    Code:
    class Magic
        @@staticVar = 0 # make sure it exists
        
        def Magic::myStaticMethod
            @@staticVar += 1
            
            puts "Static method call " + @@staticVar.to_s
        end
    end
    In the above code, we make sure that the @@staticVar variable exists, and then we're set. Calls to Magic.myStaticMethod (or Magic::myStaticMethod) will have the desired result. Notice that Magic.myStaticMethod and Magic::myStaticMethod are interchangeable syntaxes. Thus, it is possible, if you prefer, to make it clearer what methods you're calling statically, by using :: to call the method instead of `.'. This is similar to the way C++ has of accessing static methods.

    Even more conventions are enforced by Ruby beyond these two, however. We'll go through them fairly quickly:
    * Constants always start with an uppercase. HELLO_WORLD is a constant, as is HelloWorld. Does that second one look like a class name? Yes, as mentioned before, classes are constant instances of the Class class. Cool? Yeah.
    * Global variables always start with a `$'. $overallName is a global variable.

    If you want to escape the fact that an uppercase letter means a constant, you can prefix your variable with _. Thus, _Hello is not a constant.

    Accessors and Mutators

    Ruby's accessors and mutators are more similar to C#'s than anyone else's, in the sense that the difference between the member variable being accessed/mutated and the method itself is essentially nonexistent to users outside of the class. For example:
    Code:
    class MyClass
        def myName=( newName )
            @myName = newName
        end
        
        def myName
            @myName
        end
    end
    This defines an accessor and mutator for the variable `myName'. On the outside, we can use this like so:
    Code:
    >> test = MyClass.new
    => #<MyClass:0xb7aaa6c4>
    >> test.myName
    => nil
    >> test.myName = 5
    => 5
    >> test.myName
    => 5
    Fairly straightforward, right? But anyone who has had to code extensively in an OO language knows how much of an incredible pain it is to sit down and write accessors and modifiers for all the member variables that need them. So Ruby, as usual, provides a shortcut:
    Code:
    class MyClass
        attr_accessor :myName
    end
    This is essentially the same as the above code. From six lines to one. Shiny. But what if I just want to have a setter?
    Code:
    class MyClass
        attr_writer :myName
    end
    Just a getter?
    Code:
    class MyClass
        attr_reader :myName
    end
    And what in the world is that : in front of the damn thing? Thus are we brought unto the next section.

    Data Types


    Really quick, it bears mentioning that Ruby has bunches and bunches of data types (classes), but that there are a few specific ones you should know about.

    1. The string: same as any other string, double or single-quoted. Double-quoted ones can have variables embedded in them if wrapped in #{}.
    2. The symbol: essentially a string, except you declare you won't be doing anything with it except for using its textual value. Symbols are cheaper than strings in terms of memory and speed. Symbols also evaluate to themselves. Influence? Lisp.
    3. The array. Defined as [1, 2, 3, 4], it's just a list of numbers, accessed linearly. These are zero-based, as in most other languages, so accessing arr[0] of an array will get you item 0 in the array. Note that the [] operator is overloadable, as in C++.
    4. The hash. Defined as { :key => "value", :key2 => 3, :key3 => "gzzt" }. Essentially the same as Javascript and PHP arrays, Java Maps, and C++ hash_maps (most closely). Accessing an item in a hash, thanks to operator overloading, is just hash[:key].
    5. The array of hashes. If you want to start off an array of hashes, you have the shorthand option of writing [ :key => "value", :key2 => 3, :key3 => "gzzt" ]. This is the same as saying that you're creating an array whose first value is the hash containing those key-value pairs.

    Before we get to iterating over these and other things, we'll go for a quick wrapup of the class phenomenon.

  5. #4
    Senior Member
    Join Date
    Jun 2005
    Location
    Atlanta, GA
    Posts
    4,146
    Member #
    10263
    Liked
    1 times
    Visibility

    Though methods default to public (except initialize, which defaults to private), and instance and class variables default to private, there are ways of changing these. Actually, there are only ways of changing methods, since there's no significant difference between using a member variable via an accessor and using it directly. To modify visibility, we do something similar to what we did to create accessors:
    Code:
    class MyClass
        def mySuperPrivateMethod
            puts "magic!"
        end
        private :mySuperPrivateMethod
    end
    Voila! The method is now private. The same applies to the `protected' keyword. It bears mentioning that, unlike the weirdness that is Java and C++ accessing, making a method private in Ruby means it can only be used without a qualifying object before it. So you can't call a private method on another instance of your class from within your class. Private method means you can only call it on yourself, period. Making `new' private is how you avoid instantiation.

    Inheritance

    Subclassing in Ruby is done using `<':
    Code:
    class MyString < String
    end
    Above, MyString is a subclass of String. See Java's `extends' and C++'s `:'. Note that there is no multiple inheritance in Ruby. Instead, you can use mixins, which are strange and froody (as the Gospel of Tux would put it). Mixins basically let you add a set of methods to a class that have been defined elsewhere. Such mixins as Iterable will give you the equivalent of interfaces in Java, except with prebuilt implementations. Rock onwards.

    And Now, To Iteration

    So finally we come to iteration, which should be fairly basic, but for some reason I left it for last. The thing is, iteration is `different' in Ruby. But, it's very cool. So cool, in fact, that the Javascript Prototype framework extended Javascript's builtin classes with Ruby iterators, and provided a Hash class that can use these, as well.

    So, the most common iterator in Ruby is the `each' iterator. The thing about iterators is, they're methods. They are, however, methods that pass control over to blocks of code that do stuff with each value. Magic! But let's see how it works:
    Code:
    >> test = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
    => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
    >> test.each { |number| puts number }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    So, for each item, we call the block of code. We pass in the argument `number', with the arguments being specified between ||s, and then the block of code does something with it. Cool? Yeah.

    Iterating over hashes shows us something else that's interesting:
    Code:
    >> test = { :key => 'value', :key2 => 'value2', :key3 => 'value3' }
    => {:key=>"value", :key2=>"value2", :key3=>"value3"}
    >> test.each do |key, value|
    >> puts key.to_s + "::::" + value.to_s
    >> end
    key::::value
    key2::::value2
    key3::::value3
    => {:key=>"value", :key2=>"value2", :key3=>"value3"}
    Notice two things. First of all, this block took two arguments -- a key and a value. Second of all, we called to_s on both of them. Why? First of all, you can't use the + operator directly on a symbol, which is what the keys are. Second of all, as with any hash, both the key and the value could be any object. Thus, we use to_s to make sure we get the string representation of that object.

    Also notice that instead of using curly braces, we used `do..end'. This is the way you make multiline blocks, usually, but I wanted to show it here even though it wasn't necessary.

    Okay, so we know how to iterate over an array. The first thing we ask is, how can we iterate over a certain amount of numbers? Well, that's easy:
    Code:
    >> for i in (0..9)
    >> puts i
    >> end
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    => 0..9
    We just ran into another type of object -- the Range class. This class represents a range of numbers, and lets us do some magical things with it, not the least of which is the above. But... How does it work? What is this special for... in loop? Turns out, it's just a shortcut for .each:
    Code:
    >> (0..9).each { |number| puts number }
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    => 0..9
    Coolness! So, then can we... Sure we can!
    Code:
    >> for item in [12, 14, 16, 18]
    >> puts item
    >> end
    12
    14
    16
    18
    => [12, 14, 16, 18]
    I love the smell of a well-implemented language in the morning...

    But the iterators can do more, too. Iterable classes also have a method `collect', which not only iterates through the items, but also collects the results of the blocks into a new array:
    Code:
    >> (1..5).collect { |number| cat * number }
    => ["cat", "catcat", "catcatcat", "catcatcatcat", "catcatcatcatcat"]
    And there's still more! The detect iterator will keep iterating until the block evaluates to something non-false. Then, it will return that value. If it never hits a non-false result, it will return nil:
    Code:
    >> (1..100).detect do |number|
    >> puts number
    >> number == 13
    >> end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    => 13
    We see here it went through from 1 until it hit 13, then stopped and returned 13.

    If you need to access the items with their index, you can call each_with_index, which passes the argument the item and the index, in that order. The find method will do the same as detect (whichever makes more sense to you, you can use). findAll works similarly to find and detect, except instead of returning a value when the block evaluates to true, it collects all the values for which the block evaluates to true and returns an array with these. member? checks whether an item is a member of the collection.

    There are more of these, all of which can be found in the reference for the Enumerable module, part of the Pragmatic Programmer's Guide.

    A warning on blocks before we go on: variables in blocks are in the same scope as the block is in. So blocks DO NOT have their own scope. This means any changes to a variable in the block affects variables outside the block. THIS INCLUDES THE BLOCK ARGUMENT!!

    Phew. So that's iteration, more or less, in a nutshell. Now, really quick...

    Yielding to Those Who Know

    Because if you're reading this you've probably already programmed, you're probably wondeirng how you can create these cool little functions that pass control over to blocks. The key is the `yield' statement. Wherever you want to pass control on over to a block, you write `yield'. If you want to pass arguments, you list them after `yield'.
    Code:
    >> def myCoolFunction
    >> (1..5).each { |number| yield number }
    >> end
    >> myCoolFunction { |thing| p thing }
    1
    2
    3
    4
    5
    => 1..5
    Nothing too hard to that one, right? Finally, we're wrapping up...

  6. #5
    Senior Member
    Join Date
    Jun 2005
    Location
    Atlanta, GA
    Posts
    4,146
    Member #
    10263
    Liked
    1 times
    Syntactic Semantics

    Now, a whirlwind of little details about Ruby's syntax.
    (1) Semicolons. Semicolons are not mandatory in Ruby, though they can be added. Ruby thus guesses where your statement ends. Basically, if a statement *can* end at the end of the line, Ruby assumes it does, unless you put a `\' there, which tells it to keep looking. You may dislike this, but always remember that in Matlab you have to write `...' to do that, so you should stop whining :-P
    Examples:
    Code:
    5 + 5 +
        5 # evaluates to 15
    5 + 5 # evaluates to 10
        + 5 # evaluates to 5
    5 + 5 \
        + 5 # evaluates to 15
    (2) If statements look like a cross between various languages:
    Code:
    if test
        # do stuff
    end
    If it makes you happy, you can put parentheses around the test to be all C-like. Again, notice that instead of curly braces you use end to end the statement.

    (3) Someone thought it was a good idea to make `else if' be `elsif'. This is my number 1 biggest annoyance with Ruby. I think it says a lot about the language that my biggest annoyance is a spelling gripe:
    Code:
    if 5 == 4
        # print something about hell having frozen over or math being upside down or
        # something
    elsif 3 == 2
        # do something similar to the above
    else
        # print something about everything being right with the world
    end
    (4) Post-conditionals! You can qualify a statement after-the-fact. This is one of the coolest things (in my innocent mind) in the language, because it makes it read more like English, which makes me happy. This comes in part from Perl, I believe.
    Code:
    puts "you suck" if you.sucks?
    puts "you rock" if ! you.sucks?
    (5) ! is still the not operator. However, it will show up in method calls sometimes to indicate a method that will change the value of the object it is being called on.

    (6) You can return multiple values at a time into multiple variables. Just return an array, and then on the other side, you can do this:
    Code:
    index0, index1, index2 = functionWithArrayReturn
    index0, index1, and index2 will then be populated with the first three fields of the return value. If you provide more items on the left-hand-side of the assignment operator than there are items in the array, the extra items on the left-hand-side will be nil. If there are more items in the array than there are items to be assigned, any extra items in the array are ignored.

    (7) There are three printing functions in Ruby: p, puts, and print. p will print the value with some indication of its type. Strings, for example, get ""s around them. Hashes get printed as they should. This is close to what print_r does in PHP, I believe. puts prints the result of running to_s on its argument (much like System.out.println does with toString in Java). print is the same as puts, except it doesn't add a newline to the end of the string. Thus, it is equivalent to PHP's echo, Java's System.out.print, C++'s cout, and C's printf (though C's printf has that weird complex substitution syntax, whereas Ruby has the embedded variable syntax instead for strings).

    Extra Bits of Coolness

    A few last thingies that bear mentioning, as I think of them. First of all, when I said everything was an object above, you might have been wondering what in the world we were doing defining functions outside of classes if everything was an object. It turns out, when you aren't inside a class, you're actually already inside a class! You're in the Object class, which is the superclass of all other classes. That means if you define myFunction in the regular scope, then your subclass can use it as a method. Kiinda cool...

    Second of all, if everything's an object, why aren't methods? Well, they are! You can get a handle to a method object by calling, on your instance, the `method' method with a parameter that's the symbol for the method you want:
    Code:
    >> class MyClass
    >> def myAwesomeMethod
    >> puts "power!"
    >> end
    >> end
    => nil
    >> obj = MyClass.new
    => #<MyClass:0xb7a9605c>
    >> obj.method :myAwesomeMethod
    => #<Method: MyClass#myAwesomeMethod>
    Moreover, you can then *run* the method via its `call' method:
    Code:
    >> obj.method( :myAwesomeMethod ).call
    power!
    => nil
    And, to get a list of methods in any object, you can just run:
    Code:
    >> obj.methods
    => ["to_a", "respond_to?", "type", "protected_methods", "eql?",
    "instance_variable_set", "is_a?", "hash", "to_s", "send", "class",
    "require_gem_with_options", "tainted?", "private_methods", "__send__",
    "untaint", "id", "inspect", "instance_eval", "myAwesomeMethod", "clone",
    "public_methods", "extend", "freeze", "display", "__id__", "testMeth", "==",
    "methods", "require_gem", "method", "===", "nil?", "dup", "instance_variables",
    "instance_of?", "myCoolFunction", "myName", "object_id", "=~",
    "singleton_methods", "test", "myName=", "equal?", "taint", "frozen?",
    "instance_variable_get", "require", "kind_of?"]
    Last thing, I think: ranges. Ranges are useful, but what's the real use of a range if you can't test whether a number is in it? Turns out, you can. The === operator is used to check whether an item is in a range:
    Code:
    >> p "sweetness!" if (1...6) === 5
    "sweetness!"
    => nil
    Note that the operator only works in one direction, because you want to call the === operator of the range, not of 5. When you're not dealing with ranges or similar things, === is equivalent to ==.

    Okay, maybe I'm not done. Regular expressions are defined between //s in Ruby, much like in Javascript and Perl, and the ~= operator runs a match (as does the match method). !~ is the inverse of ~=. Additionally, the ++ and -- operators don't exist, though +=, -=, /=, etc, do. And finally, we have the <=> operator, which is the comparison operator -- the equivalent of Java's compareTo method. It returns 1 for greater than, 0 for equal to, and -1 for less than.

    Also worth noting is the fact that almost all operators are methods. So, these are interchangeable:
    Code:
    5.+ 3 <-> 5 + 3
    arr[5] <-> arr.[] 5
    5 == 3 <-> 5.== 3
    The array syntax for [] is just syntactic sugar.

    That syntactic sugar also works for Strings, oh by the way. Specifically, substrings can be acquired via [minicode]"test"[0, 1][/minicode] <- two arguments!! Yes, that means you can define the [] method to take two arguments. Note that "test"[0] will return the character code of the character at the first position. This is a number, not a character (since in Ruby there is no `character' type).

    And finally, polymorphism in Ruby is implemented as a has-a question rather than an is-a question. What does that mean? That means in Ruby, it's better to ask an object whether it has a particular method (the respond_to? method that every object has can let you answer that question) rather than asking it whether it is a certain type of object (the kind_of? method answers that question).

    And that's about all I can think of for the moment! Ruby is an exceedingly shiny language, and there are more references for it on the following sites:
    * Why's (Poignant) Guide to Ruby
    * Programming Ruby: The Pragmatic Programmer's Guide
    * Intro to Ruby, originally by Matz, the creater of Ruby himself, translated to English.
    * Why the Lucky Stiff's 15-minute interactive Ruby tutorial (highly recommended, due to its shortness).


    Phew. That was about 5 times longer than I was expecting...

  7. #6
    WDF Staff smoseley's Avatar
    Join Date
    Mar 2003
    Location
    Boston, MA
    Posts
    9,729
    Member #
    819
    Liked
    205 times
    Meh... I like Java's syntax better.

  8. #7
    Senior Member
    Join Date
    Apr 2006
    Posts
    146
    Member #
    13110
    Liked
    1 times
    nice tutorial, even though i dont use the language

  9. #8
    WDF Staff Wired's Avatar
    Join Date
    Apr 2003
    Posts
    7,656
    Member #
    1234
    Liked
    137 times
    my brain hurts...
    The Rules
    Was another WDF member's post helpful? Click the like button below the post.

    Admin at houseofhelp.com

  10. #9
    Senior Member Stylise's Avatar
    Join Date
    Jul 2005
    Location
    Mount Martha, Australia
    Posts
    229
    Member #
    10679
    mine too, but great tutorial


Remove Ads

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
All times are GMT -6. The time now is 10:51 AM.
Powered by vBulletin® Version 4.2.3
Copyright © 2019 vBulletin Solutions, Inc. All rights reserved.
vBulletin Skin By: PurevB.com