Ruby Class Cheat sheet
The following is my ruby class cheat sheet, aimed at developers new to ruby and rails.
class MyClass #class declaration, notice the capital letter as this is a Constant
attr_reader :readOnlyProperty, … #shortcut to save writing a property getter
attr_writer :writeOnlyProperty, … #shortcut to save writing a property setter
attr_accessor :readWriteProperty, … #shortcut to save writing a property setter and getter
def initialize #class initialization method
@instanceVar=1 #instance variable, available throughout an instance of the class.
@readOnlyProperty=2
@writeOnlyProperty=3
@readWriteProperty=4
end
def instanceVar #property getter
@instanceVar #return the value of the instance variable
end
def instanceVar=(value) #property setter
@instanceVar = value # set the instance variable to the passed in value
end
def instanceMethod #instance method, available to all instances, this is the instance
end
def MyClass.classMethod #class method, only accessible via the class, this is the class
end
CLASSCONSTANT = ["a","b","c"] #constant defined by the class accessible by all instances note its in uppercase
end
I hope you have found this useful. If you have anything to add please comment.
Going loopy with JavaScript
I am in the middle of writing a JavaScript tree that can handle 100s of thousands of nodes in the tree and needed to see if I can optimize the code. Trying to optimize the loop iterations for array objects, I put together a test case to time the efficiency of various different types of loops in JavaScript.
The test
Create an array of 1 million numbers 0 to 1 million, for each of the loop tests, increment a counter then display it at the end of the iterations.
The test covers the following loops:
- ForLoop – standard for loop accessing the length of the array in the iterator
- ForLoopLocalCount – standard for loop, accessing the length of the array stored in a local variable before the iterator
- ForLoopLocalCountAndIterator – standard for loop accessing the count and the iterator from local variables
- ForInLoop – standard For In loop
- ForInLoopLocalItem – standard For In Loop, but declaring the iterator variable locally first.
- WhileLoop – While loop iterator accessing the length at each iteration
- WhileLoopCountFirst – while loop but storing the length of the array in a local variable before the iterator.
var loopTest = {
itemCount : 1000000,
items : [],
initArray : function()
{
for(var x=0; x < this.itemCount; x++)
{
this.items.push(x);
}
console.log(this.items.length);
},
forLoop : function()
{
var total=0;
for(var i=0;i < this.items.length; i++)
{
total ++;
}
console.log(total );
},
forLoopLocalCount : function()
{
var total=0;
var count = this.items.length;
for(var i=0;i < count; i++)
{
total ++;
}
console.log(total );
},
forLoopLocalCountAndIterator : function()
{
var total=0;
var count = this.items.length;
var i = 0;
for(i=0;i < count; i++)
{
total ++;
}
console.log(total );
},
forInLoop : function()
{
var total=0;
for(item in this.items)
{
total ++;
}
console.log(total);
},
forInLoopLocalItem : function()
{
var total=0;
var item = null;
for(item in this.items)
{
total ++;
}
console.log(total);
},
whileLoop : function()
{
var total=0;
var i = 0;
while(i<this.items.length)
{
total ++;
i++;
}
console.log(total );
},
whileLoopCountFirst : function()
{
var total=0;
var i = 0;
var count = this.items.length;
while(i<count)
{
total ++;
i++;
}
console.log(total );
},
runTests : function()
{
this.initArray();
this.forLoop();
this.forLoopLocalCount();
this.forLoopLocalCountAndIterator();
this.forInLoop();
this.forInLoopLocalItem();
this.whileLoop();
this.whileLoopCountFirst();
console.log("Complete.");
}
}
The test was profiled using the firebug profile option and run in Firefox 2.0.0.4 on a Dual Core Pentium 3.2Ghz machine with 3Gb of ram.
Results & Conclusion
The test results are shown in the table to the right. So what can we conclude from the results?
- Don’t use a For In loop. There is a small increase in performance if you allocate the item variable outside of the loop, but it is still up to 31 times slower than using a for or while loop.
- Always ensure that the count (used in the loop exit test) is stored in a temporary variable outside of the iterator i.e. rather than calling array.length in the iterator exit test.
- When local variables are used to store the iterator and count, a for loop performs the same as a while loop. One would assume that the JavaScript.
- In a For loop, declaring the iterator variable outside of the loop actually slows the iteration down! This I did not expect.
Firebug – Console options
Firebug, the ultimate javascript debugger for firefox, automatically creates a “console” object that has various methods that can be used to aid in debugging your javascript apps.
Full Documentation is here http://www.getfirebug.com/console.html
console.log() is the most used, with the ability to pass parameters and a formatted string.
One of the nice things is, if you log an object it displays all the objects properties as well.
For performance testing console.time(id) and console.timeEnd(id) are very useful.
consolt.trace() will even dump the full stack at the point it is called.
If you haven’t got firebug, it’s a must if you are developing with firefox. Go get it here
101 of Memory Leak causes in JavaScript
Really nice article explaining some of the gotcha’s that can cause memory leaks in JavaScript
http://www-128.ibm.com/developerworks/web/library/wa-memleak/
Ext.Format extension for thousands separator formatting
A simple function, the basis of was in the public domain (see comments) to format a number with thousand separators.
Ext.apply(Ext.util.Format,{
decimalSeparator : '.',
thousandSeparator : ',',
/* Adapted from http://www.mredkj.com/javascript/nfbasic.html,
* Public Domain, without copyright, and can be used without restriction:
* see http://www.mredkj.com/legal.html
*/
asThousands : function(value)
{
value = parseInt(value,10) + '';
var x = value.split(this.decimalSeparator);
var x1 = x[0];
var x2 = x.length > 1 ? this.decimalSeparator + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + this.thousandSeparator + '$2');
}
return x1 + x2;
}
});
Ext.util.SpriteManager
One of the ways of improving web page performance (especially in RIA – Rich Internet Applications) where there are lots of small images that need to be displayed, e.g. on a toolbar, is to create a compound image and then use css to select a section of the image to display. In the javascript world this is known as using sprites. In the world of C#/vb/Delphi this is well known and there have always been ImageList components that store images in this form.
So instead of creating single images : ![]()
we create a composite image e.g.
(have added a second row as well)
To make the process of assigning the correct css style to select on of the images to display, I have created a SpriteManager addition to Ext JS as follows:
Ext.namespace('Ext', 'Ext.util');
Ext.util.SpriteManager = function(config){
Ext.apply(this,config,{
spriteSource:true,
spriteWidth:1,
spriteHeight:1,
spriteColumns:1,
spriteRows:1
});
};
Ext.util.SpriteManager.prototype = {
/**
* Gets the CSS Style for the appropriate image
* @param {Object...} spriteLocation Expects an object with an X and Y location of the sprite to display
* @return {String} returns the CSS style string enclosed in braces {}
*/
getSpriteCSS : function(spriteLocation){
var locationX = spriteLocation.x-1 || 0;
var locationY = spriteLocation.y-1 || 0;
var spriteCss = ['{'];
var spriteW = this.spriteWidth / this.spriteColumns;
var spriteH = this.spriteHeight / this.spriteRows;
var spriteXPos = locationX * spriteW;
var spriteYPos = locationY * spriteH;
if(!typeof this.spriteSource =="boolean")
{
spriteCss.push('background:url(' + this.spriteSource +');');
}
spriteCss.push('height:' + spriteH + 'px;');
spriteCss.push('width:' + spriteW + 'px;');
spriteCss.push('background-position:-' + spriteXPos + 'px -' + spriteYPos + 'px;');
spriteCss.push('}');
return spriteCss.join("");
},
/**
* Applies the CSS Style for the appropriate sprite image to an element
* @param {element} Ext.Element to apply the sprite style to.
* @param {Object...} spriteLocation Expects an object with an X and Y location of the sprite to display
*/
applySpriteCss : function(el, spriteLocation)
{
var css = this.getSpriteCSS(spriteLocation);
el.applyStyles(css);
}
};
Here is an example of the usage:
<script type="text/javascript">
var spriteManager = new Ext.util.SpriteManager({
spriteSource:"sprites.png",
spriteWidth:64,
spriteHeight:34,
spriteColumns:4,
spriteRows:2
});
</script>
...
<img id="test" src="images/default/s.gif" />
<a href="javascript:spriteManager.applySpriteCss(Ext.get('test'),{x:1,y:1});">Image 1,1</a>
<a href="javascript:spriteManager.applySpriteCss(Ext.get('test'),{x:2,y:1});">Image 2,1</a>
<a href="javascript:spriteManager.applySpriteCss(Ext.get('test'),{x:1,y:2});">Image 1,2</a>
<a href="javascript:spriteManager.applySpriteCss(Ext.get('test'),{x:2,y:2});">Image 2,2</a>
** Updated 2/5/2007 – spriteSource does not now need to be supplied if the element already has a css style specifying the background image.
Non-record based Json calls across Domains with Ext
From a forum question I posted at Ext: http://extjs.com/forum/showthread.php?t=5430
I am trying to make a call to a webpage that returns a json object that is hierarchical in nature and not record based so as far as I am aware, jsonreader / datareader are not suitable.
The Server returns something looking like this:
1: (
2: {
3: children: [
4: {
5: id : "1",
6: name : "Dim Item 1",
7: children : [
8: {
9: id : "1.0",
10: name : "Dim Item 1.0"
11: },
12: {
13: id : "1.1",
14: name : "Dim Item 1.1"
15: }
16: ]
17: }
18: ]
19: }
20: );
Where each item can have children in a hierarchy. (I am not trying to use this data with the Ext Tree by the way)
To complicate matters the server providing the data is hosted on a different port, so I have to use the Ext.data.ScriptTagProxy to get the data, which is successful. I had a few teething problems until I realized you had to wrap the json object returned with the callback function name.
However, with my limited understanding and debugging the code, the Ext.data.ScriptTagProxy requires a reader to be supplied, but all I want in this instance is the object.
This is the client side code:
1: function GetData()
2: {
3: var url = "http://localhost:4855/largeJasonHierarchy.aspx";
4: var conn = new Ext.data.ScriptTagProxy({
5: url: url
6: });
7:
8: var reader = new Ext.data.ObjectReader();
9: conn.load({},reader,GotData);
10: }
11:
12:
13:
14: function GotData(x)
15: {
16: alert(x);
17: }
As a reader is required, I had to hack a copy of the jsonReader to create a ObjectReader that simply returns the object and does not process it.
ObjectReader.js
1: Ext.data.ObjectReader = function(meta, recordType){
2: Ext.data.ObjectReader.superclass.constructor.call(this, meta, recordType);
3: };
4: Ext.extend(Ext.data.ObjectReader, Ext.data.DataReader, {
5:
6: readRecords : function(o){
7: return o;
8: }
9: });
This all works, but I can’t help feeling like I’ve missed something crucial in the Ext library. Could someone with more experience than me confirm I have gone down the correct route, or let me know if there is a better way of getting json objects back in any format. (cross domain of course)
One concern, is that I have seen articles saying that any json data passed back from a server should be run through a regex parser to check that there are no functions /etc being injected in the data packets (anti-hacking and the likes) I’m not yet sure how I would fit this into the ObjectReader.
Thanks for any help.
Response by Animal, notice the way he has used the Ext override to override the default implementation on ScriptTagProxy.handleResponse.
As it stands, that’s the best way.
I think an enhancement request could be in order. If you don’t pass a reader, it should skip the call to reader.readRecords, and just call your callback passing the returned object.
That way, the following would work.
1: conn.load({},null,GotData);
by adding:
1: Ext.override(Ext.data.ScriptTagProxy, {
2: handleResponse : function(o, trans){
3: this.trans = false;
4: this.destroyTrans(trans, true);
5: var result;
6: if (trans.reader) {
7: try {
8: result = trans.reader.readRecords(o);
9: }catch(e){
10: this.fireEvent("loadexception", this, o, trans.arg, e);
11: trans.callback.call(trans.scope||window, null, trans.arg, false);
12: return;
13: }
14: } else {
15: result = o;
16: }
17: this.fireEvent("load", this, o, trans.arg);
18: trans.callback.call(trans.scope||window, result, trans.arg, true);
19: }
20: });
Javascript Namespaces
One of the big problems as the number of toolkits that you can use in your RIA increases is variable collision. Constructing your classes and widgets in the form of a namespace reduces the risk that the global variables you are using will have been used by someone else. The following code demonstrates a pattern for defining a namespace utilizing objects to create an object hierarchy for your namespace.
1: var MyNamespace = {};
2: MyNamespace.test = function(){
3: alert("MyNamespace.test");
4: };
5:
6: MyNamespace.common = {};
7: MyNamespace.common.test = function(){
8: alert("MyNamespace.common.test");
9: };
10:
11: MyNamespace.utilities = {};
12: MyNamespace.utilities.test = function(){
13: alert("MyNamespace.utilities.test");
14: };
15:
16: MyNamespace.common.dataaccess = {};
17: MyNamespace.common.dataaccess.test = function(){
18: alert("MyNamespace.common.dataaccess.test");
19: };
20:
21:
Notice that before the namespace can be assigned variables and functions, it needs to be initialized to an empty object.
This allows you to make calls like:
MyNamespace.common.dataaccess.test();
However, it is important that you only initialize the name space object once, and it is important that the full path of namespace objects be declared before you try and assign functions and properties to them.
If you want to separate your name space implementation across separate files, then you really need to check that all the stages of the namespace are assigned and create them if not. e.g.
1: if(!MyNamespace) MyNameSpace = {};
2: if(!MyNamespace.common ) MyNameSpace.common = {};
3: if(!MyNamespace.common.dataaccess) MyNameSpace.common.dataaccess = {};
You can imagine that if your namespaces get quite deep, you start having quite a lot of code at the start of each of your Javascript files just to ensure the namespace objects are created. There is however a very nice solution in the Ext library which helps you with this:
Ext.namespace() – this takes a variable list of namespace names and creates the objects for you if they don’t exist.
e.g.
1: Ext.namespace("MyNamespaces","MyNamespace.common","MyNamespace.common.dataaccess");
Creating a JavaScript Singleton object
If we want to create a singleton object, i.e. there can only every be one instance of it that is referenced by a global variable, in JavaScript it is very easy. We simply declare the class function inline, returning a new object with the public methods and properties on, directly followed by () parenthesis and assign it to our global variable.
If you want to create private methods and functions then you should be able to see the similarities of this and the JavaScript Class Patterns article.
1: var MySingleton = function(){
2: return {
3: // variables and methods
4: id : 1,
5:
6: test : function()
7: {
8: return this.id;
9: }
10: }
11: }();
JavaScript Class pattern
The following example show a basic template of how to define a JavaScript class. As far as I am aware this is becoming the standard pattern for allowing private and public variables and methods to be implement into a class.
How it works
The function MyClass is the constructor, note the Capitalization of the first letter to denote a constructor. Within the function object we add methods and functions. If we left the object definition as that, then javascript would automatically return the object definition as the result and the methods and properties we added would be public on that object.
Instead we return a new object, not the initial object definition. The new object has all the methods an properties that we wish to expose as public. This is what gets passed back to the calling code. Because of the javascript rules of scope in a function, the new object has access to any variables defined in the initial object definition.
So the first thing we do is create a self variable that is set to this. The public methods can then use the self variable to access any methods or variables that have been assigned to the initial object definition’s ‘this’. In addition any other vars e.g. private1 are accessible by the public functions also.
This all works because javascript closure causes the ‘new object’ to keep a reference to the ‘initial object’ even after the constructor function has returned.
1: // myobject.js
2:
3: function MyClass(param1)
4: {
5: // Private Section
6:
7: // create a reference to this, called self so the self variable
8: // can then be accessed by the public object
9: var self = this;
10:
11:
12: // Totally private variables are defined with var
13: var private1 = "fred";
14:
15:
16: // Private variable that can be accessed by the implementation of the public object only
17: this.private2 = "private2 data";
18:
19:
20: // private functions
21: this.privateMethod1 = function()
22: {
23: alert("private Method 1 called : private1 variable value is (" + private1 + ")");
24: }
25:
26:
27: // public Object defintion which gets returned to the outside world.
28: return {
29: publicVariable : 10,
30:
31: publicMethod1 : function()
32: {
33: alert("public method 1 called");
34: },
35:
36: publicMethod2 : function()
37: {
38: alert("public method 2 called about to call privatemethod1");
39: // Note: this refers to the current object about to returned
40: // to access the private methods, we need to use 'self'
41: self.privateMethod1();
42: alert("Private Variable (private1):" + private1);
43: alert("Private Variable (private2):" + self.private2);
44: }
45:
46: };
47:
48: };
49:
50: // static members and properties
51: MyClass.prototype.staticFunction = function()
52: {
53: alert("Hello from a static function");
54: }
55:
56: MyClass.prototype.staticVar = 69;
A test page to prove the scoping of the private and public members and properties.
1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2: <html>
3: <head>
4: <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5: <title>Untitled Document</title>
6:
7: <script src="myobject.js" type="text/javascript"></script>1:2:3: <link href="./css/ext-all.css" media="screen" rel="stylesheet" type="text/css">4:5:6: <script type="text/javascript">7: var test = new MyClass("Private1 passed in by constructor");8:9: function callPublic1()10: {11: test.publicMethod1();12: }13:14: function callPublic2()15: {16: test.publicMethod2();17: }18:19: function tryCallPrivateMethod1()20: {21: test.privateMethod1();22: }23:24: function tryAccessPrivateVariable()25: {26: alert("Private 1:" + test.private1);27: alert("Private 2:" + test.private2);28: }29:30: function tryAccessPublicVariable()31: {32: alert(test.publicVariable);33: }34:35: function callStaticFunction()36: {37: MyClass.prototype.staticFunction();38: }39:40: function getStaticVariable()41: {42: alert(MyClass.prototype.staticVar);43: }44:45:46:</script>
8:
9: </head>
10:
11: <body>
12: <a href="javascript:callPublic1();">Call Public Method 1</a><br/>
13: <a href="javascript:callPublic2();">Call Public Method 2</a><br/>
14: <br>
15: <a href="javascript:tryCallPrivateMethod1();">Try and call PrivateMethod1</a> This should fail<br/>
16: <a href="javascript:tryAccessPrivateVariable();">Try and access private variable</a> This should return undefined as the variable does not exist<br/>
17: <a href="javascript:tryAccessPublicVariable();">Try and access public variable</a> This should display 10<br/>
18: <br>
19: <a href="javascript:callStaticFunction();">Call static function on class prototype</a><br/>
20: <a href="javascript:getStaticVariable();">Get static variable from class prototype</a> Should display 69<br/>
21: </body>
22: </html>