Mary-Esther has an appropriately named ‘Nuby' teething ring. WTF?!!1!
Items filed under noob
One of the things that is offputting about learning any of the web application stacks that I have tried (rails, turbogears, django) is the command line operations that need to be performed. When you start using them they seem like magic but after a while they become old friends. Hence this article is a summary of the rails command line operations that I use routinely.
All these commands except for the first one should be executed in the root directory of your application. Note that for the commands that start 'script' you are running ruby scripts and under windows you will need to type 'ruby script/blah'.
rails {app name}
The basic one, creates a new rails application. It will create a subdirectory with the given name in the current directory. This subdirectory is the root directory of your application and will be filled with all the appropriate files and subdirectories to start developing. It is a big code generator.
script/server
This could be considered the next step after creating your application. You cd to the application's root directory and run this command. It will start a development web server and you will be able to connect to localhost:3000 in a web browser and admire your new creation. This is the way to debug your application. Any print statements will be dumped out here.
script/generate model {model name}
This command will generate a new model in your application. A model is roughly equivalent to a table in the database.
script/generate controller {controller name}
This command will generate a new controller in your application in the file 'app/controllers/{controller name}_controller.rb'. A controller is essentially the logic that takes a web page request and decides what to do with it. It will also create a directory called 'app/views/{controller name}' to store the views for this controller, views being the templates that determine how the web pages will look.
rake db:migrate
This runs the migrations that will either define the database schema, modify it or undo those modifications. It defaults to updating the development database but can take the argument 'RAILS_ENV=production' to update the production database.
script/console
script/console is useful for debugging. It gives you a ruby irb command line prompt where you can play with the inner workings of your code, primarily you have direct access to your models and hence the database. It can be an easier way of manipulating the database from a command line than typing SQL into the mysql or sqlite command line clients.
rake --tasks
Lists what rake tasks are available.
rake db:test:prepare
Prepares the test database for running unit tests.
rake test
Runs all unit, functional and integration tests on your model.
I think that covers it. There are many more options than these are the ones that I have found to be most useful.
1 Comment
Sometimes software jargon gets in the way of understanding what practical use something is. For example, you have a problem and you want to know how to solve it so where do you look it up in the ruby book?
What I am going to describe is based on the concept of 'metaclasses' which are classes for creating classes. If that jargon fried your brain then lets have a problem and an example.
I want to create classes for implementing Commands. Each Command class has a command number and I want to define this Command Number in the class definition but I don't want to wear my fingers out typing them in. What nice syntactic sugar can ruby offer to help me with this?
1 # 2 # Class for building command classes 3 # 4 class Command 5 class << self 6 attr :nCommandNumber 7 8 def CommandNumber( nNumber) 9 @nCommandNumber = nNumber 10 end 11 end 12 endToggle Line Numbers
Ok, horrible syntax so what on earth is going on here? Well the effect of 'class << <object>' is to add new methods to an object so in this case we are adding a new attribute 'nCommandNumber' to hold our command number and a new method 'CommandNumber' so set its value to an object referred to by 'self'.
So what is 'self' equal to? Well it turns out that when you use this class (Command) to create another class (ACommand) then 'self' will hold the value of the 'ACommand' class object, i.e. the object that creates instances of ACommand objects.
# # Declare a specific command # class ACommand < Command CommandNumber 123 end
Hum, that looks easy. When ACommand is being defined the line 'CommandNumber 123' will result in the CommandNumber method in Command being executed on the ACommand class object so 'ACommand' will have an attribute called nCommandNumber added to it. We can see whether this happened with:
print ACommand.nCommandNumber =>123
and indeed it works sweetly (which is what you would expect from syntactic sugar). It is important to note that it is the ACommand class itself that has these attributes, NOT objects CREATED by ACommand:
oAC = ACommand.new print oAC.nCommandNumber NoMethodError: undefined method `nCommandNumber' for #<ACommand:0x345e180> from (irb):15
so how can an object created by ACommand find the value of this attribute?
oAC.class.nCommandNumber => 123
one of the attributes of the object is the class that created it.
How would this be done in a lesser object orientated language? Probably using techniques such as:
1 class Command 2 def GetCommandNumber 3 raise RuntimeError, "Pure base function called" 4 end 5 end 6 7 class ACommand < Command 8 def GetCommandNumber 9 return 123 10 end 11 endToggle Line Numbers
or
1 class Command 2 def initialize( nCommandNumber) 3 @nCommandNumber = nCommandNumber 4 end 5 end 6 7 class ACommand < Command 8 def initialize 9 super( 123) 10 end 11 endToggle Line Numbers
or something similar. Like all syntactic sugar, it doesn't make the impossible possible (anything is possible in hand-coded assembler) it just makes for less typing and clearer code.
2 Comments
Found another ruby gotcha when calling methods declared with default argument values:
irb(main):004:0> def a( b=1,c=2,d=3) irb(main):005:1> print "#{b} #{c} #{d}\n" irb(main):006:1> end => nil irb(main):007:0> a(c=23) 23 2 3 => nil
A python programmer would have expected this to print
2 23 3
as when calling the function we are saying we want c to be 23 and the other arguments to be left at their default values. Ruby appears to be ignoring the 'c=' bit when the function is being called so the first argument 'b' gets the value 23.
Pity, this python trick simplifies calling functions with lots of default parameters: you don't have to get the order of the parameters right or specify the correct default values of arguments before the one you are having to specify a value for. I should be calling this with:
irb(main):007:0> a(b=1, c=23)
i.e passing 'b=1' even though the declaration should tell ruby what the default for that should be. The 'b=' and 'c=' are only serving to help me selfdocument my code.
Ruby's behaviour is C/C++ish i.e. primitive.
UPDATE:
1 def fun_with_text(text, args={}) 2 text = text.upcase if args[:upcase] 3 text = text.downcase if args[:downcase] 4 if args[:find] and args[:replace] 5 text = text.gsub(args[:find], args[:replace]) 6 end 7 text = text.slice(0, args[:truncate_at]) if args[:truncate_at] 8 return text 9 end 10 11 fun_with_text("Foobar", {:upcase => true, :truncate_at => 5}) 12 # => "FOOBA" 13 fun_with_text("Foobar", :upcase => true, :truncate_at => 5) 14 # => "FOOBA" 15 fun_with_text("Foobar", :find => /(o+)/, :replace => '\1d', :downcase => true) 16 # => "foodbar"Toggle Line Numbers
2 Comments
I'm going to blog this so I can remember it. How to get Rails/ActiveRecord to wrap an existing table in a database, i.e. one that you don't want created or manipulated via migrations:
ruby script/generate model my_table --skip-migration
where my_table is the name of the table you are wrapping. This assumes you are already connected to the database (easy: edit config/database.yml).
It may be possible to simply derive a new class from ActiveRecord but the above is probably ensuring that everything is done properly.
In my case the database is being stuffed from some complex python code that I don't have the time/inclination to port to ruby/rails and I would rather the creation of the tables was still done through python. ActiveRecord being the wonder that it is will pick up the schema of the table and create wrappers automatically so you still don't need to tediously reiterate the column names/functions as you would in lesser frameworks.
It should be entirely possible to create views in MySQL and wrap them for Rails in this fashion although I found that creating views on a 20,000 record table causes the mysqld to take 99% cpu time for ten minutes afterwards. I know what you're saying, 'check your indexes', well I have.
1 Comment
I've been looking into why the make facilities in my Eclipse/CDT install are not working (I try a make and nothing happens). I found a log file in my workspace folder called /.metadata/.log and the log file contains this:
!ENTRY org.eclipse.core.resources 4 2 2007-11-28 11:13:09.401 !MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.core.resources". !STACK 0 java.lang.NullPointerException at org.eclipse.cdt.managedbuilder.internal.core.CommonBuilder.build(CommonBuilder.java:520) at org.eclipse.cdt.managedbuilder.internal.core.CommonBuilder.build(CommonBuilder.java:506) at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:624) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37) at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:166) at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:273) at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:354) at org.eclipse.core.internal.resources.Project.internalBuild(Project.java:494)
So the java is hitting some runtime error and the architecture is so poor that the error is not reported to me, I have to sit there wondering why nothing is happening.
I searched through the eclipse plugin directory and found zip files that contained the source code. The error in the log pointed me to this line:
IConfiguration activeCfg = info.getDefaultConfiguration();
so my guess was that getDefaultConfiguration was returning a null. This tied in with an observation I made that the "Build Configurations" menu in Eclipse/CDT had all it's items greyed out, including 'Manage..'. I decided that it was probably all because I hadn't set up my CDT project properly. I created a new CDT project, imported my source into it, deleted the old project, renamed the new project to match the old and tried it out. Voila, make ran and the output was in the console.
Lessons learnt:
- Projects may work with a number of perspectives (e.g. C/C++, Ruby etc) and each perspective wants it's configuration data within the project set up properly. At the same time, they seem only to set these configurations up when you create new projects, adding configuration data to an existing project when you use a new perspective appears to be up to the individual plugins: RDT, the ruby development plugin has an 'add ruby nature' option in the project menu to do this.
- Because Eclipse is written in java it comes with all the source code. This means that even if some of it is a bit flaky one stands a good chance of working around the problems.
Ok, I'm an Eclipse noob and didn't set my project up correctly but the environment really ought to have handled this better.
I was trying to use blocks in ruby and had code of this form:
1 2 def wangle 3 while true 4 nValue = rand(10) 5 if yield( nValue) 6 return 7 end 8 print "THIS IS NEVER PRINTED" 9 end 10 end 11 12 def wibble 13 wangle do |nValue| 14 return nValue == rand(10) 15 end 16 end 17 18 wibble()Toggle Line Numbers
The method 'wibble' calls 'wangle' passing it a block of code to execute. Wangle is supposed to keep calling this block until two random numbers match. if the numbers match it will return true and cause the loop to terminate. However, the loop will always terminate immediately, the string "THIS IS NEVER PRINTED" is never printed.
The reason for this is blindingly obvious in hindsight and after analysing the small print describing the yield command. This says "the value of the last expression evaluated in the block is passed back to the method as the value of the yield". Notice how it doesn't mention the 'return' keyword? This is because the return keyword is being applied to the outer method 'wibble' and that is returning to whatever called it, completely bypassing 'wangle' on it's way up the call tree. If 'wibble' is changed to:
def wibble wangle do |nValue| nValue == rand(10) end end
then it will pass the results of the comparison "nValue == rand(10)" back to wangle to deal with as I originally intended.
I can imagine that this subtlety was permitted as there may be occasions when you want wibble to be able to return directly to it's caller. In my ruby noobyness I'm getting blocks mixed up with methods. Unfortunately I like using the return keyword, it makes code easier to skim read, it waves a big flag to me that says THIS IS THE RETURN VALUE.
Filed under: noob readthesmallprint ruby
This is all very noobish but it was about time I learned more about the du command. du means 'disk usage' and lists how much disk space is being used. At its most basic
du
dumps out a list of subdirectories under the current directory and shows their sizes in magic pixie units. First improvement is to show the sizes in something meaningful so we go
du -bh
to show sizes in 'human' readable units like Kbytes, Mbytes etc.
du normally dumps the sizes of files in subdirectories so we can go
du -bsh
to show just a sum total.
Now what if we find to our horror that a directory is using far more space than we thought, how to determine how big each subdirectory is?
du -bsh *
3 Comments
Syntactic Sugar
Ruby has some perlisms such as 'unless'. This makes it possible to write code as follows:
return unless bFlag
Without unless one may have to resort to:
if !bFlag return end
I think code is easier to read when lines start with keywords, when the keywords are further inside a line one has to rely on syntax highlighting to make the keyword shout out at you. This is especially important with a keyword like return where you have to be aware that the code in the lines following may not be executed and understand the circumstances in which this will apply.
This way of expressing a statement always seems harder for me to get my head around, having written in C like languages for years. If one wrote similar expressions in English, which seems to be better expressed?
- jump up and down and sing a merry song if you are happy
- if you are happy then jump up and down and sing a merry song
To me the second form is even clearer as having the if at the start warns you in advance that a condition is coming up, it's not a surprise half way through the sentence. However, the second form requires you to type a whole extra word, and a four letter one at that!
1 Comment
Ooh Err, has_and_belongs_to_many, how_can_a_keyword_be_so_long?
Anyway, I've just used it for the first time to implement a UI in rails for user role permissions and here are some notes so that I might be able to use it again without excessive code trawling.
has_and_belongs_to_many is used to define many to many relationships. In the system I am implementing I have many Users and many Roles for them to perform. A User can be assigned to many Roles and a Role may be assigned to many Users. This is a classic many to many relationship and is implemented by having a table that contains a list of mappings of user id to role id, one mapping for each assignment of a user to a role.
This is (essentially) the migration that is used to create the user that is created by acts_as_authenticated but here it is stripped to the meaty bits:
1 class CreateUsers < ActiveRecord::Migration 2 def self.up 3 create_table "users", :force => true do |t| 4 t.column :login, :string 5 end 6 end 7 8 def self.down 9 drop_table "users" 10 end 11 endToggle Line Numbers
This is the migration that the role_requirement plugin uses to create the roles tables:
1 class CreateRoles < ActiveRecord::Migration 2 def self.up 3 create_table "roles" do |t| 4 t.column :name, :string 5 end 6 7 # generate the join table 8 create_table "roles_users", :id => false do |t| 9 t.column "role_id", :integer 10 t.column "user_id", :integer 11 end 12 add_index "roles_users", "role_id" 13 add_index "roles_users", "user_id" 14 end 15 16 def self.down 17 drop_table "roles" 18 drop_table "roles_users" 19 end 20 endToggle Line Numbers
In summary, there are three tables in the database:
- A 'users' table with a field called 'login' that gives the user login name
- A 'roles' table with a field called 'name' that gives the name of the role
- A table called 'roles_users' that holds each assignment of a role to a user.
Models need to be created for the User and Role table but not the roles_users table as that one is handled automagicaly by rails.
Here are the meaty bits of the model for the User table:
class User < ActiveRecord::Base has_and_belongs_to_many :roles validates_length_of :login, :within => 1..40 validates_uniqueness_of :login, :case_sensitive => false end
And the model for the Role table:
class Role < ActiveRecord::Base has_and_belongs_to_many :users validates_presence_of :name validates_uniqueness_of :name, :case_sensitive => false end
Both these have the magical has_and_belongs_to_many declaration to invoke the many-to-many goodness. They also perform some validation on what the user enters such as making sure they are giving their users login names.
Now for some code for a partial that can be used in a view to edit or create user records. This is used to generate a list of check boxes, one for each role. The check box will be checked according to whether or not the user has been assigned that role:
1 <% form_for :user, :url => { :action => action, :id => @user} do |f| %> 2 3 <p>Enter the login name for the new user:</p> 4 5 <div style="margin-left: 50px; margin-bottom: 50px"> 6 <%= f.text_field :login %> 7 </div> 8 9 <p>Select the Roles that this user can perform</p> 10 11 <div style="margin-left: 50px"> 12 <table> 13 <% for oRole in Role.find(:all, :order => :name) %> 14 <tr> 15 <td> 16 <%= check_box_tag "user[role_ids][]", oRole.id, @user.roles.include?(oRole) %> 17 </td> 18 <td> 19 <%= oRole.name %> 20 </td> 21 </tr> 22 <% end %> 23 </table> 24 </div> 25 26 <%= submit_tag submit_tag %> 27 <%= submit_tag "Cancel" %> 28 <% end %>Toggle Line Numbers
Here we iterate through all the Roles in the role table, sorted into name order. For each role we generate a check box tag. The check_box_tag line is tricky but can be broken down as:
- "user[role_ids][]"
- this is the name for the check box tag field. Naming the check box like this ensures that when the form is posted back to the server, the values for each tag will be placed correctly in the params array
- oRole.id
- the id of the Role record for this checkbox. It is these ids that are stored in the roles_users table to map a user id to a role id.
- @user.roles.include?(oRole)
- from the current user record, search the list of roles mapped to that user and see if the list already contains a particular role. If it does then the checkbox will be checked when the form is displayed.
When the form is submitted we need to ensure that the roles mapped to a user are updated correctly. This is simple:
1 def update 2 strLogin = params[:user][:login] 3 4 oUser = User.find( params[:id]) 5 oUser.login = strLogin 6 oUser.role_ids = params[:user][:role_ids] 7 oUser.save! 8 flash[:notice] = "Updated User '#{strLogin}'" 9 10 redirect_to :action => :list 11 endToggle Line Numbers
This is the method in the user controller that updates an existing record. The juicy bit is the line
oUser.role_ids = params[:user][:role_ids]
which is ALL it takes to update all the role assignments! This saves a lot of work such as adding new role assignments and removing extraneous ones.
Another little thing to watch out for: when deleting a role or a user do NOT use the delete method:
User.delete( params[:id]) ## WRONG
delete apparently just sends the raw sql to the database engine to get it to delete the object. Instead you should call destroy:
User.destroy( params[:id]) # Delete user and database objects associated with him/her
destroy will invoke the rails Active Record magic that will cause the roles_users table to be updated, removing any entires for roles or users that are being deleted. Calling delete will not do this and will leave stray records in the database.
8 Comments
Endless Ends
Ruby terminates just about everything with the end keyword:
def SillyExample if a == 3 10.repeat do |n| if n == a print n end end end end
Maybe I am nesting too deep but the endless ends become quite confusing after a while, especially with ruby's official two space indents. Visual Basic 6 (ugh) at least has end if, loop, end sub etc so you know what you are looking at the end of.
Then again, python has no equivalent to end:
def SillyExample(): if a == 3: for i in range(10): if n == a: print n
but python's indentation standard is four spaces rather than two making it a bit easier to follow.
Maybe I should just defy convention and indent my ruby with four spaces? Who cares apart from the indentation Nazis?
More Scope for Errors
So why wasn't this loop doing what I thought it would?
Mytable.find( :all, :order => "serial_number") do |oRecord| print oRecord.serial_number end
Mytable is a rails ActiveRecord class and I'm using it to load records from a table. But nothing is printed although I am sure there are records there.
Hum, turns out I missed the call to the 'each' method:
Mytable.find( :all, :order => "serial_number").each do |oRecord| print oRecord.serial_number end
and now it iterates through the recordset correctly. It seems that the first form silently does nothing, it doesn't seem to execute anything inside the block. It gives no errors either.
1 Comment
Legible Blocks
Thus far I have been using this syntax for blocks:
blah.each { |n| print n }
But I've found the following syntax is more legible because the do and end are syntax highlighted:
blah.each do |n| print n end
Maybe the braces can be syntax highlighted but I'm ok with typing big fat words.
What's Not in a Hash
If you address an item that is not in a hash you get a nil value:
?> oHash = {1=>2, 3=>4} => {1=>2, 3=>4} >> ?> oHash[5] => nil
python raises an exception in this case. I prefer the ruby way, I'm not a great fan needing exception handlers all over the place. It can be done in python without an exception handler with a little more typing:
>>> o = {1:2, 3:4} >>> o.get(4, None) >>>
There is one little quirk in the ruby way:
?> oHash[3] = nil => nil >> oHash.keys => [1, 3] >> oHash[3] => nil >> oHash[4] => nil >>
No simple difference between an item of value nil and a non-existant item. However I cannot imagine this ever being a problem.
Aptana Syntax Highlighting Oddity
I was having some weird problems with syntax highlighting in aptana. Some lines were indented more than others and I was having to fiddle about adding and deleting spaces. I finally traced the problem to the way that keywords were highlighted in bold. Because the bold made the font slightly larger it seemed to alter the size of the spaces before the keyword, making them wider. The result was that lines that started in a keyword were indented more than lines without.
The font I was using is called 'Andale Mono', a nice clear readable font except it seems to have this problem, the spacing on bold characters is different to normal characters. I changed the font back to nasty Courier New and the problem went away. However, as I prefer Andale Mono I will simply avoid using bold in the highlighting.
Not sure any of this is recommended practise but it appears to work so I'm noting it here.
Overriding Array Methods
1 class MyArray 2 # 3 # Initialise array 4 # 5 def initialize 6 @zog = [] 7 end 8 9 # 10 # Read from array 11 # 12 def [](x) 13 return @zog[x] 14 end 15 16 # 17 # Assign to array 18 # 19 def []=(x,y) 20 @zog[x] = y 21 end 22 endToggle Line Numbers
Used thus:
1 irb(main):021:0* a = MyArray.new 2 => #<MyArray:0x30d8074 @zog=[]> 3 irb(main):024:0> a[0] = 1 4 => 1 5 irb(main):025:0> a[0] 6 => 1 7 irb(main):026:0> a[1] = 2 8 => 2 9 irb(main):027:0> a[0] 10 => 1 11 irb(main):028:0> a[1] 12 => 2 13 irb(main):029:0>Toggle Line Numbers
Interesting that ruby doesn't seem to be fussy about array indices:
irb(main):031:0* g = [] => [] irb(main):032:0> g[5] = 2 => 2 irb(main):033:0> g[2] => nil
Contrast to python:
>>> a = [] >>> a[5] = 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list assignment index out of range
I think if I had the choice I would rather have my wrist slapped: the ruby way looks like an opportunity for obscure bugs.
Method Missing
It took me ages to work this out but it's simple. You have a class and you want to hook into calls to any undefined methods. Maybe you want to determine the method names at runtime. The hook is called 'method_missing':
1 class Klack 2 def method_missing( strName, *args) 3 print "Calling undefined method #{strName} with arguments #{args.inspect}" 4 end 5 end 6 7 irb(main):054:0> k = Klack.new 8 => #<Klack:0x309dd84> 9 irb(main):055:0> k.wibble( :wobbles, :banana) 10 Calling undefined method wibble with arguments [:wobbles, :banana]=> nilToggle Line Numbers
args appears to be a simple array holding the arguments the method was called with.
Note how useful the .inspect method is. It's equivalent to repr in python in making anything into a human readable string. Also gotta love how easy it is to insert the values of variables into strings.
UPDATE: this does seem to make for very fragile code. Just about any problem in your method_missing method can lead to a stack overflow. Or maybe it's a rails problem?
Wots the colon?
The colon thing is handy:
b = :blah
:blah is like a string constant, something like a string, easier to type but less complex in it's implementation. Have to be careful with them though:
1 irb(main):058:0> b = :blah 2 => :blah 3 irb(main):059:0> b[1] 4 NoMethodError: undefined method `[]' for :blah:Symbol 5 from (irb):59 6 irb(main):060:0> b == 'blah' 7 => false 8 irb(main):061:0> b == :blah 9 => true 10 irb(main):062:0> b.to_s == 'blah' 11 => trueToggle Line Numbers
They don't have common string functions and :blah is NOT comparable to 'blah'.
Regular Expression Gotcha
The =~ operator for testing a string against a regular expression returns the offset of the match.
irb(main):086:0> o = "poop1" =~ /poop(\d+)(=?)/ => 0
In this case the result is zero as the match starts at character offset zero. The operator would return nil if there was no match.
If you want access to the expression match object then this does the job:
irb(main):088:0> o = /poop(\d+)(=?)/.match( "poop1") => #<MatchData:0x3085748> irb(main):089:0> o[1] => "1" irb(main):090:0>
o is the expression match object where you can examine the juicy details of the match. These are also available in global varibles such as $1, $~ etc but everyone knows that using global variables is sloppy.
Zero is True
The =~ result works nicely with an if operator to detect a match because of the strangest ruby design decision: zero is true:
irb(main):095:0> if 0 irb(main):096:1> print 'true' irb(main):097:1> else irb(main):098:1* print 'false irb(main):099:1> end true=> nil
nil is false but 0 is true.
This is totally at odds with python where 0 and None are both False (with a capital F). I think even basic has 0 as false.
Processing Arrays
The collect method looks useful for writing one-liners:
irb(main):103:0> [1,2,3].collect { |x| x + 1} => [2, 3, 4]
Each item in the array is processed by the block and the results returned in a new array. To me this is more readable than the python version:
[ i + 1 for i in [1,2,3]]
2 Comments
Ruby gave me a little puzzle. What gives?
def GetWidgets oWidgets = [] ['a', 'b', 'c'].each { |x| oWidgets << x + 'y' } end
This returned
['a', 'b', 'c']
rather than
['ay', 'by', 'cy']
Huh? Well the problem was I forgot to put in return oWidgets at the end. Any stricter language would have complained that I didn't return anything or Python would return None but ruby returned the result of the last expression in the function. This is probably a feature borrowed from perl or php (son of perl) where typing 'return' is a massive strain on the metacarpels.
Still lovin, ruby though. Blocks ftw.


