Friday, 5 December 2008

Ruby Methods Part 2 - Not Overloading!

Method overloading is a common feature of several object-orientated languages. It allows the same name to be used for methods that perform the same, but accept different parameter types. Here is an example in Java:
  // Method overloading in Java
public int myMethod(String name, int age, int shoeSize) {
// do stuff
}

public int myMethod(String name, int shoeSize) {
myMethod(name, 0, shoeSize) {
}

public int myMethod(int age, int shoeSize) {
myMethod("", age, shoeSize) {
}

public int myMethod() {
myMethod("", 0, 0) {
}

// Invoking
public int main(String[] args) {
myMethod("F2Andy", 43, 8);
myMethod("F2Andy", 8);
myMethod(43, 8);
myMethod();
}

Ruby does not support method overloading, something I found very surprising at first. I suspect the reason is the way Ruby handles objects. Java is very strict that what gets sent to a method is exactly what the method expects. That gives (I would imagine) more robustness, but at the loss of flexibility.

Ruby has what could be described as "method over-writing" instead of overloading. In this example, the second test method over-writes the first:
def test s
puts "hello test"
end

def test
puts "goodbye test"
end

test # Causes "goodbye test" to be printed
#test "my string" # Causes an error:
# wrong # of arguments(1 for 0) (ArgumentError)
See here for how to use alias if you still need to access the old methods:
http://www.zweknu.org/blog/index.rhtml?start=77&

Default values and dynamic typing
Ruby has four tricks to mimic method overloading, and I am going to bundle the first two together. The first is default values in the method definition. Simply give a parameter a default value and it becomes optional. The second is the way Ruby handles objects; dynamic typing. Ruby does not care what sort of object you throw at a method, leaving the method writer the chance to handle different classes in different ways. In the next example the method has a default value - "default" - but the method is written in such a way that it will accept any class of object:
def test t = 'default'
puts "goodbye test t=#{t}"
end

test # => "goodbye test t=default"
test 34 # => "goodbye test t=34"

Something to consider, then, is how you handle unexpected objects in your class. One way is to ignore the issue, making the assumption that the method user knows what he is doing and any problems will be caught by the Ruby system.
def test t = 'default'
puts 'goodbye test t=' + t
end

test "one" # => "goodbye test t=one"
#test 2 # => can't convert Fixnum
# into String (TypeError)

Let us look at another example to see what options we have:
def test n
puts n.abs
end

test -4 # => 4
test 2 # => 2
#test "three" # => undefined method `abs'
# for "three": String (NoMethodError)

Rather than relying on your own method calls to generate errors, you might prefer to check that what you receive in your method is what you are expecting. You can then be quite clear about what exceptions your method is throwing, and more importantly, you will not have exceptions thrown half way through you method leaving the system in an unpredictable state.
def test n
raise StandardError.new("Oops, not a Fixnum") unless n.is_a? Fixnum
puts n.abs
end

test -4 # => 4
test 2 # => 2
test "three" # => Oops, not a Fixnum
# (StandardError)

Then again, perhaps you do not care what class the object is. The important question is whether it will behave as you expect. Instead of testing that it is of the right class, you could test that it responds to the appropriate methods calls. In this next example, a new method, abs, is added to the String class (how that is done was the subject of another post). Now the test method checks that the object it is given will respond to the necessary method call. This technique offers a lot more flexibility, but does rely on the API user sending sensible objects to the method. Does it really make sense that a string should return the ASCII code of the first character when asked for its absolute value? However, I would say that that is up to the API user; he has the responsibility now of ensuring the object he sends makes sense. You would need to check for each and every method call in your code.
class String
def abs
self[0]
end
end

def test n
raise StandardError.new('Oops, object does not respond to abs') unless n.respond_to? 'abs'
puts n.abs
end

puts "three".abs # => 116
test -4 # => 4
test 2 # => 2
test "three" # => 116

What would have happened if I had defined the abs method on String to return a string, rather than a Fixnum?
Using hashes for parameters
The third trick is to use a hash, and this is done throughout Rails. In the next example, the method expects a hash. Note that the default is set to be an empty hash, to avoid errors with nil.
def test options = {}
puts "hello #{options[:name]}"
end

test # => "hello "
test "here" # => "hello "
test :name => 'F2Andy' # => "hello F2Andy"

Compared to method overloading, there are advantages on both sides. If you have an existing method and you want to add overloading, it is no problem in Java. In Ruby, chances are your existng method is not expecting a hash and you either have to change your existing method calls or write the new method to expect either a hash or the original type. However, if your Ruby method already accepts a hash, adding more parameters becomes trivial - just add them to method calls if desired, and use in the method code where needed.

Variadic functions
Finally, Ruby supports variadic functions. These are methods that accept a vaiable number of parameters. In Ruby this is indicated by an asterix in the method parameter list, before the last parameter. This will then become an array holding all the "left over" values. Here is an example:
def vari_method name, *values
puts name
values.each { |x|
puts " -#{x}"
}
end

vari_method 'fruit', 'apple', 'banana', 'pear'

When vari_method is invoked, 'fruit' goes into the name variable, and the three other strings are collected into a single array, values. The method prints the name, then lists each member of the array. There is no reason for the members of the array to be of the same class or in any way connected to each other.

Struggling with Ruby: Contents Page

Thursday, 4 December 2008

Ruby Methods Part 1 - The Basics

A Ruby method definition starts with the keyword def followed by the method name and the parameter names, and ends with the keyword end.
def test
puts "Hello World"
end

test # Causes "Hello World" to be printed

Note that unlike Java and C#, Ruby does not require the return type or the parameter types to be stated. Every Ruby method returns a value. In the above example, puts returns nil, and as this is the last statement in the method test, test will also return nil. The return keyword is entirely optional (though necessary if you want to jump out of the middle of a method, of course).

Visibility
By default, all methods are public; they can be accessed from anywhere by anything.

Private methods can only be accessed from with the class and (unlike Java et al) its subclasses. That said, you can access private methods from anywhere using the send method, or modify their visibility on-the-fly, so it would seem that this is more advisory than anything else; the API writer is telling you that you probably should not use those methods.

The private keyword indicates that all subsequent methods (until public or protected is encounted) will be private.
class MyClass
def public_method
puts "In public_method"
end

# You can access private methods within the class
def private_via_public_method
puts "private_via_public_method"
private_method
end

private # Flags all subsequent methods
# as private

def private_method
puts "In private_methodstance_method"
end
end

class MySubClass < MyClass
# You can also access private methods
# within any subclass
def private_via_subclass_public_method
puts "private_via_subclass_public_method"
private_method
end
end

mc = MyClass.new
mc.private_via_public_method
mc.public_method
#mc.protected_method # Protected method
# not visible
#mc.private_method # Private method
# not visible

mc.send :private_method # Private method
# accessed with send

# Visibility can be changed dynamically
class MyClass
public :private_method
end

mc.private_method # Private method is
# now visible

The third visibility type is protected, which is a little more esoteric. The protected visibility is very similar to private, except that protected allows you call method from a different object, as long as that object is of the same class or subclass. To put it another way, private is restricted to the specific object, protected is restricted to the class.
class MyClass
# You can access private methods on the
# object within the class
def private_via_public_method
private_method
end

# You can access protected methods on another
# object within the class
def protected_via_other_public_method
mc = MyClass.new
mc.protected_method
end

# This will fail
# You cannot access private methods on another
# object, even within the class
def private_via_other_public_method
mc = MyClass.new
mc.private_method
end

protected
def protected_method
puts "In protected_method"
end

private
def private_method
puts "In private_methodstance_method"
end
end

The important point here is that both private and protected methods can only be used with the class (or subclass), but that private methods are further restricted to calls that do not require the dot operator.

As an aside, in Ruby all constants are public, and all variables are private

Class methods
Class methods are methods that are applied to the class rather than to a specific instance of the class. The most important example of a class method is new; in Rails the find method is also used very frequently.
s = String.new "My string"  # Equivalent to
# s = "My string"
post = Post.find :first # gets the first record
# from the posts table

As can be seen, class methods are invoked by using the class name, rather than the object, and as in the examples above they are often used to create or retrieve instances of the class.

Class methods are written much like instance methods, but with the keyword self before the method name. You cannot call a class method from an instance of the class, or call an instance method from the class itself. This does mean you can have a class method with the same name as an instance method.

See the next section for an example of a class method.

The initialize method
I have already mentioned the new class method. What this does is create a new instance of the object, and then it invokes the initialize method, if it exists. The initialize method is always private; there seems no way to change that. However, you can invoke it from within your class.

The following code illustrates the use of initialize and class methods.
class MyClass
def initialize
puts "In initialize"
end

def self.class_method
puts "In class_method"
end

def instance_method
puts "In instance_method"
end
end

MyClass.class_method # Prints "In class_method"
mc = MyClass.new # Would cause error; cannot call class methods on an object
#mc.class_method # Prints "In initialize"
mc.instance_method # Prints "In instance_method"


Class initialize method?
Sometimes you might want to do something to set up your class. You want it to run before any instances and created. I believe Rails does this for ActiveRecords, inspecting the database to see what fields are present, so it will know how to handle requests, rather than inspecting the database each time a request is made.

There is no method that supports this, you just put your code straight into the class definition.
class MyClass
p 'This will be printed when the class is loaded'

def initialize
p 'This will be printed when an object is instantiated'
end
end


Multiple return results
Pretty much every modern language allows you to send multiple arguments to a function/procedure/method. How many allow you to return multiple arguments? Certainly not the C derivatives, and really I cannot see why that should be so. At the machine code level, I would assume there is no difference. I would guess the reason is that C is based on a mathematical concept of functions, F = f(x,y,z), and Java and C# had followed suit.

Not so Ruby, which allows you to return as many values as you like. Here is a trivial example to illustrate that:
def test
return return 1, 'two', 3
end

a, b = test
p a # => 1
p b # => "two"

a, b, c, d = test
p a # => 1
p b # => "two"
p c # => 3
p d # => 4

Note that in this case the return keyword is required. What is actually returned is an array containing each each return value. This can lead to confusion...
def tester
return 3, 6
end

def output x, y = nil
p "x=#{x} y=#{y}"
end

x, y = tester
output x, y
# => "x=3 y=6"

output tester
# => "x=36 y="

The first call to tester correctly gets the two values assigned to the two variables. However, the second fails; the array is passed directly to the output method, which has no clue about the context, and just sees an array. What is really happening is a bit of trickery. Ruby does not pass back multiple values at all; it just passes back an array when multiple values are used with return. Meanwhile, at the other end, Ruby allows multiple varaibles to be set from an array.
x, y = [7, 6]
output x, y

Overall we have the illusion of muliple returns.

blog on dynamically creating methods:
http://ola-bini.blogspot.com/2008/05/dynamically-created-methods-in-ruby.html

Struggling with Ruby: Contents Page

Saturday, 22 November 2008

Ruby File Access

Reading Files
Note that while Ruby accepts backslashes, it seems to prefer forward slashes in file paths, even on Windows.

You can access the contents of a file like this:
file = File.open(filename, 'r')
do_stuff_with file
file.close

To test if the end of the file has been reached, use file.eof?. To test if a file has been closed, use file.closed?.

You can read the entire contents of file in a block:
contents = File.open(filename, 'r') { |file| file.read }

Or just:
contents = File.open('test.txt', 'r').read

If you prefer, you can put each line of the file into an array:
lines = []
File.open(filename, 'rb') { |file|
file.each_line { |line|
lines << line
}
}

Note that file here is exactly the same object as in the very first example. The big advantage of using it in a block is that Ruby will ensure the file is closed for you. You can use each_byte to iterate through the bytes (or, of course, your custom do_stuff_with file method). You can break lines at any character, for example, at the full stops:
lines = []
File.open(filename, 'rb') { |file|
file.each_line('.') { |line|
lines << line
}
}

Alternatively, use IO.foreach:
lines = []
IO.foreach(filename, '.') { |line|
lines << line
}

Or simply use IO.readlines (why was it not named read_lines?):
lines = IO.readlines(filename, '.')


Writing Files
To write data to a file, you can do something like this:
file = File.new("test.txt", "w")
file.syswrite("First line of text")
file.syswrite("Second line of text")
file.close

However, the prefered way, as with reading a file, is to do it in a block, and leave it to Ruby to close the file:
File.open("test.txt", "w") { |file|
file.syswrite("First line of text")
file.syswrite("Second line of text")
}

As well as syswrite, you can also use write, print, puts (adds a return at the end of the line), p (alias for puts) and printf (formated print, just like the C function of the same name). Or you can use the append function:
File.open("test.txt", "w") { |file|
file << "First line of text"
file << "Second line of text"
}


Binary Files
Binaries files are just the same; you just add a b to the second parameter of the open method. This example reads the contents of a binary file to contents (which is a string, by the way), and then writes that to a new binary file:
contents = File.open(in_filename, 'rb').read

File.open(out_filename, 'wb') { |file|
file << contents
}

Manipulating Files
These are all pretty self-explanatory:
File.rename(old_filename, new_filename)
File.exists?(filename)
File.file?(filename)
File.delete(filename)
File.directory?(filename)
File.executable?(filename) # Returns true for a text file!
File.readable?(filename)
File.writable?(filename)
File.zero?(filename)
File.size(filename) # Return 0 if the size is zero
File.size?(filename) # Returns nil if the size is zero
File.ftype(filename)

Using Directories
You can list the contents of a directory at least three way:
Dir.entries(dir)  # Surprisingly, no default for current directory
Dir["#{dir}/*.txt"] #
`dir`

The first and second will produce arrays of the files in the given folders. The first has just the filenames, and starts with entries for "." and "..". The second has the full path for each file, but does have the facility to filter (as in the example, only .txt files will be listed). The third uses a backquoted string to invoke a system command, and will produce a flat string with the same contents that you would see if you typed "dir" at the command prompt (presumably an error on some operating systems).

Other methods:
Dir.pwd                  # Gets the current directory
Dir.chdir('c:') # Changes the current directory (to c:)
Dir.mkdir('newfolder') # Create a new directory
Dir.delete('newfolder') # Or unlink or rmdir


Putting It Together
Here is an actual program. It uses the directory functionality to create an array of file names conforming to the filter (in this case, files end .nif; NetImmersion format), then iterates through the array. For each filename, the file is opened in binary format, the contents read to a string, and then each occurance of one set of strings replaced by another (this was subst, an array of hashes, giving replacement names for texture files). Finally, the file is saved, again in binary format, with a new filename.
files = Dir["#{mesh_dir}/in_r*.nif"]
print "Found #{files.length} files.\n"
Dir.chdir(mesh_dir)
files.each { |f|
contents = File.open(f, 'rb').read
subst.each { |h|
contents.gsub!(h[:old], h[:new])
}
File.open(f.gsub(/In_R/i, 'And'), 'wb') { |file|
file << contents
}
print '.'
}
print "\nDone.\n"


File data in with code?
If you put __END__ in your code, Ruby execution will terminate at that point. Everything beyond that will be considered data, and can be accessed as a file, DATA. Here is a complete program to illustrate that:
p DATA.read

__END__

Your data goes here


Reading a CSV file
This is trivial, as Ruby provides a library to do just this.
require "csv"
values = CSV.read "C:/my-data.csv"

This gives you your data in a two dimensional array.


Struggling with Ruby: Contents Page

Saturday, 15 November 2008

Contents Page

This is not a blog in the true sense, where I create a new post each time I learn something. Instead, I am collecting what I learn into a collection of larger posts, and updating those posts as I learn more. Below is a list (a contents page if you like) of posts to date (22/Dec/09) grouped by topic, rather than chronologically, for easy reference.

Ruby Basics
Constants
Variables
Conditional statements
Case statements and relationship operator
Loops
Regular Expressions
Exception Handling

Methods, classes, etc.
Ruby Classes
Duck-typing
Methods - Basics
Methods - Not Overloading
Methods - method_missing
Methods - calling
Modules
Singletons
Proc objects
Blocks
Accessors
Operator Overloading

The Ruby Library (excluding Rails)
Hashes
Arrays
Strings
File Access
Time, Date and DateTime
Unit Testing
YAML
REXML for XML
Sockets
GUI with Shoes
GUI with Monkeybars (and Swing)

Miscellaneous
JRuby and Java

Links to APIs
Because I am always refering to these three...
Array
String
Hash

Rails
Building a Project
Basic Project
Deploying on Tomcat

The Model
Creation
Validation and Association
Interactive Rails Environment
Testing
Find and other methods
Date and Time
Gotchas

The Controller
Routing
Basic Methods
Render and Filter
Functional Testing
Testing for valid HTML

The View
ERB and Links
Scope, Helpers and Partials
Using Forms
Using Select/Options
Partials as methods

Handling Images On Rails
Dynamic Images with RMagick
Dynamic Images with Java
Generating Line Graphs with Java
Uploadable Images with File Column

More On Rails
Integration Testing
Rails Mailer
Usage Statistics on a Bar Graph with HTML
Single Table Inheritance
Moving to Rails 2.2.2
Moving to Rails 2.3.8
Using JavaScript
Using Java applets
Organising in Subdirectories
named_scope
Iterating through records
Singularize and Pluralize
Capturing file uploads

Useful Links
General Ruby and Rails
Good Rails tutorial that go beyond the very basic:
http://www.akitaonrails.com/2008/5/25/rolling-with-rails-2-1-the-first-full-tutorial-part-1

Book on Ruby (not Rails):
http://ruby.activeventure.com/programmingruby/book/index.html

FAQ
http://www.ruby-doc.org/docs/ruby-doc-bundle/FAQ/FAQ.html

Cheatsheet:
http://www.ilovejackdaniels.com/cheat-sheets/ruby-on-rails-cheat-sheet/

Quick ref:
http://www.zenspider.com/Languages/Ruby/QuickRef.html

Others
PDF generation:
http://prawn.majesticseacreature.com/

XML handling with REXML
http://www.germane-software.com/software/rexml/docs/tutorial.html
http://www.developer.com/lang/article.php/3672621

The Controller Part 4 - Functional Testing

Functional testing targets individual methods in your controllers. It tests the user is redirected, gets the right HTTP response and so on, without actually generating any web pages (though it does generate the HTML so will find errors there).

Setting it up
Rails creates functional tests, but there are a few things to be done first... The test database must be set up (though this was probably done when you did your unit testing):
rake db:test:prepare

As with unit testing the require needs altering, if you are using NetBeans 6.1: require 'test_helper' becomes require 'test/test_helper'. You should now be able to run the default tests put there by Rails (depending on the changes you have made to the controller and model). Outside of an IDE, the easiest way is using rake.
rake test (run all tests)
rake test:functionals (run all functional tests)
rake test:recent (run all test files modified in last 10 minutes)

There are typically three parts to a test method. The first part is setting up, and might include, for instance, logging a user on. The second, and only required, part calls the method and checks changes to the database. The third part checks the HTTP result.
def test_should_get_new
login
get :new
assert_response :success
end

Method Calls
By default, controller method calls have all the parameters you would expect (eg :controller), but often you want to add more. In this example, an extra parameter is given. This is equivalent to ?run=199 at the end of the URL.
get :new, :run => '199'
In his example, parameters for a model are given. This is equivalent to data in a form, as usually accessed via params. I found that this was essential for create, otherwise there is no data in your model, and so nothing gets saved and the test fails.
post :create, :sample => { :sample_reference => 'P12345', :sample_type => 'PP1'}

Checking the results
While your view can, of course, access any instance variable in the controller, you do not have direct access to those variables from within your tests. Instead, they can be accessed though the assigns method. This allows you to test against values.
assert_not_nil assigns(:samples)
assert_equal 1, assigns(:samples).length
assert_equal 'glc', assigns(:sample).analysis
# Test value of a specific attribute for one record
To check the returned HTTP code, just use the standard method:
assert_response :redirect
Other options are :success, :missing and :error. Not sure why you would test for the last two.

You can also test the template used. This is for those occasions when you specified a template (like this; render :template => 'folder/template'), otherwise the template is nil.
assert_template 'samples/new'

The last check is where the page has been redirected to. You can use the same parameters for assert_redirected_to that you can for redirect_to.
assert_redirected_to :controller => 'samples', :action => 'home'
assert_redirected_to samples_path
assert_redirected_to sample_path(assigns(:sample))

See also:
http://api.rubyonrails.com/classes/ActionController/Assertions/ResponseAssertions.html

You can also check what has happened to your database table with the assert_difference method. Wrap this method around your method call, and it will check that the number of records has changed by the appropriate amount. This example checks the number of records for a model called Post has increased by one (the default value) when a new record is created:
def test_should_create_post
assert_difference('Post.count') do
post :create, :post => { }
end
assert_redirected_to post_path(assigns(:post))
end

The destroy method needs to check that the number of records has decreased by one, so in that case the method call looks like this:
    assert_difference('Post.count', -1) do

What assert_difference does is to determine the value of the first parameter (Post.count in the example), then run the block, and then determine the value of the first parameter again. It then compares the value before and after, and checks that difference against the second parameter (which defaults to +1).

Fixtures
Fixtures are a way to easily generate example data. You can point your tests to a fixtures file with:
fixture :my_data

By default, rails includes the statement fixture :all in tester_helper.rb, so all the fixtures get loaded for all your tests.

Rails will look for test/fixtures/my_data.yml (or test/fixtures/my_data.csv), and use the data in there to create a data structure, my_data (actually, I suspect my_data is a method that returns the data_structure, but the effect is the same), as well as in your database table. Here is an example of a fixtures file, employees.yml.
:one
name: Fred Smith

:two
name: Mary Jones

You can access specific records from your fixtures using their label. For the employees fixture, to access Fred Smith, use:
employees(:one)

Functional testing gets a little more complicated once you have a model that belongs_to another (see here for how to set up the model). Let us suppose the companies.xml fixture file look like this:
:one
name: The Excellent Software Company

:two
name: MegaSoft Ltd

In the Employees fixture file, employees.yml, you can set up the association for the company very easily. Just add a key named after your associated model, with the value equal to the label you used for your entry (without the colon):
:one
name: Fred Smith
company: one

:two
name: Mary Jones
company: one

To assign a company to an employee in a test, use something like this:
post :create, :employee => {:name => 'Tom Johnson', :company => companies(:one) }


Preventing something when testing
It may be desirable to prevent some actions happening while testing, for example, confirmation e-mails being sent whenever a new user account is set up. This is easily done by checking ENV['RAILS_ENV'].
def my_method
return if ENV['RAILS_ENV'] == 'test' # Do not during testing
do_stuff_only_if_not_in_test_environment
end

Obviously this could cause potential problems, as you are specifically not testing some of your code, so use with care!

Testing functions that require a logged in user
This is what works for me...

At the start of each relevant method, put in a line like this:
login_as_admin(@request)

In test_helper.rb, define the login method, something like this:
def login_as_admin(request)
user = User.new
user.login = "tester"
user.email = "tester@domain.com"
user.username = "Test Administrator"
#...
# Set up other details, permissions, etc.
#...
request.session[:user_id] = user.id
end

You should also test that a user will get redirected if not logged in (and that a user logged in but with permissions gets redirected too). Here is how:
def test_should_be_refused_without_login
get :new # Example method to test
assert_response :redirect
assert_redirected_to :controller => 'session', :action => 'new'
end

Similar methods can be set up for other user roles, to test how the system behaves.

Testing helper methods
You can test your helpers (in application_help.rb) in your functional tests.
class HelperTest < Test::Unit::TestCase
include ActionView::Helpers::TextHelper
include ActionView::Helpers::TagHelper
include ApplicationHelper
# include whatever helpers you want to test here, sometimes you'll need
# to include some of the Rails helpers, as I've done above.

def test_some_helper
end
end

However, you do not have access to the usual Rails helpers, and so any of your methods that rely on them are going to generate errors. There may well be a way around that that I have yet to discover, though as some Rails helpers use the context of the web user to determine their behavior (eg, the output of link_to depends on the current web page) there may not.

Credit: http://blog.lathi.net/articles/2006/03/31/testing-rails-helpers

Testing filter methods
You can test filter methods via the usual fuctional tests, for example having one test in which a user is signed in, and another in which the user is not. However, I feel it is better to also test the method itself. I would describe that as unit testing, but as your filter may well do a redirect, you will have to test it in your functional tests. This will be a protected, instance method, so can be invoked like this:
MyModelsController.new.send(:check)

However, as far as I can find, there is no way to set the params variable, so you cannot test a filter that, for example checks an id exists (see forum thread here for more).

What to test
My opinion is that you need one functional test for each outcome of each action in your controller. If an action can result in either of two pages being rendered, then that action needs two tests (that said, I rarely bother to test for when a save fails). This rule of thumb does rely on you having pretty much nothing in your controller besides setting up the instance variable, and deciding what page to display; all the complicated stuff is in the models, and that is adequately covered in your unit tests.

Things to watch out for
If you get a error complaining about a database table or column missing check that the table or column really is there via SQL - have you updated your test tables after modifying them in the development environment? Alternatively, if there is not supposed to be a table or column of that name (eg a subclass in STI or a model you later removed), check the test/fixtures directory; Rails may be trying to put data from here into your old table - just delete the .yml file for an erroneous table, or edit the data to remove references to the erroneous column.

If you are getting 300 responses when you expect successes, it might be because you need to set up a session with an appropriate user.

I write tests by copy-and-pasting existing tests. This leaves me liable to having two tests with the same name. Ruby will give no warning about this, but will only perform one of the tests, which can lead to a false sense of security.

You cannot rely on the values of the id field. In the development database they number sequentially from 1, but in the test database they start at some huge number.

I had a method that found the most recent entry of a certain type in the database and used that as a template for a new one. This is difficult to test, because all the entries in your fixtures file get created at the same time, so you have no idea which one will be selected as the most recent. Fortunately, in my case I had a reference number for each record and I could use that instead.

The data in fixture files gets loaded without validation, which is fair enough. However, validation will apply to the method calls in your tests. So if your update test uses update_attributes, and is working with a record that will not validate (perhaps the record has a required field missing, or the same supposedly unique field as another), the result will be that update_attributes will return false, with no clue as to why. It took me about a long time to realise this.

Similarly, if your create method is failing to increase the count in your database table, it may be because the validation fails.

Be aware that functional testing will not check any of your links actually go anywhere, or that your web pages make sense.

I have to say that in setting up functional tests for my project, most of the errors it turned up were down to the testing, rather than real bugs...

Struggling with Ruby: Contents Page

Sunday, 2 November 2008

Loops

Ruby has several options for loops; I will start with for and each loops. In practical terms, there is not a lot between for and each besides style, though each is actually a method call that takes a block, while for seems to be a language feature. They both iterate over a collection, which could be a hash, a string, an array or a range. Let us look at ranges first.

For and each with ranges
Use of a range takes the place of the normal for/next loop. In these examples, 1..10 and 1...11 are Range objects; the three dots indicates that the end stops before the terminator, two dots indicates it includes the terminator. These three examples will all print out the numbers 1 to 10, illustrating the difference between each and for, and the two and three dots.
for i in 1..10
do_stuff
end

for i in 1...11
do_stuff
end

(1..11).each do i
do_stuff
end

Ruby is perfectly happy with characters and variables in a Range object, and the next example shows how a range can be assigned to a variable.
r = 'a'..'z'
for i in r
puts i
end

n = 5
(1..n).each do i
puts i
end

These loops output the Range object, by the way, and you can test if something is within a range using the member? method (eg r.member? "c").

A quick note about arrays and ranges. I got really confused by putting square brackets around a range. What is [1..5]? This is an array with a single member, and that member is a Range object.

For and each with arrays, hashes and strings
The each method allows you to iterate over each member of a string, an array or a hash.
array.each { member do_stuff_with(member) }
array.each do member
do_stuff_with(member)
end

For a hash, you pass two values to the block
hash.each { key, value do_stuff_with(key, value) }
hash.each do key, value
do_stuff_with(key, value)
end

You can use the for feature with hashes and arrays too, for example:
h = {:a => 19, :b => 35, :c => 3456}
for k, v in h
puts "key=#{k} value=#{v}"
end


The times method
In Ruby everything is an object, and integer objects (of the class Fixnum) have a method called times, which, like each, accepts a block, and iterates from zero up to one less that the number. In these examples, the numbers zero to nine are printed.
10.times { i puts(i) }

10.times do i
puts i
end

n = 10
n.times { i puts i }

Invoking times on a negative number will create a loop with zero iterations!

The yield feature
You can easily define your own methods that work like each and times, using the keyword yield. Say this method is defined in a class, Car:
def cars
yield "Red car"
yield "Green car"
yield "Blue car"
end

The following will then produce a list of cars; red, green and blue.
m = MyClass.new
m.cars { c puts c }

The cars method runs until it hits the yield, and at that point passes the value back to the calling code, which then processes it as required. Then the loop goes again, and the cars method continues to the next yield stament. The loop iterates until it runs out of yields (the cars method will run to the end regardless of any further yields in the code).

The while and until loops
Ruby also supports while and until. The until loop is just a while not loop. There appears to be no option to check the conditional after the iteration that I have found.

Infinite loops
You can also create infinite loops with the loop method. Hmm, beter make sure there is some way to break out of the loop, which brings us to:

The break, redo, retry, next and return keywords
Ruby also has some interesting keywords to modify loop behaviour. As with C and derivatives, the break statement drops you out of the current loop. The next statement replaces continue; it stops the current iteration, moves to the next one, and passes control to the condition at the end of the loop. The retry statement is similar, but does not move to the next iteration; it repeats the current one. The redo statement starts the whole loop from the first iteration. There is also a return statement, which drops you straight out of the entire method (and optionally takes a parameter; a value returned by the method).

Struggling with Ruby: Contents Page

Saturday, 1 November 2008

Conditional statements

Before going any further, try this in the Ruby interactive console:

puts false or true        # prints false
puts true and false # prints true

Surprisingly, what gets printed is false and true respectively. What is going on? The problem is that and and or do not bind as strongly as the method call. In effect, you are doing this:

(puts false) or true
(puts true) and false

Contrast this with && and . These bind more tightly than the method call, and so behave as you would expect.

puts false  true        # prints true
puts true && false # prints false

More on operator precedence here:
http://www.techotopia.com/index.php/Ruby_Operator_Precedence

if and unless
While C and its derivatives have only if (condition) statement; Ruby supports two conditionals, if and unless, each in two formats:

if condition
statement
end

unless !condition
statement
end

statement if conditional

statement unless !conditional

You can optionally surround your conditional in brackets.

Ruby uses lazy conditionals. In the following code, if s is nil, Ruby knows that the expression will be false, and so does not test s.length > 10 - which is good, because that would throw an exception. This could, however, be a problem if you are changing the state of something in your condition; it might not change as often as you might imagine.

if !s.nil? and s.length > 10
puts 'Long string'
end


Conditional assignments can be done with the ||= operator.
s ||= "default"

The way this works is that nil counts as false, and in effect it say s = s || "default". If s is nil or false, then s becomes "default", otherwise it keeps its orignal value.

Ruby also supports the usual tertiary operator:
x = conditional ? value1 : value2

Struggling with Ruby: Contents Page