Sunday, July 29, 2007

addEvent of Javascript


<script type="text/javascript" charset="utf-8">
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini

// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false); // copy handler function.
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
// create a hash table of event types for the element
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one, else this value is 'undefined')
if (element["on" + type]) {
//alert('exist on' + type + ' handler! copy existing event handler to handlers[0]');
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs, Static variable: addEvent.guid
addEvent.guid = 1;

function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};

function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};

function fixEvent(event) {
// add W3C standard event methods, IE has not those methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};

// This little snippet fixes the problem that the onload attribute on the body-element will overwrite
// previous attached events on the window object for the onload event
if (!window.addEventListener) {
document.onreadystatechange = function() {
if (window.onload && window.onload != handleEvent) {
addEvent(window, 'load', window.onload);
window.onload = handleEvent;
}
}
}
</script>

<a href="http://www.baidu.com" id="a1"> baidu </a>

<script type="text/javascript" charset="utf-8">
var a1 = $('a1');
var handler = function (e) {
alert('handler:' + e.type);
Event.stop(e);
};
var otherHandler = function (e) {
alert('otherHandler: ' + e.type + e.eventPhase);
Event.stop(e);
};
var handlerSelf = function (event) {
alert('too much recursion');
//a1.onmouseover(event);
}
a1.onmouseover = handlerSelf; // this handler will override by addEvent function.
addEvent(a1, 'mouseover', handler); // addEvent.guid = 1(handler), element.events['mouseover'][0] = element['on' + 'mouseover'] = handlerSelf, element.events['mouseover'][1] = handler
addEvent(a1, 'click', handler); // addEvent.guid = 1(handler), element.events['click'][1] = handler
addEvent(a1, 'click', otherHandler); // addEvent.guid = 2(otherHandler), element.events['click'][2] = otherHandler

/*
var evts = ("blur,focus,load,resize,scroll,unload,click,dblclick," +
"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
"submit,keydown,keypress,keyup,error").split(",");
evts.each(function (e) {
Element.prototype[e] = function (callback) {
addEvent(this, e, callback);
};
});

var handler = function (evt) {
alert(evt.type + ': ' + evt.eventPhase);
Event.stop(evt);
return false;
};

a1['mouseover'](handler);
removeEvent(a1, 'mouseover', handler); // won't alert evt.type, unless comment this line.

a1.click(handler); // alert evt.type
*/
</script>

Thursday, July 26, 2007

Rhino javascript shell

firstly, download mozilla rhino.
$> unzip rhino.zip
$> cd rhino
$> export CLASSPATH=$CLASSPATH:/${toYourRhinoPath}/js.jar
$> java org.mozilla.javascript.tools.shell.Main
($> java -classpath js.jar org.mozilla.javascript.tools.shell.Main)
js> quit();

Wednesday, July 25, 2007

usage of form_remote_tag and remote_form_for


<%= form_remote_tag :html => { :action => url_for(:controller => "some", :action => "place", :id => 1), :id => "form_id" }, :update => "ajax_update_div" %></form>

A "fall-through" target for browsers that doesn‘t do JavaScript can be specified with the :action/:method options on :html.
<% form_remote_tag({:html => { :action => url_for(:controller => "other", :action => "place", :id => 1), :id => "form_id", :method => :get }, :url => url_for(:controller => "some", :action => "place", :id => 1), :update => "ajax_update_div"}) do%>
<% end %>

<% remote_form_for :person, @person, :html => {:id => 'form_id', :name => 'form_name', :method => :get, :action => url_for(:controller => 'where', :action => 'some', :id => @person)}, :url => { :action => "test" }, :update => 'ajax_div' do |f| %>
First name: <%= f.text_field :first_name %>
Last name : <%= f.text_field :last_name %>
Biography : <%= f.text_area :biography %>
Admin? : <%= f.check_box :admin %>
<% end %>


form_for(object_name, *args, &proc)
Creates a form and a scope around a specific model object, which is then used as a base for questioning about values for the fields. Examples:

<% form_for :person, @person, :url => { :action => "update" } do |f| %>
First name: <%= f.text_field :first_name %>
Last name : <%= f.text_field :last_name %>
Biography : <%= f.text_area :biography %>
Admin? : <%= f.check_box :admin %>
<% end %>

Worth noting is that the form_for tag is called in a ERb evaluation block, not a ERb output block. So that’s <% %>, not <%= %>. Also worth noting is that the form_for yields a form_builder object, in this example as f, which emulates the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, you get away with f.text_field :name.
That in itself is a modest increase in comfort. The big news is that form_for allows us to more easily escape the instance variable convention, so while the stand-alone approach would require text_field :person, :name, :object => person to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with :person, person and all subsequent field calls save :person and :object => person.
Also note that form_for doesn’t create an exclusive scope. It’s still possible to use both the stand-alone FormHelper methods and methods from FormTagHelper. Example:

<% form_for :person, @person, :url => { :action => "update" } do |f| %>
First name: <%= f.text_field :first_name %>
Last name : <%= f.text_field :last_name %>
Biography : <%= text_area :person, :biography %>
Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %>
<% end %>

Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base. Like collection_select and datetime_select.
Html attributes for the form tag can be given as :html => {…}. Example:

<% form_for :person, @person, :html => {:id => 'person_form'} do |f| %>
...
<% end %>

You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers, then use your custom builder like so:

<% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= text_area :person, :biography %>
<%= check_box_tag "person[admin]", @person.company.admin? %>
<% end %>

In many cases you will want to wrap the above in another helper, such as:

def labelled_form_for(name, object, options, &proc)
form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc)
end

instance __proto__ chain of javascript


The term instance has a specific technical meaning in class-based languages. In these languages, an instance is an individual member of a class and is fundamentally different from a class. In JavaScript, "instance" does not have this technical meaning because JavaScript does not have this difference between classes and instances. However, in talking about JavaScript, "instance" can be used informally to mean an object created using a particular constructor function.
Object Properties
This section discusses how objects inherit properties from other objects in the prototype chain and what happens when you add a property at run time.
Inheriting Properties
Suppose you create the mark object as a WorkerBee (as shown in image) with the following statement:
mark = new WorkerBee;



When JavaScript sees the new operator, it creates a new generic object and passes this new object as the value of the this keyword to the WorkerBee constructor function. The constructor function explicitly sets the value of the projects property, and implicitly sets the value of the internal __proto__ property to the value of WorkerBee.prototype. (That property name has two underscore characters at the front and two at the end.) The __proto__ property determines the prototype chain used to return property values. Once these properties are set, JavaScript returns the new object and the assignment statement sets the variable mark to that object. This process does not explicitly put values in the mark object (local values) for the properties that mark inherits from the prototype chain. When you ask for the value of a property, JavaScript first checks to see if the value exists in that object. If it does, that value is returned. If the value is not there locally, JavaScript checks the prototype chain (using the __proto__ property). If an object in the prototype chain has a value for the property, that value is returned. If no such property is found, JavaScript says the object does not have the property. In this way, the mark object has the following properties and values:
mark.name = "";
mark.dept = "general";
mark.projects = [];
The mark object inherits values for the name and dept properties from the prototypical object in mark.__proto__. It is assigned a local value for the projects property by the WorkerBee constructor. This gives you inheritance of properties and their values in JavaScript. Some subtleties of this process are discussed in Property Inheritance Revisited. Because these constructors do not let you supply instance-specific values, this information is generic. The property values are the default ones shared by all new objects created from WorkerBee. You can, of course, change the values of any of these properties. So, you could give specific information for mark as follows:
mark.name = "Doe, Mark";
mark.dept = "admin";
mark.projects = ["navigator"];


Adding Properties
In JavaScript, you can add properties to any object at run time. You are not constrained to use only the properties provided by the constructor function. To add a property that is specific to a single object, you assign a value to the object, as follows:
mark.bonus = 3000;
Now, the mark object has a bonus property, but no other WorkerBee has this property.
If you add a new property to an object that is being used as the prototype for a constructor function, you add that property to all objects that inherit properties from the prototype. For example, you can add a specialty property to all employees with the following statement:
Employee.prototype.specialty = "none";
As soon as JavaScript executes this statement, the mark object also has the specialty property with the value of "none". The following figure shows the effect of adding this property to the Employee prototype and then overriding it for the Engineer prototype.


Determining Instance Relationships
You may want to know what objects are in the prototype chain for an object, so that you can tell from what objects this object inherits properties.
Starting with JavaScript 1.4, JavaScript provides an instanceof operator to test the prototype chain. This operator works exactly like the instanceof function discussed below. As discussed in Inheriting Properties, when you use the new operator with a constructor function to create a new object, JavaScript sets the __proto__ property of the new object to the value of the prototype property of the constructor function. You can use this to test the prototype chain. For example, suppose you have the same set of definitions already shown, with the prototypes set appropriately. Create a __proto__ object as follows:
chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
With this object, the following statements are all true:
chris.__proto__ == Engineer.prototype;
chris.__proto__.__proto__ == WorkerBee.prototype;
chris.__proto__.__proto__.__proto__ == Employee.prototype;
chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
Given this, you could write an instanceOf function as follows:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype)
return true;
object = object.__proto__;
}
return false;
}
With this definition, the following expressions are all true:
instanceOf (chris, Engineer)
instanceOf (chris, WorkerBee)
instanceOf (chris, Employee)
instanceOf (chris, Object)
But the following expression is false:
instanceOf (chris, SalesPerson)


Global Information in Constructors
When you create constructors, you need to be careful if you set global information in the constructor. For example, assume that you want a unique ID to be automatically assigned to each new employee. You could use the following definition for Employee:
var idCounter = 1;function Employee (name, dept) {
this.name = name || "";
this.dept = dept || "general";
this.id = idCounter++;
}
With this definition, when you create a new Employee, the constructor assigns it the next ID in sequence and then increments the global ID counter. So, if your next statement is the following, victoria.id is 1 and harry.id is 2:
victoria = new Employee("Pigbert, Victoria", "pubs")
harry = new Employee("Tschopik, Harry", "sales")
At first glance that seems fine. However, idCounter gets incremented every time an Employee object is created, for whatever purpose. If you create the entire Employee hierarchy shown in this chapter, the Employee constructor is called every time you set up a prototype. Suppose you have the following code:
var idCounter = 1;
function Employee (name, dept) {
this.name = name || "";
this.dept = dept || "general";
this.id = idCounter++;
}
function Manager (name, dept, reports) {...}
Manager.prototype = new Employee;
function WorkerBee (name, dept, projs) {...}
WorkerBee.prototype = new Employee;
function Engineer (name, projs, mach) {...}
Engineer.prototype = new WorkerBee;
function SalesPerson (name, projs, quota) {...}
SalesPerson.prototype = new WorkerBee;
mac = new Engineer("Wood, Mac");
Further assume that the definitions omitted here have the base property and call the constructor above them in the prototype chain. In this case, by the time the mac object is created, mac.id is 5. Depending on the application, it may or may not matter that the counter has been incremented these extra times. If you care about the exact value of this counter, one possible solution involves instead using the following constructor:
function Employee (name, dept) {
this.name = name || "";
this.dept = dept || "general";
if (name)
this.id = idCounter++;
}
When you create an instance of Employee to use as a prototype, you do not supply arguments to the constructor. Using this definition of the constructor, when you do not supply arguments, the constructor does not assign a value to the id and does not update the counter. Therefore, for an Employee to get an assigned id, you must specify a name for the employee. In this example, mac.id would be 1.


function doc(arg){
document.write(arg);
document.write('
');
}

function Shape() {
this.name = 'shape';
this.borderWidth = 5;
}

function Square() {
this.edge = 12;
}

Square.prototype = new Shape;

myPicture = new Square;

doc($H(Square.prototype).inspect().escapeHTML());
doc($H(myPicture.__proto__).inspect().escapeHTML());

doc(myPicture.constructor);
doc(myPicture.__proto__.constructor);
doc(myPicture.__proto__.__proto__.constructor);
doc(myPicture.__proto__.__proto__.__proto__.constructor);

doc(myPicture.borderWidth);

Monday, July 23, 2007

usage of Prototype Ajax.Responders.register



Ajax.Responders.register({
onCreate: function() {
Ajax.activeRequestCount++;
},

onComplete: function() {
Ajax.activeRequestCount--;
}
});

Ajax.Responders.register(obj) 是将obj注册到Ajax.Responders.responders中,原代码:this.responders.push(responderToAdd) 上面是注册了一个对象,其中包含了二个方法(onCreate和onComplete)。这个obj注册了之后,就成了responders数组中的一个值,在后面Ajax.Responders.dispatch里调用对象responder时会遍历到此obj,callback即为obj中的function name(onCreate和onComplete)。 dispatch里会对所有responders数组中对象执行此callback方法。



Del.icio.us :

Friday, July 20, 2007

call() and apply() of Function methods

These methods allow you to invoke a function as if it were a method of some other object.

<script type="text/javascript" language="JavaScript">

function doc(str){
document.writeln(str);
document.writeln("<br />");
}

var str = 'test';
doc.call(String, str);

// This is similar to the following lines of code:
String.m = doc;
String.m(str);
delete String.m;

</script>

Thursday, July 19, 2007

JavaScript URLs

JavaScript code may appear in a URL that uses the special javascript: pseudo-protocol. The content of such a URL is determined by evaluating the JavaScript code and converting the resulting value to a string. If you want to use a JavaScript URL to execute JavaScript code without returning any document content that would overwrite the current document, use the void operator:
<form action="javascript:void validate( )">

Sunday, July 15, 2007

Javascript keyCode


<script type="text/javascript" charset="utf-8">
<!--
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

function isNumberInput(field, event)
{
var key, keyChar;
if (window.event) {
key = window.event.keyCode;
alert(key);
} else if (event) {
key = event.which;
code = event.keyCode;
var d1 = document.getElementById('d1');
d1.appendChild(document.createTextNode(key + "(key)=" + String.fromCharCode(event.which) + "(code) \n"));
// event.shiftKey and event.altKey, Mozilla provides a mapping for the keys, so you could do something. like:
if (event.keyCode == event.DOM_VK_TAB){
alert('TAB is pressed');
} else if (event.keyCode == event.DOM_VK_F1){
alert('F1 is pressed');
}
} else {
return true;
}
// Check for special characters like backspace(8), enter return(13), tab(9), escape(27) etc.
if (key == null || key == 0 || key == 8 || key == 13 || key == 27) {
return true;
}

// Check to see if it's a number
keyChar = String.fromCharCode(key);
if (/\d/.test(keyChar))
{
window.status = "";
return true;
}
else
{
window.alert("Field accepts numbers only.");
return false; // not input error keypress
}
}
//-->
</script>
<div id="d1">

</div>
<form name="testform" id="testform" action="#" method="get">
Robot Serial Number:
<input type="text" name="serialnumber" id="serialnumber" size="10" maxlength="10"
onkeypress="return isNumberInput(this, event);" title="Serial number contains only digits" />
</form>

Using Keyboard Events

Prior to the release of Netscape 4.0, JavaScript programs couldn't detect keyboard
actions—just mouse actions. This made it difficult to create some types of programs
in JavaScript. For example, games were difficult to play using Go Left and Go Right
buttons.

Thankfully, JavaScript 1.2 and later can detect keyboard actions. The main event
handler for this purpose is onKeyPress, which occurs when a key is pressed and
released, or held down. As with mouse buttons, you can detect the down and up parts
of the keypress with the onKeyDown and onKeyUp event handlers.

Of course, you may find it useful to know which key the user pressed. You can find
this out with the event object, which is sent to your event handler when the event
occurs. In Netscape, the event.which property stores the ASCII character code for the
key that was pressed. In Internet Explorer, event.keyCode serves the same purpose.

NOTE

ASCII (American Standard Code for Information Interchange) is the standard numeric
code used by most computers to represent characters. It assigns the numbers 0–128 to
various characters—for example, the capital letters A through Z are ASCII values 65
to 90.

Displaying Typed Characters

If you'd rather deal with actual characters than key codes, you can use the
fromCharCode string method to convert them. This method converts a numeric ASCII code
to its corresponding string character. For example, the following statement converts
Netscape's event.which property to a character and stores it in the key variable:

Key = String.fromCharCode(event.which);

Since Internet Explorer and Netscape have different ways of returning the key code,
displaying keys browser-independently is a bit harder. However, you can create a
script that displays keys for either browser. The following function will display
each key in the status line:

function DisplayKey(e) {
if (e.keyCode) keycode=e.keyCode;
else keycode=e.which;
character=String.fromCharCode(keycode);
window.status += character;
}

The DisplayKey function receives the event object from the event handler and stores
it in the variable e. It checks whether the e.keyCode property exists, and stores it
in the keycode variable if present. Otherwise, it assumes the browser is Netscape and
assigns keycode to the e.which property.

Key Pressed Javascript Key Code
backspace 8
tab 9
enter 13
shift 16
ctrl 17
alt 18
pause/break 19
caps lock 20
escape 27
page up 33
page down 34
end 35
home 36
left arrow 37
up arrow 38
right arrow 39
down arrow 40
insert 45
delete 46
0 48
1 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
a 65
b 66
c 67
d 68
e 69
f 70
g 71
h 72
i 73
j 74
k 75
l 76
m 77
n 78
o 79
p 80
q 81
r 82
s 83
t 84
u 85
v 86
w 87
x 88
y 89
z 90
left window key 91
right window key 92
select key 93
numpad 0 96
numpad 1 97
numpad 2 98
numpad 3 99
numpad 4 100
numpad 5 101
numpad 6 102
numpad 7 103
numpad 8 104
numpad 9 105
multiply 106
add 107
subtract 109
decimal point 110
divide 111
f1 112
f2 113
f3 114
f4 115
f5 116
f6 117
f7 118
f8 119
f9 120
f10 121
f11 122
f12 123
num lock 144
scroll lock 145
semi-colon 186
equal sign 187
comma 188
dash 189
period 190
forward slash 191
grave accent 192
open bracket 219
back slash 220
close braket 221
single quote 222

select options manuplation of javascript


<form action="" method="get" accept-charset="utf-8">
<strong>Single Robot Choice:</strong>
<select name="robot" id="robot">
<option value="1">Security</option>
<option value="2">Trainer</option>
<option value="3">Friend</option>
<option value="4">Cook</option>
</select>
<br /><br />
<strong>Multiple Robot Choice:</strong>
<select name="robotMulti" id="robotMulti" size="4" multiple="multiple">
<option value="a">Security</option>
<option value="g">Trainer</option>
<option value="s">Friend</option>
<option value="d">Cook</option>
</select>

<input type='button' value='-' name='button1'>
</form>

<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

function selectedItems (obj) {
var o = obj.options;
var s = '';
for(var i in o) {
if(o[i].selected){
s += 'index="' + i + '": selected options text="' + o[i].text + '", selected options value="' + o[i].value + '"; ';
}
}
alert(s);
}

var select1 = document.forms[0].robot
var select2 = document.forms[0].robotMulti

// doc(select1);
// alert(select2.multiple);

select1.onchange = function () {
alert('selected text = "' + select1.options[select1.selectedIndex].text + '"; selected index="' + select1.selectedIndex + '"; option index ="' + select1.options[select1.selectedIndex].index + '" ');
}

document.forms[0].button1.onclick = function() {
selectedItems(select2);
}

</script>

Saturday, July 14, 2007

DOM manipulate of Javascript


<div id="div1"></div>

<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

function insertAfter (newNode, refNode) {
if (refNode.parentNode){
var nextNode = refNode.nextSibling;
if (nextNode){
this.insertBefore(newNode, nextNode);
} else {
this.appendChild(newNode);
}
}
}
HTMLTableCellElement.prototype.insertAfter = insertAfter;

var frag = document.createDocumentFragment();
var d1 = document.getElementById('div1');
var table = document.createElement('table');
var tr = document.createElement('tr');
var td = document.createElement('td');
var coms = document.createComment('test comment');
var attr = document.createAttribute('style');
var textNode1 = document.createTextNode(' this is text node 1! ');
var textNode2 = document.createTextNode(' this is text node 2! ');
var textNode3 = document.createTextNode(' 33333! ');
var clonedText = textNode3.cloneNode(false);

frag.appendChild(table);
table.appendChild(tr);
tr.appendChild(td);
td.appendChild(textNode1);
td.insertBefore(coms, textNode1);
td.insertBefore(textNode2, textNode1);
td.insertAfter(clonedText, textNode1);

var clonedTr = tr.cloneNode(true);
table.appendChild(clonedTr); // this is text node 2! this is text node 1! 33333!
d1.appendChild(frag);

textNode2.data = ' 22222! '; // 22222! this is text node 1! 33333!
td.setAttribute('style', 'background-color: #ddd');
// td.style.backgroundColor = '#ccc';
td.style.border = 'red solid 1px';

doc(frag);
doc(clonedText);
doc(td);
</script>

lookahead of regexp of javascript


<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

var pp = /^\d(?=\.\d+)/; // pattern positive lookahead
doc('3.14'.match(pp));
doc('3.'.match(pp));
doc('.14'.match(pp));

var pn = /^\d(?!\.\d+)/; // pattern negative lookahead
doc('3'.match(pn));
doc('3.14'.match(pn));
doc('.14'.match(pn));
</script>

Javascript tips of functions usage

These tips are suggested as good programming practices and should lead to easier-to-maintain code.
Define All Functions for a Script First The reason for this tip should be obvious: we need to make sure a function is defined and read by a browser before we can invoke it. Secondarily, if we define all the functions that our code will use in one place, it makes functions easier to find.
Name Functions Well When naming functions and variables, you need to be a little careful. Because functions and variables share the same namespace, you shouldn’t be declaring variables and functions with the same name. It might be a good idea to precede function names with “func” or some other string or letter of your own choosing. So, using such a scheme, if we had a variable named hello and wanted to define a function also called hello, we would use funcHello.
Note
Some developers prefer different casing to distinguish between variables and functions, but this may not be obvious enough. The choice is a matter of style and we leave it open for readers to decide for themselves.
Besides the obvious collision of names, very subtle bugs may slip in when we have similar names, particularly when you consider that functions are created when the document is parsed, while variables are created when the script is run. Notice in the following script how there is a variable as well as a function called x.
var x = 5;
function x()
{
alert("I'm a function!");
}
alert(typeof x);

You might expect the alert to show x to be a function or, more appropriately, an object because it appears to be defined second. However, as you can see here, it is a number.
The output makes sense if you consider when the function and variables are actually created. The function is created as the script is parsed, while the variable gets created as the script runs. While this was a contrived example, it illustrates the importance of understanding how things are created in JavaScript.
Consider Using Linked .js Files for Functions, But Be Cautious While many JavaScript programmers like to put functions in external files, we need to make sure that a function is available before calling it. For example, if we have two .js files (lib1.js and lib2.js), each of which calls functions found in the other, we may have to check to make sure the function is available before calling it because the browser might finish loading one script before the other. In the main document, we would define variables showing the files being loaded as false:
var lib1Loaded = false;
var lib2Loaded = false;

Then, in each of the loaded documents the last line would set the corresponding variables to true. Using this scheme, we would then make sure to look at the value of the variables lib1Loaded or lib2Loaded before any functions that are contained in the files are called. For example:
if (lib1Loaded)
doSomething(x,y,z)

Most of the time such efforts aren’t required, but JavaScript designers should be careful to consider the load order of documents and what happens if certain parts of a script are invoked before an entire document has loaded.
Use Explicit Return Statements Even if your function will not return any values, insert a return statement anyway. JavaScript being an interpreted language, keeping the interpreter from having to do any extra work or make any assumptions should produce better running scripts.
Write Stand-Alone Functions As always, you should practice modular design and pass data into and out from functions using only function arguments, the return statement, and data values that are passed by reference. We should avoid side-effects such as changing global values from within functions. Local variables should always be used to perform calculations that are unique to a function, and hidden functions can be used in the same manner to create special-purpose functions that are not needed anywhere else. The value of going through the trouble to create stand-alone functions in this fashion is that such functions can be reused without worry in a variety of situations.

static variable of Javascript


<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

// Define a static variable to hold the running static_var over all calls
// Can't claim static variable with key "var", this is function Object's properties
function doSome (a) {
doSome.static_var ++;
return a + doSome.static_var;
}
doc(typeof doSome); //function Object
doSome.static_var = 0; // var doSome.static_var = 0 will error.
doc(doSome(1)); //2
doc(doSome(1)); //3
doc(doSome(1)); //4
doSome.static_var = 0;
doc(doSome(1)); //2
for (i in doSome)
{
doc(i);
/*static_var
prototype
bind
bindAsEventListener*/
}
</script>

Class Properties
In addition to instance properties and properties of prototypes, JavaScript allows you to define class properties (also known as static properties), properties of the type rather than of a particular object instance. An example of a class property is Number.MAX_VALUE. This property is a type-wide constant, and therefore is more logically located in the class (constructor) rather than individual Number objects. But how are class properties implemented?
Because constructors are functions and functions are objects, you can add properties to constructors. Class properties are added this way. Though technically doing so adds an instance property to a type’s constructor, we’ll still call it a class variable. Continuing our example,

doSome.static_var = 0;

defines a class property of the doSome object by adding an instance variable to the constructor. It is important to remember that static properties exist in only one place, as members of constructors. They are therefore accessed through the constructor rather than an instance of the object.
As previously explained, static properties typically hold data or code that does not depend on the contents of any particular instance. The toLowerCase() method of the String object could not be a static method because the string it returns depends on the object on which it was invoked. On the other hand, the PI property of the Math object (Math.PI) and the parse() method of the String object (String.parse()) are perfect candidates, because they do not depend on the value of any particular instance. You can see from the way they are accessed that they are, in fact, static properties. The isMetallic property we just defined is accessed similarly, as doSome.static_var.

Objects Are Reference Types


Objects Are Reference Types

All JavaScript data types can be categorized as either primitive or reference types.
These two types correspond to the primitive and composite types discussed in Chapter 3.
Primitive types are the primitive data types: number, string, Boolean, undefined, and null.
These types are primitive in the sense that they are restricted to a set of specific values.
You can think of primitive data as stored directly in the variable itself.
Reference types are objects, including Objects, Arrays, and Functions. Because these types can
hold very large amounts of heterogeneous data, a variable containing a reference type does not
contain its actual value. It contains a reference to a place in memory that contains the actual data.

This distinction will be transparent to you the majority of the time.
But there are some situations when you need to pay particular attention
to the implications of these types. The first is when you create two or
more references to the same object. Consider the following example with primitive types:
var x = 10;
var y = x;
x = 2;
alert("The value of y is: " + y);
This code behaves as you would expect. Because x has a primitive type (number),
the value stored in it (10) is assigned to y on the second line. Changing the value
of x has no effect on y because y received a copy of x’s value. The result is shown here:

Now consider similar code using a reference type:
var x = [10, 9, 8];
var y = x;
x[0] = 2;
alert("The value of y's first element is: " + y[0]);
The result might be surprising:

Because arrays are reference types, the second line copies the reference to x’s data into y.
Now both x and y refer to the same data, so changing the value of this data using either
variable is naturally visible to both x and y.

test and exec of Javascript Regular Expression


<script type="text/javascript" charset="utf-8">
var p = new RegExp("http", "i");
document.write(p.test("Http://www.google.com"));

var customer = "Alan Turing 555-1212";
var pattern = /(\w+) \w+ ([\d-]{8})/;
document.write("<br/>" + pattern.test(customer));
if (pattern.test(customer))
{
document.write("<br/>Groups Results:");
document.write(RegExp.$1 + " " + RegExp.$2);
}

var cat = new RegExp("cat", "im");
var inputStr = "where is the white cat and the blank cat?";
var rs = cat.exec(inputStr);
document.write("<br/><br/>rs.length = " + rs.length);
document.write("<br/>rs.index = " + rs.index);
document.write("<br/>cat.global = " + cat.global);
document.write("<br/>cat.multiline = " + cat.multiline);
document.write("<br/>cat.ignoreCase = " + cat.ignoreCase);
document.write("<br/>cat.source = " + cat.source);
document.write("<br/>cat.lastIndex = " + cat.lastIndex);
document.write("<br/>rs.input = " + rs.input);
document.write("<br/>");
document.write("<br/>RegExp['$_'] = " + RegExp['$_']);
document.write("<br/>RegExp['$&] = " + RegExp['$&']);
document.write("<br/>rs = " + rs);

var lucky = "The lucky numbers are 3, 14, and 27";
var pattern = /\d+/;
document.writeln("<br/>" + "Without global we get:");
document.writeln("<br/>" + pattern.exec(lucky));
document.writeln("<br/>" + pattern.exec(lucky));
document.writeln("<br/>" + pattern.exec(lucky));
pattern = /\d+/g;
document.writeln("<br/>" + "With global we get:");
document.writeln("<br/>" + pattern.exec(lucky));
document.writeln("<br/>" + pattern.exec(lucky));
document.writeln("<br/>" + pattern.exec(lucky));
</script>

Friday, July 13, 2007

Javascript Debugger functions


<script type="text/javascript" charset="utf-8">
// Helper function to parse out the name from the text of the function
function getFunctionName(f)
{
if (/function (\w+)/.test(String(f)))
return RegExp.$1;
else
return "";
}

// Manually piece together a stack trace using the caller property
function constructStackTrace(f)
{
if (!f)
return "";

var thisRecord = getFunctionName(f) + "(";

for (var i=0; i< f.arguments.length; i++) {
thisRecord += String(f.arguments[i]);
// add a comma if this isn’t the last argument
if (i+1 < f.arguments.length)
thisRecord += ", ";
}

return thisRecord + ")\n" + constructStackTrace(f.caller);
}

// Retrieve a stack trace. Works in Mozilla and IE.
function getStackTrace() {
var err = new Error;
// if stack property exists, use it; else construct it manually
if (err.stack)
return err.stack;
else
/* alert(getStackTrace.caller);*/
return constructStackTrace(getStackTrace.caller);
}

function a(x)
{
document.writeln(x);
document.writeln("<br/>\n----Stack trace below----\n<br/>");
document.writeln(getStackTrace());
/* document.writeln((new Error).stack);*/
}
function b(x) {
a(x+1);
}
function c(x) {
b(x+1);
}
c(10);
</script>

Thursday, July 12, 2007

Prototype of Javascript


<script type="text/javascript" charset="utf-8">
function doc (argument) {
document.write(argument);
document.write("<br />\n");
}

function Google (name) {
// constructor body...
var url = 'http://www.google.com';
this.url = url;
this.name = name;
}

Google.prototype.desc = "this is google.";
Google.prototype.title = "GOOGLE";
Google.prototype.toString = function () {
return "Object [Google].";
}

var g = new Google('yu');
doc('g=' + g);
g.test = 'test';
doc("g.test=" + g.test);
doc("g['test']=" + g['test']);
doc("g.url=" + g.url);

g = null;

function ExtGoogle (argument) {
this.ext = argument;
}

ExtGoogle.prototype = new Google('yu'); // before toString and ajax function.
ExtGoogle.prototype.toString = function () { return "Object [ExtGoogle]."};
ExtGoogle.prototype.ajax = function (url) {return 'Ajax function.'}

doc('');
var e = new ExtGoogle('yu');
doc(e.ajax('Google'));
doc(e);
doc("e['ext']=" + e['ext']);
doc(e.url);
doc(e.title);

e = null;
</script>

Tuesday, July 10, 2007

Memory leak profiling with Rails


# author: scott@sigkill.org
# http://scottstuff.net/blog/articles/2006/08/17/memory-leak-profiling-with-rails
class MemoryProfiler

DEFAULTS = {:delay => 10, :string_debug => false}

def self.start(opt = {})
opt = DEFAULTS.dup.merge(opt)

Thread.new do
prev = Hash.new(0)
curr = Hash.new(0)
curr_strings = []
delta = Hash.new(0)

file = File.open('log/memory_profiler.log', 'w')

loop do |i|
begin
GC.start
curr.clear
curr_strings = [] if opt[:string_debug]

ObjectSpace.each_object do |o|
curr[o.class] += 1 # Marshal.dump(o).size rescue 1
if opt[:string_debug] and o.class == String
curr_strings.push o
end
end

if opt[:string_debug]
File.open("log/memory_profiler_strings#{Time.now.to_i}.log", 'w') do |f|
curr_strings.sort.each do |s|
f.puts s
end
end
curr_strings.clear
end

delta.clear
(curr.keys + delta.keys).uniq.each do |k,v|
delta[k] = curr[k] - prev[k]
end

file.puts "Top 20"
delta.sort_by { |k, v| -v.abs }[0..19].sort_by { |k, v| -v}.each do |k, v|
file.printf "%+5d: %s (%d)\n", v, k.name, curr[k] unless v == 0
end
file.flush

delta.clear
prev.clear
prev.update curr
GC.start
rescue Exception => err
STDERR.puts "** memory_profiler error: #{err}"
end

sleep opt[:delay]
end

end # end loop

end # end Thread.new

end # end def self.start

Monday, July 09, 2007

Ruby instance_eval example


class Klass
def initialize
@secret = 99
end
end
k = Klass.new
p k
p k.instance_eval('self')
k.instance_eval(%q)
p k.instance_eval { self }
puts k.instance_eval { @secret }
puts k.name
p k.methods(false)

k.instance_eval do
def first_name
'yu'
end
end

puts k.first_name

# Evaluates a string containing Ruby source code, or the given block, within the con-
# text of the receiver (obj). To set the context, the variable self is set to obj while the
# code is executing, giving the code access to obj’s instance variables.

k.instance_variable_set(:@secret, 100)
puts k.instance_variable_get(:@secret)

p k.instance_variables

# >> #
# >> #
# >> #
# >> 99
# >> test
# >> ["name"]
# >> yu
# >> 100
# >> ["@secret"]

Ruby binding usage example


class Demo
def initialize(n)
@secret = n
end
def get_binding
return binding()
end
end

d1 = Demo.new(3)
d2 = Demo.new(4)

a1 = d1.get_binding
a2 = d2.get_binding

puts eval("self", a1)
puts eval("@secret", a2)


def get_binding(param)
return binding
end
b = get_binding("hello")
puts eval("param", b)

Friday, July 06, 2007

difference usage obj.send and mod.module_eval


class A
def fred
puts "In Fred"
end

def create_method(name, &block)
self.class.send(:define_method, name, &block) # obj.send
end

def custom_method(name, &block)
self.class.module_eval {define_method(name, &block)} # mod.module_eval, class_eval alias module_eval
# A.module_eval {define_method(name, &block)}
end

define_method(:wilma) { puts "Charge it!" }

end

class B < A
define_method(:barney, instance_method(:fred)) #
end

b = B.new
p b

b.barney

b.wilma

b.create_method(:betty) { puts 'betty' }
b.betty

b.custom_method(:test) {puts 'test'}
b.test

##
#In Fred
#Charge it!
#betty
#test

CLASS AND MODULE DEFINITIONS[programming ruby 2nd]


# programming ruby 2nd
# CLASS AND MODULE DEFINITIONS 373
class OnceTest

# @__#{id.to_i}__ = [__#{id.to_i}__(*args, &block)]
def OnceTest.once(*ids)
for id in ids
module_eval <<-"end;"
alias_method :__#{id.to_i}__, :#{id.to_s}

private :__#{id.to_i}__

def #{id.to_s}(*args, &block)
if @__#{id.to_i}__
puts 'exist cache'
puts @__#{id.to_i}__.inspect
end
(@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
end

end;
end
end

def p1
# complex process
puts 'p1'
return 1
# the body of a particular method should be invoked only once, The value returned by that first call should be cached.
end

def p2
# complex process
puts 'p2'
return 2
# 方法体内语句只会执行一次,方法返回的结果会被缓存。
end

once :p1, :p2
# 这些方法都要在此语句之前定义
# 原来的p1和p2方法在once里被重新定义了一个同名方法
# 原来方法名被改为__#{id.to_i}__,格式如:(__nnn__)
# 在once方法体里将原来方法调用后生成的结果放到@__#{id.to_i}__这个实例变量中
# 第二次调用相同方法体时,直接返回@__#{id.to_i}__
end

o = OnceTest.new
3.times do |i|
o.p1
o.p2
end

#p1
#p2
#exist cache
#[1]
#exist cache
#[2]
#exist cache
#[1]
#exist cache
#[2]

install ruby gc patch and usage of railsbench

use one of: base, comp, comp_gc, convert_raw_data_files, diff, diff_gc, generate
_benchmarks, help, html, install, path, perf_comp, perf_comp_gc, perf_diff, perf
_diff_gc, perf_html, perf_plot, perf_plot_gc, perf_prof, perf_run, perf_run_gc,
perf_table, perf_tex, perf_times, perf_times_gc, plot, plot_gc, postinstall, pro
f, readme, run, run_gc, run_urls, table, tex, times, times_gc
'railsbench help' displays README
'railsbench cmd help' displays help for given command

==================================================
RAILSBENCH INSTALLATION
==================================================

STEP 1: installing railsbench and PATH modification
---------------------------------------------------

If you obtained and installed railsbench as a gem, a script called
railsbench is available in your Ruby bin directory. railsbench is a
simple driver for the railsbench scripts, which are located in the gem
installation directory. Example:

railsbench perf_run 100 -bm=all

Alternatively, add the railsbench script directory to your search
path. The exact place can be found running

railsbench base

which prints the script directory path. Another option is to run

eval `railsbench path`

Since gem packages don't support running postinstall scripts, you will
need to make the scripts executable by running

sudo railsbench postinstall

After performing these steps, individual commands can be run directly:

perf_run 100 -bm=all

# benchmark.yml
# default:
# uri: /
#
# all:
# uri: /admin

The environment variable RAILS_ROOT must be set and point to your apps
base directory, in order for railsbench to work properly.

If you obtained railsbench as a svn checkout, add the railsbench
script directory to your search path.


STEP 2: prepare your application for benchmarking
-------------------------------------------------

Manual installation:

Copy benchmarks.rb and benchmarks.yml into $RAILS_ROOT/config and
edit them to suit your needs. The provided default benchmark.yml
will run the root URL of your app.

Copy benchmarking.rb to $RAILS_ROOT/config/environments and add a
corresponding section to database.yml.

Automatic installation:

Run 'railsbench install'. This will perform all of the above steps
and create a configuration named 'benchmarking' in database.yml
pointing to your development database. In case you are worrying
about possible results, you can call railsbench install --dry-run
first.

In either case, run `railsbench generate_benchmarks'. This will create
a benchmarks.yml file with a benchmark for each controller and action.


STEP 3: optional (but highly recommended)
-----------------------------------------

Patch the ruby garbage collector using rubygc18{45}.patch, depending
on your ruby version. Recompile ruby and copy the ruby binary and
shared libs to where they were previously installed. See GCPATCH for
details on how to influence the patched ruby gc.

[root@localhost soft]$ sudo gem install railsbench
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed railsbench-0.9.2
[root@localhost soft]$ cd ruby-1.8.5
[root@localhost ruby-1.8.5]$ pa
pal2rgb pango-querymodules-32 passwd patch pax
pand paps paste pathchk
[root@localhost ruby-1.8.5]$ pat
patch pathchk
[root@localhost ruby-1.8.5]$ patch -p0 < /usr/local/ruby/
bin/ lib/ share/
[root@localhost ruby-1.8.5]$ patch -p0 < /usr/local/ruby/lib/
libruby-static.a ruby/
[root@localhost ruby-1.8.5]$ patch -p0 < /usr/local/ruby/lib/ruby/
1.8/ gems/ site_ruby/
[root@localhost ruby-1.8.5]$ patch -p0 < /usr/local/ruby/lib/ruby/gems/1.8/gems/railsbench-0.9.2/
bin/ config/ lib/ postinstall.rb README script/
BUGS INSTALL LICENSE PROBLEMS ruby184gc.patch setup.rb
CHANGELOG install.rb Manifest.txt Rakefile ruby185gc.patch test/
[root@localhost ruby-1.8.5]$ patch -p0 < /usr/local/ruby/lib/ruby/gems/1.8/gems/railsbench-0.9.2/ruby185gc.patch
patching file gc.c
Hunk #2 succeeded at 62 (offset 14 lines).
Hunk #4 succeeded at 225 (offset 14 lines).
Hunk #6 succeeded at 428 (offset 14 lines).
Hunk #8 succeeded at 582 (offset 14 lines).
Hunk #10 succeeded at 618 (offset 14 lines).
Hunk #11 succeeded at 1254 (offset -3 lines).
Hunk #12 succeeded at 1334 (offset 14 lines).
Hunk #13 succeeded at 1364 (offset -3 lines).
Hunk #14 succeeded at 1391 (offset 14 lines).
Hunk #15 succeeded at 1393 (offset -3 lines).
Hunk #16 succeeded at 1431 (offset 14 lines).
Hunk #17 succeeded at 1422 (offset -3 lines).
Hunk #18 succeeded at 1647 (offset 14 lines).
Hunk #19 succeeded at 1647 (offset -3 lines).
Hunk #20 succeeded at 1760 (offset 27 lines).
Hunk #21 succeeded at 1854 (offset -58 lines).
Hunk #22 succeeded at 2409 (offset 27 lines).

Wednesday, July 04, 2007

Rails中的flash[:notice]错误使用的提示


NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.size):
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/cgi_process.rb:228:in `set_content_length!'
c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/cgi_process.rb:187:in `out'
c:/ruby/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/dispatcher.rb:41:in `dispatch'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/rails.rb:78:in `process'
c:/ruby/lib/ruby/1.8/thread.rb:135:in `synchronize'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/rails.rb:76:in `process'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:618:in `process_client'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:617:in `each'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:617:in `process_client'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:736:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:736:in `initialize'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:736:in `new'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:736:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:720:in `initialize'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:720:in `new'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel.rb:720:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/configurator.rb:271:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/configurator.rb:270:in `each'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/configurator.rb:270:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/bin/mongrel_rails:127:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/lib/mongrel/command.rb:211:in `run'
c:/ruby/lib/ruby/gems/1.8/gems/mongrel-1.0.1-mswin32/bin/mongrel_rails:243
c:/ruby/bin/mongrel_rails:16:in `load'
c:/ruby/bin/mongrel_rails:16


如果没有赋值给flash[:notice],直接在View里调用抛出上面的错误,因为flash[:notice] = nil。


Tuesday, July 03, 2007

Installing eruby in Apache [programming ruby]

If you want to use erb-like page generation for a Web site that gets a reasonable amount
of traffic, you’ll probably want to switch across to using eruby, which has better per-
formance. You can then configure the Apache Web server to automatically parse Ruby-
embedded documents using eRuby, much in the same way that PHP does. You create
Ruby-embedded files with an .rhtml suffix and configure the Web server to run the
eruby executable on these documents to produce the desired HTML output.

To use eruby with the Apache Web server, you need to perform the following steps.
1. Copy the eruby binary to the cgi-bin directory.
2. Add the following two lines to httpd.conf.
AddType application/x-httpd-eruby .rhtml
Action application/x-httpd-eruby /cgi-bin/eruby
3. If desired, you can also add or replace the DirectoryIndex directive such that
it includes index.rhtml. This lets you use Ruby to create directory listings for
directories that do not contain an index.html. For instance, the following direc-
tive would cause the embedded Ruby script index.rhtml to be searched for and
served if neither index.html nor index.shtml existed in a directory.
DirectoryIndex index.html index.shtml index.rhtml
Of course, you could also simply use a sitewide Ruby script as well.
DirectoryIndex index.html index.shtml /cgi-bin/index.rb

Ruby url_encode

require 'cgi'
require 'erb'
require 'uri'

str = "<a href='http://www.google.com'>'Stop!' said Fred</a>"
url_encoded_string = CGI::escape(str)
puts url_encoded_string

url_encoded_str2 = URI::escape(str)
puts url_encoded_str2

url_encoded_3 = ERB::Util.url_encode(str)
puts url_encoded_3

# >> %3Ca+href%3D%27http%3A%2F%2Fwww.google.com%27%3E%27Stop%21%27+said+Fred%3C%2Fa%3E
# >> %3Ca%20href='http://www.google.com'%3E'Stop!'%20said%20Fred%3C/a%3E
# >> %3Ca%20href%3D%27http%3A%2F%2Fwww.google.com%27%3E%27Stop%21%27%20said%20Fred%3C%2Fa%3E

3个方法输出的结果都不一样,最后用ERB::Util.url_encode(str)方法获取得同php5中的urlencode()方法得到的结果。

Extending irb [programming ruby chapter15]

Because the things you type to irb are interpreted as Ruby code, you can effectively
extend irb by defining new top-level methods. For example, you may want to be able to
look up the documentation for a class or method while in irb. If you add the following to
your .irbrc file, you’ll add a method called ri, which invokes the external ri command
on its arguments.
def ri(*names)
system(%{ri #{names.map {|name| name.to_s}.join(" ")}})
end
The next time you start irb, you’ll be able to use this method to get documentation.
irb(main):001:0> ri Proc
--------------------------------------------------------- Class: Proc
Proc objects are blocks of code that have been bound to a set of
local variables. Once bound, the code may be called in different
contexts and still access those variables.
and so on...
irb(main):002:0> ri :strftime
------------------------------------------------------- Time#strftime
time.strftime( string ) => string
---------------------------------------------------------------------
Formats time according to the directives in the given format
string. Any text not listed as a directive will be passed through
to the output string.
Format meaning:
%a - The abbreviated weekday name (``Sun'')
%A - The full weekday name (``Sunday'')
%b - The abbreviated month name (``Jan'')
%B - The full month name (``January'')
%c - The preferred local date and time representation
%d - Day of the month (01..31)
and so on...
irb(main):003:0> ri "String.each"
--------------------------------------------------------- String#each
str.each(separator=$/) |substr| block => str
str.each_line(separator=$/) |substr| block => str
---------------------------------------------------------------------
Splits str using the supplied parameter as the record separator
($/ by default), passing each substring in turn to the supplied
block. If a zero-length record separator is supplied, the string
is split on \n characters, except that multiple successive
newlines are appended together.
print "Example one\n"
"hello\nworld".each |s| p s
and so on...

Monday, July 02, 2007

Ruby attr_accessor使用


class Name
attr_accessor :name

def initialize
@name = ""
p @name.object_id
puts "\n"
end

def set_name(input_name)
name = input_name
self.name = input_name
end

def gets_name
p @name
p @name.object_id
p self.name
p self.name.object_id
end
end

a = Name.new
a.set_name('test')
a.gets_name
p a.name
p a.name.object_id

# >> 1647780
# >>
# >> "test"
# >> 1647790
# >> "test"
# >> 1647790
# >> "test"
# >> 1647790

puts "\n"
a.name = 'text'
a.gets_name
p a.name
p a.name.object_id

# >>
# >> "text"
# >> 1647680
# >> "text"
# >> 1647680
# >> "text"
# >> 1647680


self.name中的self是指当前的实例对象a,而self.name这个方法返回的则是对象a里的实例变量@name的值。
另:R4R第7章内容是关于ruby self的使用,说得非常详细,不同的作用域self代表的是不同的对象。
The default object (self) and scope In this chapter
■ The role of the current or default object, self
■ Scoping rules for variables and constants
■ Method access rules