Title Image
Twitter Logo
http://tiny.cc/cznl3 gotta love Harry. 5 days ago
Follow me on twitter @stewartmatheson

Using Ruby, require, include and Mixins

20th
7 / 2010

When I first discovered Rails all those years ago I had not really heard of ruby. I think rails introduced a lot of new people to ruby such as my self. Its great for ruby to have all these new users however this is a problem as well. The problem is that people such as myself jump right in to rails with out fully understanding ruby or in my case even partly understanding ruby. This in it’s self is not a probelm however the deeper you go in to rails the longer your going to have to go back and look at the naked ruby. This can lead to some problems later down the line. It can also make other peoples code hard to read. This is a weakness and something that I have been working on skilling up on.

This weakness was exposed today when I was trying to write an acts_as_method. I am currently working on a rule based AI system and I wanted to separate the underlying code of the AI system from the rails models that provide the knowledge. Thats where the acts_as_method comes in. However it came in rather slowly.

My first hurdle was looking at the require vs include. Both sound the same but do different things. Its important to understand this. The require opens reads and evaluates the code with in a ruby file. So for example say I have a file called Person.rb. In this file there was a class called “Person”. With me so far? I am working out of a file next to Person.rb called test.rb. Test.rb needs to know about Person.rb so that the Person class can be used. To do this we simply use

require 'Person.rb'

Simple enough. Ruby also supports shortcuts and will auto append the .rb so

require 'Person'

will also work. Again simple enough however all of a sudden it looks like we are talking about a class or a module here. This is what threw me a bit at first but remember it is the file. Directories work as you would expect. Say our person.rb is now in a models directory. Just use

require 'models/person'

Again no .rb but remember it is the file we are talking about. That brings us to include. Include in c++ for example includes a file the the way require works as described above but this is not the case in ruby.

In ruby we have mixins that allow use to add a module full of methods to any class we like. This is great and very handy as ruby does not support multiple inheritance. But who cares. Mixins are simple to use and make more sense. So lets consider the following

class Person
  def say_goodbye
    "goodbye"
  end
end
 
module PersonMethods
  def say_hello
    "hello"
  end
end
 
Person.include(PersonMethods)

Here we have a person class. We have a module with a method and we are using the include method to add the module methods to the person class. Now the person class will have both the say hello and say goodbye methods. The include is working on the program level. Not the file level. Very different to #include in c++ for example. I think form memory PHP has something smilier.

Who cares? Why do I need to do this? Why not just put both methods in the person class. Well you could do that and in this case its fine. However think about developing a Rails application for example.  You might have some logic that you want to use in a number of Rails applications. Cuting and pasting code from one model to another is one way to it but what about the following?

ActiveRecord::Base.send :include, PersonMethods

This is one of my favorite things about ruby. You can add in methods to classes that have already been declared else where.  You can add them when you need and you can break up your methods in different ways and add them at different times. All of a sudden your writing extra features in to rails with out even touching the source. Well the rails models at least.

This does not just stop at rails. You can apply this to any class anywhere. You can even apply it to core ruby classes. You can change the way ruby works at runtime! Check out the ruby homepage for lots more info.

Events in ActionScript3

14th
7 / 2010

There are a lot of posts around the Internet on ActionScript. A lot of them are very poorly written. Whilst they take the time to explain the “what” they don’t take the time to explain the “why”. I will attempt to do that with this blog post.

Events are a vital part of developing with ActionScript 3. Events are a very flexible way to make your code moduler and loosely coupled. Flush supports a number of events prepackaged. These include mouseclick events and keyboard events.

Whilst these are important for making any kind of user interface its custom events can I am going to explain how to use today. In the example I set up custom event for a unit within a strategy game I am developing. Think of civilisation and moving units around on a map.

When creating a custom event the first thing to do is write the custom event class. The custom event class must extend the event class which can be found in the flash.events package.

In this example the unit event class covers all events that relate to units. Obviously. Specifically the events I wish to send include movement, when the unit is selected, when the unit is deselected and when the unit has finished its movement.

In the class there is a static string declared representing each of these event types. The event model in action script uses this string to decide what listeners to call. Therefore this string is needed when adding an event listener.

In the class is the constructor. The constructor accepts one variable which is this event string. Make sure when you declare the constructor that the super call with the command string is present. This is all ActionScript needs to handle the event.

You may require to send additional information with the event. I have done this by using get and set methods. As the event is simply a class there are no limits on what functionality you can implement within the event itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.events {
 
	import flash.events.Event
	import com.geom.MapPoint;
 
	public class UnitEvent extends Event {
		public static const MOVEMENT:String = "movement";
		public static const SELECTED:String = "selected";
		public static const DESELECTED:String = "deselected";
		public static const MOVEMENT_COMPLETE:String = "movement_complete";
		private var targetLocation:MapPoint;
		private var startLocation:MapPoint;
		public function UnitEvent(command:String) { super(command); }
		public function getTargetLocation():MapPoint { return targetLocation; }
		public function setTargetLocation(t:MapPoint):void { targetLocation = t; }
		public function getStartLocation():MapPoint { return startLocation; }
		public function setStartLocation(t:MapPoint):void { startLocation = t; }
	}
}

Once we have the event class written we a free to dispatch it. Despatching an event can be done from any class that extends IDispatcher. IDispatcher is built into ActionScript.

The following example is an excert from a class that handles the unit. The code creates a new unit event. The new unit event takes one constructor which is the movement complete static variable of the event itself. This calls any listeners that are subscribed to that particular event type. After the locations are set the dispatchEvent method is called. This takes one parameter which is the event instance.

1
2
3
4
5
6
7
8
9
if(movesLeftThisTurn <= 0)
{
	var movementCompleteEvent:UnitEvent = new UnitEvent(UnitEvent.MOVEMENT_COMPLETE);
	movementCompleteEvent.setStartLocation(startLocation);
	movementCompleteEvent.setTargetLocation(currentLocation);
	startLocation = m;
	movesLeftThisTurn = movement;
	dispatchEvent(movementCompleteEvent);
}

So now we have a custom event class, we have code that dispatches the event however we do not have any way of listening for the event. A listener is set up with an addEventListener method. This method takes two parameters.

The first parameter is the string representation of the event. Remember when we first created the instance of the event? We passed it a single string parameter. When we add an event listener that listener will only be called if the event is created with that particular string parameter. This allows us to create different types of events in a single class. It also allows us to blind behaviours for different events. A very powerful system!

The second parameter that this method takes is a string representation of the function that the event is calling. Make sure to omit the brackets at the end of the function as we dont want to call function we simply want to tell the listener about it.

1
2
3
4
5
6
7
function unitFactory():Unit
{
	var u:Unit = new Unit():
	u.addEventListener(UnitEvent.MOVEMENT, unitView.moved);
	u.addEventListener(UnitEvent.MOVEMENT, activeState.selectNextUnit);
	return u;
}

The final step is to add the actual listener. The listener is a function in itself. The listener accepts one variable. The event that you have passed. This was the event that was sent in the dispatchEvent method. Make sure that every event listener returns void. If the event listener does not have a return type void then the event will not be fired properly.

1
2
3
4
5
6
7
8
class UnitView extends View {
	...
	public function moved(e:UnitEvent):void
	{
		x  = e.getTargetLocation().xpos;
		y  = e.getTargetLocation().ypos;
	}
}

In the above event listener we update the units position as this event listener is fired when the unit is moved.

I hope this helps. Please give me feedback. If there is any other topics you would like me to blog about please don’t hesitate to ask.

Tutorial: Installing Nginx, Apache and SVN

7th
4 / 2010

In this video I install Nginx Apache and SVN. Download links are here…

http://mirror.lividpenguin.com/pub/apache/httpd/httpd-2.2.15.tar.gz

http://subversion.tigris.org/downloads/subversion-1.6.9.tar.gz

http://nginx.org/download/nginx-0.7.65.tar.gz

Here are the apache configurations I used

<IfModule mpm_prefork_module>
    StartServers          1
    MinSpareServers       1
    MaxSpareServers       1
    MaxClients           10
    MaxRequestsPerChild   0
</IfModule>
 
<Location /repos>
    DAV svn
    SVNPath /usr/local/nginx_svn_test/testrepos
    SVNAutoversioning on
    Options Indexes FollowSymLinks
    Order allow,deny
    Allow from all
</Location>

This is the Nginx proxy pass configuration

location / {
  proxy_pass http://localhost:86;
}

The following is the line that configures the apache compile.

./configure --enable-dav --enable-dav-fs --prefix=/usr/local/nginx_svn_test --disable-alias --disable-userdir --disable-actions --disable-dir --disable-negotiation --disable-cgi --disable-cgid --disable-status      --disable-autoindex --disable-asis --disable-mime --disable-version --disable-setenvif --disable-env --disable-log-config --disable-include --disable-filter --disable-auth-basic --disable-authz-default --disable-authz-user --disable-authz-groupfile --disable-authz-host --disable-authn-default --disable-authn-file

The following is the configure line for the SVN install.

./configure --prefix=/usr/local/nginx_apache_svn_test --with-apxs=/usr/local/nginx_apache_svn_test/bin/apxs