PRIVATE METHODS AND VARIABLES

To make methods and instance variables private in Python, one *always* needs to write __ in front of the name. In Ruby, instance variables are private by default. Methods defined after the method call "private" are private.

FUNCTIONS AND METHODS

There are no functions and methods separately in Ruby; all of them are methods. In Python, e.g. len() is a function, but items() is a method. Inconsistent solutions such as these remind me of PH*, *shiver*.

Python:

str = "Hello world"
print str.count("o"), len(str) # prints 2, 11 – why not str.len()?

Ruby:

str = "Hello world"
puts str.count("o"), str.length # prints 2, 11

"SELF"

In Python, one needs to write "self" as the first parameter of a method (alike Perl). Furthermore, Python doesn't even require the variable name to be "self", it can be "poop_rules" for all Python cares. In Ruby, "self" is automatically available in a similar fashion as "this" in C++.

Additionally, instead of the method call "self.method", the shorter form "method" can be used.

NOTATION OF INSTANCE VARIABLES

In Python, one has to write instance variables using the very long form "self.__foobar". In Ruby, the form is "@foobar".

To get away with less typing, many Python programmers resort to making variables (and methods) public even when there's no reason for them to be public.

AN EXAMPLE OF A CLASS

Python:

class World:
    def init(self, verb):
        self.__verb = verb
        self.__double()

def expression(self): return self.__verb + " world!"

def __double(self): self.verb += " " + self.verb.lower()

world = World("Hello") print world.expression() # prints "Hello hello world!" world.__double() # ERROR, private method

Ruby:

class World
    def initialize verb
        @verb = verb
        double
    end

def expression @verb + " world!" end

private

def double @verb += " " + @verb.downcase end end

world = World.new "Hello" puts world.expression # prints "Hello hello world!" world.double # ERROR, private method

RUBY'S SYNTACTICS

Ruby has a *very* neat syntax for giving a code block as a parameter to a method call (aka. closure):

config = open(conffile) {|f| YAML.load f }

In the example, the open method is given a file name and a code block as parameters. After opening the file successfully, open runs the block, giving the File object as a parameter to it.

Inside the block YAML.load parses the YAML-formatted file and returns the structure, which ends up in the config variable.

Another example from a certain script:

autofetch.check_downloads do |filename|
    puts "Making torrent for #{filename}"
    system btmakemetafile', config['tracker_url'], filename
end

check_downloads checks an "incoming" directory for possible new files. If there are any, the method moves them to a "shared" directory. If a code block is given to the method, it calls it, giving the path of the file (in the "shared" dir) as a parameter.

The code block creates a torrent file using a tool from the BitTorrent project.

The check_downloads method:

def check_downloads
    Dir.foreach(@src_dir) do |filename|
        # %wfoo bar is a shorter form for ['foo', 'bar', 'quux']
        next if %w[ . .. ].include? filename

src = File.join @src_dir, filename dst = File.join @dst_dir, filename

puts "Moving #{src} to #{dst}" FileUtils.mv src, dst

yield dst if block_given? end end

Note that Dir.foreach makes use the same syntax: the code block is executed once per each file found inside the directory. The filename variable contains the name of each file.

One more example: traversing through an XML tree recursively.

require rexml/document'

doc = REXML::Document.new '<foo><bar>quux</bar></foo>' doc.each_recursive do |node| puts node.name puts "- " + node.text if node.has_text? end

For more help, ask us at Newbies Linux Forum