Posted Nov 19, 2005 11:44:11 AM
Ruby is a very powerful, fun, and expressive language - I thought instead of continuing my sometimes long winded Intro To XXX series this morning, I'd post a cheat sheet of sorts to get you started writing Ruby code quickly.
Numbers
Ruby has three built-in types to support numeric values: Fixnum, Bignum, and
Float. The names are pretty indicative of what they're used for, Fixnum for fixed length integers,
Bignum for infinite length integers, and Float for floating point numbers.
12345 # Fixnum (decimal) 0x45DF # Fixnum (hexadecimal) 04577 # Fixnum (octal) 0b11010010 # Fixnum (binary) 12345678901234567890 # Bignum
Fixnum stores values in a native machine word minus 1 bit. Values that can not be represented in this size are automatically converted to a Bignum instance.
Strings
Strings in Ruby may be either single or double quoted. Single quoted strings will not be evaluated in Ruby,
other than two special back-slash notation expressions: \\ and '. Double quoted
strings will be evaluated for expression subsitution, and will obey back-slash notation the way most C, C++, and
Java developers would expect.
puts 'This is my string.\n It does not look the way I think.\n' puts "This is my string.\nIt looks just fine to me!\n"
Yields the following output:
This is my string.\n It does not look the way I think.\n This is my string. It looks just fine to me!
Expressions substitution in double quoted strings allows you to insert arbitrary values inline, instead of using string formatting syntax:
myname = "Timothy Fanelli"
myage = 25
intro1 = "Hello, my name is #{myname} and I am #{myage}."
intro2 = "Hello, my name is " + myname + " and I am " + myage.to_s + "."
intro3 = "Hello, my name is %s and I am %d." % [ myname, myage ]
intro1, intro2 and intro3 are all identical strings.
The third string is a general case of using Ruby's builtin sprintf or format function,
which look like this:
sprintf( formatstring, *args ) format( formatstring, *args )
Where you can pass any number of arguments in (they'll be converted to an array called args), and
formatstring can use the following conversion specifiers:
%b Binary integer %c Single character %d Decimal integer %e Decimal integer displayed in exponential form %f Floating point number %g Same as %e if exponent is less than -4, %f otherwise %o Octal integer %s String %u Unsigned decimal integer %x Hexadecimal integer
You can substitute %E, %G and %X for %e, %g and %x respectively if you prefer capital letters in your notation.
Regular Expressions
Ruby has powerful builtin regular expression support. A regular expresion is expressed either as a pattern between delimiting forward-slashes, a pattern between an arbitrary delimiter preceded by a %r, or can be declared explicitly as a Regexp class instance, like so:
/pattern/ /pattern/im # Regex with modifiers. %r!pattern! Regexp::new( "pattern", modifiers )
Any of these declarations can be treated as a Regexp instance. Calling Regexp::match( string ) will
return a Match object or nil if the string does not match the pattern. Match objects can be indexed
into if you used match groups in your regular expression.
Where ! in this instance could be replaced by either a matching pair of parenthesis, square or angle brackets or simpy two of any character of your choosing.
The following regular expression modifiers are supported:
i Regexp::IGNORECASE Case insensitive x Regexp::EXTENDED Ignore whitespace and allow comments in regular expressions m Regexp::MULTILINE Treat new lines as regular characters instead of whitespace o Substitute only once
Methods
The general form for all Ruby method declarations is as follows:
def methodname ( parameterlist ) method body end
The parameter list can contain any number reference names, and can optionally have two special arguments
indicated by an asterisk and ampersand respectively: *var and &block. Any excess
parameters passed into a method beyond those explicity declared in the method's parameter list will be
converted to an array and passed in as var (or whatever you chose to name it). &block
will be a Proc instance if a code block was specified, or nil otherwise.
Methods that support code blocks, such as List::sort, are called like so:
mylist = [ 'a', 'c', 'x', 'b' ]
mylist.sort { |a,b| a <=> b }
Where the sort method takes no explicit arguments, and only a Proc instance. This mechanism allows you
to pass arbitrary code blocks into a method that can be executed repeatedly. This is comparable to C's
function pointers or C#'s delegate type. The arguments a and b between the vertical
bars are the arguments to the Proc instance that will passed in when it is executed.
The return value of a method can be explicitly stated using a return statement. If return
is omitted, then the method returns the value of the last expression evaluated.
Classes
You can define a class using the class keyword, and there's built in support for your
standard public, private and protected access control mechanisms:
class Fruit
public
def initialize( color )
setColor color
end
def getColor
@color
end
protected
def setColor( color )
@color = color
end
private
def doSomething
end
end
class Lemon < Fruit
def initialize
super 'yellow'
end
end
mylemon = Lemon::new
In this case Lemon extends Fruit. Lemon::initialize is public
by default because it's not under any other access modifier. initialize is a special method that gets
triggered when an object is instantiated using the built in new. super, when used in a method
calls the parent class method of the same name. If no arguments are specified to super then the calling
method's arguments are passed in the same order to the parent class' method. Finally, the @ prefix
on a variable declares it as an instance variable of the class. An @@ prefix would declare it as a
class variable, which is comparable to static variables in C++ objects and Java.
Modules
Modules are very similar to classes, except that they have no base class and can not be instantiated. Use the
module keyword to declare a module, like so:
module Colors
def convertToRGB( colorname )
...
end
end
A class can include a module using a mechanism knowns as "Mix-ins":
class Fruit
include Colors
initialize( color )
@color = convertToRGB( color )
end
end
Including a module makes its methods and properties available to your class.
Conclusion
So that's where I'll leave off for now. This is still just the very basics, but it should be more than enough to get you on your way to becoming a Ruby developer!
Posted Nov 17, 2005 9:50:27 PM
I recently decided I was going to take up Ruby programming as a hobby. Prior to that I had taken on Python, which has quickly become one of my favorite languages. Ruby is coming in a close second, and could easily take it over as soon as they have built in XML support - so I thought I'd follow up my Intro To Python series with some Intro To Ruby posts.
I've found Ruby very easy to learn and use - I decided to learn Ruby about 2 weeks ago now, and have since released Blosxonomy, a Ruby implementation of a Blosxom like blogging system that powers this site. Its syntax is simple and intuitive, and the grammar is expressive and easy to learn.
Ruby carries the tag line "Programmers' Best Friend." I don't know if I'd go quite this far, but it's certainly a very developer friendly language - most comparable to Python in my experience. Its syntax, according to ruby-lang.org is inspired by Eiffel and Ada, neither of which I've had the pleasure of working with - but as both a Python and Ruby newby (relatively speaking), I find them quite dissimilar. The language's nuances are also very Pythonesque - as we'll see in this post, and my Ruby copy of Building Strings using Lists, which will come in a day or two.
Having compared Ruby to Python thus far, I'd like to start by pointing out that Ruby, unlike Python, uses delimited code blocks. Python determines code blocks based on their indentation level in the source, which can cause issues when editors convert between tabs and spaces. Ruby doesn't use an explicit statement-delimeter though, just a programmer-friendly newline. This combination eases development and allows developers use thier own coding style, which for seasoned developers is a solid positive, and for newbies a potential negative (for those of us that have to read your code, that is.)
Ruby, like Python, is both dynamically and strictly typed; meaning that a variable's datatype is determined at runtime by its value; and that an objects type can not be changed.
So in any event, after a long winded birds eye view of my opinion of Ruby, I'll show you a hello-world:
def sayHi( name ) puts "Hello, %s!" % String( name ) end sayHi( "Derf" )
def sayHi declares a function called sayHi. The parameter list is not required, but in this
case, we pass a single parameter called name. Notice that the type of the name variable
is not declared, that's because it's dynamically typed - meaning I could pass any object I want into the method.
To account for that fact, I use the built-in String( x ) function to create a string from the given
instance, no matter what its type.
The body of the method uses the puts method, which simply writes a string to standard-out followed by
a new line. The string is formatted using syntax identical to Python's, using %s inside the string to represent some
arbitrary string variable, and passing in the arguments following a % symbol after the string. If you had more than
one argument, you'd pass them in a list by encapsulating the comma separated arguments in square-brackes [ ].
The code outside of the method declarations is the "main" part of the program. This is analogous to writing the "main" method of a C or C++ program - and identical to "global" code in a Python application.
So that's the extreme basics and birds eye view of Ruby. My next post will be about Ruby's built-in Arrays and Hashes (practically identical to Pthon's), and I'll also cover CGI support.
If you're anxious to get started on your own though, I would recommend reading Programming Ruby: The Progmatic Programmer's Guide online. If you're very comfortable with programming languages in general, O'Reilly's Ruby In A Nutshell provides a very thorough and technical reference - but it's not a great book to learn from (a must have once you're comfortable with the basics of the syntax and grammar though).
Posted Oct 31, 2005 7:11:00 PM
I while back I began posting an Intro to Python series, and for lack of time I haven't posted anything in it for a while. Since I've started writing plugins for pyBlosxom, I've gotten to learn a lot of cool stuff about the language. I wanted to do a write up on what's easily become my favorite feature thus far, the String join method.
String's join method takes the contents of a list, and concatenates them together using the contents of the string as a delimeter. For instance, suppose I have a list containing "a", "b", and "c", and I want to make the string "a, b, c", this is accomplished easily using join:
abclist = ["a","b","c"] abcstring = ", ".join( abclist )
While this seems very simple, it can also be very powerful. Let's look at a more realistic example. Suppose I have a list of filenames in a directory, and I want to generate links to each file at the url http://www.timfanelli.com/images/filename. I could easily generate HTML containing all the links by doing the following:
imagefiles = getImageFileNames() imagelinks = "<br/>".join( [ "<a href='http://www.timfanelli.com/images/%s'>%s</a>" % (imgfile,imgfile) for imgfile in imagefiles ] )
Assuming my imagefiles list contains 3 filenames, "a.jpg", "b.jpg" and "c.jpg", which would result in the following HTML:
<a href='http://www.timfanelli.com/images/a.jpg'>a.jpg</a><br/> <a href='http://www.timfanelli.com/images/a.jpg'>b.jpg</a><br/> <a href='http://www.timfanelli.com/images/a.jpg'>c.jpg</a>
There's a little bit more going on in this example. Let's take it apart to see how it works. We know that
"<br/>".join( list ) will result in the contents of the list concatenated together, delimited by "<br/>".
The list in this case is generated by the statement:
[ "<a href='http://www.timfanelli.com/images/%s'>%s</a>" % (imgfile,imgfile) for imgfile in imagefiles ]
There's two things going on here, string substitution and dynamic list generation. Python's string substition is very similar to
using C's sprintf method. You embed formatting codes into a string, and then specify the arguments as a tuple preceded by a
percent sign. A simpler example would be something like the following:
x = "This is %s." % ( "my string" )
Dynamic list generation is also a very powerful technique for building lists in a single statement. The general form of this is:
list = [ expr for var in iterable ]
expr can be any valid Python expression using var. For example, suppose I had a dict type, and I wanted
to make a list of it's values, I could do:
mydict = {}
dictvalues = [ mydict[ x ] for x in mydict.keys() ]
(Ignoring the fact, of course, that I could simply have asked for mydict.values())
So getting back to the example at hand, our expr is a string substitution expression using variable imgfile for
every imgfile in imagefiles.
One should be cautious though, as it's very easy to write statements that are extremely cryptic. I'm guilty of this in the various plugins I've written for pyBlosxom - as I've tended to over use this feature, putting together statements like this:
taglinks = "<div id='relatedtags'>%s%s</div>" % ( "related tags: ", ", ".join( ['<a href="%s%s" rel="tag">%s</a>' % (config['tag_url'],tag,tag) for tag in related] ) )
Overall though, a very nice feature that makes Python a very elegant language to use.
Posted May 14, 2005 12:00:00 AM
I left off yesterday in my Python series having shown you the very basic language elements. Today, we're going to expand on that a little bit by introducing modules and packages, as well as making a Hello, World! CGI script.
Each Python source file is a Python module. The module's name is the name of the source file (without its extension), and the attributes, methods, and classes of that module are defined by the contents of the source file. Modules access other modules by 'importing' them -- which I'll show you below. To any of you with a Java background, this is extremely similar to Java's 'import' statement being used to identify the other classes that a Java class uses.
Before we get to that though, there's another very important point about Python. Everything is an object. Now I'm sure you've heard that before about other languages, such as Java (commonly - and incorrectly - described as a 'purely-object oriented language') -- but it's true this time. As such, a module is an object. When you import a module, you are actually instantiating a module object bound to a variable with the same name as the module. That module object has the attributes and methods defined in the corresponding source file; and you access them as you would attributes and methods of any first class object.
So here we go, let's jump right into the CGI Hello World example to show you the CGI module, and then we'll talk about the CGI module below.
#!/usr/bin/env python
import cgi
field = cgi.FieldStorage()
print "Content-Type: text/plain\n\n"
print 'Hello, world!\n'
print "You submitted the following values in your query string:"
for x in field.keys():
print "\t" + x + " : " + field[ x ].value
Save this file as helloworld.cgi, and save it to your web server's cgi-bin directory, and run it... see what happens! It's very simple, almost embarrassingly so, but it serves our purpose. It says Hello, world!' and then prints a list of all the request parameters.
You can see the results of this script here
The #!/usr/bin/env python directive in the first line causes the CGI script to be
interpreted by the Python environment. If we were executing the script directly, using python
helloworld.cgi, we wouldn't even need this, but it's there for the web server, so it knows what to do
with the CGI script when it executes.
The CGI module, importing in the second line, is very simple to use. As you can see, the CGI module defines the FieldStorage object (we haven't talked about object oriented programming in Python yet, that'll be my next post... for now, think of FieldStorage as a function that returns a dictionary... ofcourse functions are objects too, you know.) When the FieldStorage object is initialized, it parses the CGI request string, and populates itself as a dictionary of key=value pairs from it. The CGI module hides the request method (GET or POST) from you, and parses either type of request.
The print method writes out what is interpreted as the response by the web server. Easy
:). So that's all you really need to start writing dynamic html using Python and CGI.
The only other thing in the CGI module is a function called 'escape'. It takes a string, and returns a copy of it after replacing all occurrences of '&', '<', and '>' with the corresponding HTML character '&', '<', and '>'
Posted May 13, 2005 12:00:00 AM
Well I've said once or twice that I've finally taken up learning Python... so far I'm really impressed with the language, although I'm not overly familiar with it yet. Since the purpose of my site was originally to post tutorials about the things that I'm learning -- you'll all get to learn Python with me. This serves the dual purpose of getting my site back on track as a technology and programming blog, as it was originally intended... unfortuantely since I completed my M.S. (effectively ending my J2EE research for the time being), this site has become a place to post about my cat. And I know none of you want to read about that.
So back to basics -- today I wrote my first CGI Hello World in Python. I'll go over the very basics of the language here and show a regular Hello, World! example, as well as some other code examples to illustrate some basics. Sorry to all you Planet Cosiites who already know this stuff.
The first major point about the Python language is that it is not freeform. Coming from the freeform world C/C++/Java i thought this would be annoying and inconveniencing, but it's actually very natural and elegant. The statement delimiter (";" in C/C++/Java) is a line-break in Python, and code-blocks are identified by their indentation. I think this is great -- especially for new programmers; there's no "remembering the semicolon" or getting lost finding the semi-colon in multi-line statements; and it forces you to tab your code. As a former TA of Software Engineering at Clarkson -- I can attest to the fact that one of the most common mistakes in new-programmers is forgetting that damn statement-delimeter... and when they do remember it, their style is typically non-existent (left-aligned all the way... it's like they're using MS Word as a code-editor...).
The next thing to know about Python is that the language is dynamically typed, and strictly typed. This means that a variable's datatype is determined at runtime by its value; and that an objects type can not be changed. To give examples of other languages: C, C++, and Java are statically typed languages* -- a variables type is declared explicitly in the source. VB is not strictly typed, meaning that when you declare a variable intending to use it as a string, you can also use it as an int, or any other type, without casting.
* Yeah yeah, object-oriented languages support dynamic typing through polymorphism.... but we're keeping it simple here, k?
So without further ado, my hello world :)
def sayHi( name ):
print "Hello, " + str( name ) + "!"
sayHi( "Derf" )
def name declares a function called name. The parameter list is required, but
may be empty; notice that the type of the name variable is not declared, that's because
it's dynamically typed. The str( x ) function that you see takes any object, and makes a
string out of it. This example would still work great without using str, but if I were to
do something stupid and pass an integer type in, I'd get a runtime exception for trying to use the
+ operator on mixed types. The code outside of the method declarations is the "main" part
of the program. This is analogous to writing the "main" method of a C or C++ program.
So that's the very very basics. One more thing about the language for today, some basic data structures: lists and maps; Python has amazing built in support for these data structures. Since this isn't an intro-to-programming tutorial, I'm just going to show some basic examples of how to use lists and maps, and also show you method delcarations and some basic looping, without the fuss:
def createList():
mylist = []
for x in range(10):
mylist += [ x ]
return mylist
def createMap():
mymap = {}
for x in createList():
mymap[x]=x*x
squares = createMap()
for x in squares.keys():
print str(x) + ": " + str( squares[x] )
When this program is run, the output is as follows:
Timothy-Fanellis-Computer:~ timfanelli$ python test.py
0: 0
1: 1
2: 4
3: 9
4: 16
5: 25
6: 36
7: 49
8: 64
9: 81
Timothy-Fanellis-Computer:~ timfanelli$
Note that the function's return type is also dynamically typed... you can return anything you want from a function;
and what you return determines its type. the createList method returns a list, therefore I
can can use it as shown in the createMap method as a list... Now me, I've always been a
stickler for being explicit -- I like declaring types statically; however I have to say, I'd almost prefer having
meaningful names for methods that imply their type. I'm still kind of torn on this issue... Maybe I'll post a
commentary about it separately.
So there you have it, my very brief, overly simplified, intro to python. This originally started as my "Hello World, CGI" post, but it's gotten kind of long winded. I'm going to end this one here and start a new one. Hopefully this will be the start of a long-running Python series for developers interested in getting started with the language.
add to del.icio.us