Tuesday, February 27, 2007

has_many :through

class Media < ActiveRecord::Base
has_many :prices
has_many :price_codes, :through =:prices
end

class Price < ActiveRecord::Base
belongs_to :media
belongs_to :price_code
end

class PriceCode < ActiveRecord::Base
has_many :prices
has_many :medias, :through =:prices
end

Based this exmaple off a recipr in the Rails Recipies Cookbook.

When I manually add data to the underlying tables, I can correctly
display the data through by navigating through the object model.

What I'm having trouble figuring out is how to delete Price records form
the association table.

Within one of my forms I have the following:

<%= link_to 'Destroy', { :action ='destroy_price', :id =@media.id,
:price_code_id =>price_code.id }, :confirm ='Are you sure?', :post =
true %>

Add here is the destroy_price action in the controller:

def destroy_price
Media.find(params[:id]).prices.find(params[:price_code_id]).destroy
redirect_to :action ='show', :id =params[:id]
end

When I call the action the following error is returned:

ActiveRecord::StatementInvalid in MediaController#destroy_price

Mysql::Error: #42S22Unknown column 'prices.id' in 'where clause': SELECT
* FROM prices WHERE (prices.id = '1' AND (prices.media_id = 82)) LIMIT
1

For this example I'm trying to delete the prices record with media_id of
82 and price_code_id of 1. For some reason the sql that is getting
generated by ActiveRecord is using prices.id = '1' rather than
prices.price_code_id = 1.

Not really sure what to do next to attempt to get this to work...

Any ideas would be greatly appreciated.

From an iRB session I can find the Prices record, but trying to destroy
it produces this error. I don't know why it's looking for an id since
there is no id in the prices table:

>>Price.find_by_media_id_and_price_code_id(82,2)
=#"82",
"updated_at"=>"2006-08-08 18:04:35", "price_code_id"=>"2",
"created_at"=>"2006-08-08 18:04:35"}>

>>Price.find_by_media_id_and_price_code_id(82,2).destroy
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'id' in
'where clause': DELETE FROM prices WHERE id = NULL

You NEED an id in the join model. has_many :through won't work without
it.


Josh Susser http://blog.hasmanythrough.com/

has_many :through

我已注意到使用 Rails 关联在创建多对多关系的两种方式上有些混乱。出现混乱是可以理解的,因为 has_many :through 还有些新,写它的文章并不多。

Has_and_belongs_to_many 出现的较早,确定的角色与资料超出了你为什么使用多对多关系的假设。事实上,许多人似乎并没有抓住本质上的区别。

就像我们从观看经典影片所学到的,告诉我们两个预期选择之间的区别最好方式是它们的舞蹈。你得观察每个人的表演。那么我们必须在两者之间选择哪个演员呢?

一、连接表:简单的关联

表:

create_table "dancers_movies", :id => false do |t|

t.column "dancer_id", :integer, :null => false

t.column "movie_id", :integer, :null => false

end

模型:

class Dancer < ActiveRecord::Base

has_and_belongs_to_many :movies

end

class Movie < ActiveRecord::Base

has_and_belongs_to_many :dancers

end

has_and_belongs_to_many 关联的设置很简单。连接表只有被连接模型的外键,没有主键或其它属性。(其它属性使用暂时的 push_with_attributes 来支持,但该特征被废弃了。)此处没有给连接表使用的模型类。

二、连接模型:富关联(Rich Associations)

表:

create_table "appearances", do |t|

t.column "dancer_id", :integer, :null => false

t.column "movie_id", :integer, :null => false

t.column "character_name", :string

t.column "dance_numbers", :integer

end

模型:

class Appearance < ActiveRecord::Base

belongs_to :dancer

belongs_to :movie

end

class Dancer < ActiveRecord::Base

has_many :appearances, :dependent => true

has_many :movies, :through => :appearances

end

class Movie < ActiveRecord::Base

has_many :appearances, :dependent => true

has_many :dancers, :through => :appearances

end

has_many :through 关联对这个简单例子来说很容易设定的,但是当使用其它特征如 polymorphism 时要有些技巧。用于连接模型的表有个主键并包含了类似其它模型的属性。

三、Checking out the moves

下面是对两种操作基本特征的比较

-----------------------------------------------------------------------------------

关联 has_and_belongs_to_many has_many :through

----------------------------------------------------------------------------------

AKA habtm 关联 遍历关联

结构: 连接表(Join Table) 连接模型(Join Model)

主键: 无 有

富关联 否 是

代理集合 是 否

Distinct 选择 是 是

自引用 是 是

早期加载 是 是

多态性 否 是

多向连接 否 是

------------------------------------------------------------------------------------------

该表格内包含了很多东西,现在我们分别看一下:

(1)、结构:

has_and_belongs_to_many 使用了简单的连接表,表的每一行记录只有两个外键。没有为连接表使用模型类的连接记录从不会被直接访问。

has_many :through 更新连接表为一个完整的模型。它使用一个模型类来表现表内的条目。

(2)、主键:

连接表没有主键。我听说一些人,如从外键对创建一个主键,但 Rails 从不为任何东西使用主键。我不能肯定你为什么要得到创建的主键,虽然它可能依据你数据库给你一些性能上的好处。 (我不是一个 DBA ,所以对于主键不想说得太多。)

连接模型有键,就像其它模型。这意味着你可以直接地访问及管理记录。

(3)富关联:

在 Rails 1.1 以前,你使用 push_with_attributes 来存储额外的属性到你的 habtm 连接表内。这样做会带来很多问题,包括随后不能更新属性。Push_with_attributes 现在不再使用了。如果你希望一个带有额外属性的富关联的话,使用连接模型。

(4)、代理集合:

使用 habtm 的一个好处是,关联是个代理集合。这意味着你可以使用关联的 << 方法在连接表内创建条目,就像 has_many 关联。因为连接模型记录有这些额外属性,所以用同样方式来自动创建连接表条目会更复杂。所以你必须手工创建连接模型条目。(更完整的解释,可参阅我的 Why aren't join models proxy collections? 文章。)

(5)、Distinct 选择:

有时候,连接表(或模型)在同样的记录之间可能有多个引用。例如,一个人可能是一本书的作者及插图绘制者。如果你有多个引用,数据库会返回给你所有与你查询相关多条记录。选项 :uniq 告诉关联过滤重复的对象,以便你只得到每个记录的一条显示。这类似于在 SQL 中使用 DISTINCT 关键字,但这是在 Ruby 内而不是数据库内移除重复发生的记录。这篇文章原只由 habtm 支持的 :uniq 才能查到,但现在通过 through 关联也可以查到。

(6)、自引用:

Habtm 与 through 关联都可是自引用的。Users 的朋友用户就是一个自引用关系的例子。你可以通过在关联上使用带有 :foreign_key 与 :association_foreign_key 选项的 habtm 来完成。同样也可以使用 through 关联,因为它的做法不太明显,所以稍后我会写出如何处理它。

(7)、早期加载

Habtm 与 through 关联都通过 :include 选项来支持被关联对象的早期加载。

(8)、多态性:

连接模型与 through 关联可以用 polymorphic 模型类型工作。

(9)、多向连接

一个 habtm 关联只可以连接两个模型。但有时候你需要表现多个模型的关联。例如登记的可能是一位飞行家,一个乘客,及一个座位的分配。使用 through 关联,你可以创建一个连接模型,它连接你需要的多个模型。技巧部分是如何构建可方便地得到被关联对象的查询。

四、And the winner is...

has_and_belongs_to_many 的使用范围狭小。但 has_many :through 则很广泛。

Seriously, there's no way to pick a winner here. Like any engineering decision, choosing a join table or a join model is a matter of picking the right tool for the job (or the right dancer for the part). Now that you've seen our players go head to head, you can make a better choice about who should get that part.

五、回帖部分:

1、David on 2006年4月21日

关于 distinct 选择 ---- 我认为你可以附加 :select 'DISTINCT *' 给关联,类似于: has_many foos, :through => bars, :select 'DISTINCT *'

六、原文网址:
http://blog.hasmanythrough.com/articles/2006/04/20/many-to-many-dance-off
http://my4java.itpub.net/post/9983/216509

Defining Getters and Setters

A getter is a method that gets the value of a specific property. A setter is a method that sets the value of a specific property. You can define getters and setters on any predefined core object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

The following JS shell session illustrates how getters and setters could work for a user-defined object o. The JS shell is an application that allows developers to test JavaScript code in batch mode or interactively.

The o object's properties are:

o.a - a number

o.b - a getter that returns o.a plus 1

o.c - a setter that sets the value of o.a to half of its value


js> o = new Object;
[object Object]
js> o = {a:7, get b() {return this.a+1; }, set c(x) {this.a = x/2}};
[object Object]
js> o.a
7
js> o.b
8
js> o.c = 50
js> o.a
25
js>

This JavaScript shell session illustrates how getters and setters can extend the Date prototype to add a year property to all instances of the predefined Date class. It uses the Date class's existing getFullYear and setFullYear methods to support the year property's getter and setter.
These statements define a getter and setter for the year property.:

js> var d = Date.prototype;
js> d.year getter= function() { return this.getFullYear(); };

js> d.year setter= function(y) { return this.setFullYear(y); };

These statements use the getter and setter in a Date object:

js> var now = new Date;
js> print(now.year);
2000
js> now.year=2001;
987617605170
js> print(now);
Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001

Defining Methods

A method is a function associated with an object. You define a method the same way you define a standard function. Then you use the following syntax to associate the function with an existing object:

object.methodname = function_name

where object is an existing object, methodname is the name you are assigning to the method, and function_name is the name of the function.

You can then call the method in the context of the object as follows:

object.methodname(params);

You can define methods for an object type by including a method definition in the object constructor function. For example, you could define a function that would format and display the properties of the previously-defined car objects; for example,


function displayCar() {
var result = "A Beautiful " + this.year + " " + this.make
+ " " + this.model;
pretty_print(result);
}

where pretty_print is function to display a horizontal rule and a string. Notice the use of this to refer to the object to which the method belongs.

You can make this function a method of car by adding the statement

this.displayCar = displayCar;

to the object definition. So, the full definition of car would now look like

function car(make, model, year, owner) {
this.make = make;
this.model = model;
this.year = year;
this.owner = owner;
this.displayCar = displayCar;
}

Anonymous Function in JavaScript

A function can also be defined inside an expression. This is called a function expression. Typically such a function is anonymous; it does not have to have a name. For example, the function square could have been defined as:

const square = function(number) {return number * number};

This is convenient when passing a function as an argument to another function. The following example shows the map function being defined and then called with an anonymous function as its first parameter:


function map(f,a) {
var result=new Array;
for (var i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}

The call

map(function(x) {return x * x * x}, [0, 1, 2, 5, 10];

returns [0, 1, 8, 125, 1000].

Monday, February 26, 2007

JavaScript and the ECMA Specification

Netscape invented JavaScript, and JavaScript was first used in Netscape browsers. However, Netscape is working with ECMA (European Computer Manufacturers Association) to deliver a standardized, international programming language based on core JavaScript. ECMA is an international standards association for information and communication systems. This standardized version of JavaScript, called ECMAScript, behaves the same way in all applications that support the standard. Companies can use the open standard language to develop their implementation of JavaScript. The first version of the ECMA standard is documented in the ECMA-262 specification.

New Features in this Release 1.5

JavaScript version 1.5 provides the following new features and enhancements:

Runtime errors. Runtime errors are now reported as exceptions.

Number formatting enhancements. Number formatting has been enhanced to include
Number.prototype.toExponential,
Number.protoytpe.toFixed and
Number.prototype.toPrecision methods.

Regular expression enhancements. The following regular expression enhancements have been added:
Quantifiers
— +, *, ? and {} — can now be followed by a
? to force them to be
non-greedy.

Non-capturing parentheses,
(?:x) can be used instead of capturing parentheses(x). When non-capturing parentheses are used, matched subexpressions are not available as back-references.

Positive and negative lookahead assertions are supported. Both assert a match depending on what follows the string being matched.

The
m flag has been added to specify that the regular expression should match over multiple lines.
Conditional function declarations.
Functions can now be declared inside an if clause.

Function expressions.
Functions can now be declared inside an expression.


Multiple catch clauses. Multiple catch clauses in a try...catch statement are supported.



Getters and Setters. JavaScript writers can now add getters and setters to their objects. This feature is available only in the C implementation of JavaScript.


Constants. Read only named constants are supported. This feature is available only in the C implementation of JavaScript.

JavaScript compared to Java

JavaScript
Object-oriented. No distinction between types of objects. Inheritance is through the prototype mechanism, and properties and methods can be added to any object dynamically.
Variable data types not declared (dynamic typing).
Cannot automatically write to hard disk.

Java
Class-based. Objects are divided into classes and instances with all inheritance through the class hierarchy. Classes and instances cannot have properties or methods added dynamically.
Variable data types must be declared (static typing).
Cannot automatically write to hard disk.

rm [options] files


rm

rm [options] files

Delete one or more files. To remove a file, you must have write permission in the directory that contains the file, but you need not have permission on the file itself. If you do not have write permission on the file, you will be prompted (y or n) to override. rm is often aliased to rm -i, especially for the root user, to protect against inadvertently deleting files.
Options
-d, --directory

Remove directories, even if they are not empty. Available only to a privileged user.

-f, --force

Remove write-protected files without prompting.

--help

Print a help message and then exit.

-i, --interactive

Prompt for y (remove the file) or n (do not remove the file).

--no-preserve-root

Do not treat root (/) specially. This is the default.

--preserve-root

Do not operate recursively on root (/).

-r, -R, --recursive

If file is a directory, remove the entire directory and all its contents, including subdirectories. Be forewarned: use of this option can be dangerous.

-v, --verbose

Verbose mode (print the name of each file before removing it).

--version

Print version information and then exit.

--

Mark the end of options. Use this when you need to supply a filename beginning with -.

To remove a file whose name starts with a `-', for example `-foo', use one of these commands (the same as `mv' command):

rm -- -foo
rm ./-foo

ruby date time parse

require 'parsedate'
res = ParseDate.parsedate("2000-01-01")
stamp = Time.local(*res).to_i
for i in 0 .. 365
time_stamp = stamp + 24 * 60 * 60 * i
t = Time.at(time_stamp)
actual_date = t.strftime("%Y-%m-%d")
day_of_week = t.strftime("%w").to_i + 1
day_of_month = t.strftime("%d").to_i
day_of_year = t.strftime("%j").to_i
month_of_year = t.strftime("%m").to_i
day_name = t.strftime("%A")
day_short_name = t.strftime("%a")
month_name = t.strftime("%B")
month_short_name = t.strftime("%b")
week_of_year = t.strftime("%W")
actual_year = t.strftime("%Y")

# quarter_of_year
quarter_of_year = (month_of_year - 1) / 3 + 1

# week_of_month
interval = 6
start_date = 0
end_date = day_of_week + 1
for n in 0 .. 5
if day_of_month >= start_date && day_of_month < end_date week_of_month = n + 1 break end start_date = end_date end_date = (n + 1) * interval + day_of_week + 1 end puts actual_date puts week_of_month puts quarter_of_year end


SELECT WEEK('1998-12-31',1);#mysql week() function

Custom Date and Datetime formatting app wide

You can utilize the environment.rb file to overwrite defined settings for the date and time display in rails.

1. ActiveSupport::CoreExtensions::Time::Conversions::
DATE_FORMATS.update(:my_format => '%d %B %Y %H:%M')
2. ActiveSupport::CoreExtensions::Date::Conversions::
DATE_FORMATS.update(:my_format => '%d %B %Y')

In addition, you can also strip the time from presentation

1. ActiveSupport::CoreExtensions::Time::Conversions::
DATE_FORMATS.update(:my_format => '%d %B %Y')

You can call the symbol (:my_format) whatever you like for multiple formatting calls. And finally, to call it in the app:

1. modelname.created_at.to_s :my_format

e.g., in my show.rhtml for my project model:

1. @project.created_on.to_s :my_format

http://www.railsweenie.com/forums/2/topics/777

Sunday, February 25, 2007

JavaScript Language Fundamentals

The following points are core principles of JavaScript:
Excess white space is ignored when outside of a regular expression literal or string.
Statements are terminated with a semicolon.
Semicolons are automatically inserted on lines with complete statements. (Returns imply semicolons for complete statements.)
Data is weakly typed.
References to identifiers are resolved using lexical (static) scoping. The one exception to this is class properties of the RegExp object, which are dynamically scoped.
Indices are enumerated beginning with zero.
There are four kinds of available objects: built-in objects, host (browser) objects, document objects and user-defined objects.
It is a prototype-based object oriented language (not class-based in its current incarnation).
Source code is interpreted.
Comments use C++ inline comment style // or C-style block comment /* */.
I/O is limited in most cases to interaction with Web documents and the user (no local filesystem or network access by default).

Good Coding Style Guidelines





















Aspect of JavaScript: Recommendation
Variable identifiers
Use camel-back capitalization and descriptive names that give an indication of what value the variable might be expected to hold. Appropriate variable names are most often made up of one or more nouns.
Function identifiers
Use the camel-back capitalization and descriptive names that indicate what operation they carry out. Appropriate function names are most often made up of one or more verbs.
Variable declarations
Avoid implicitly declared variables as they clutter the global namespace and lead to confusion. Always use var to declare your variables in the most specific scope possible. Avoid global variables whenever possible.
Functions
Pass values that need to be modified by reference by wrapping them in a composite type. Or, alternatively, return the new value that the variable should take on. Avoid changing global variables from inside functions. Declare functions in the document <head> or in a linked .js library.
Constructors
Indicate that object constructors are such by capitalizing the first letter of their identifier.
Comments
Use comments liberally. Complex conditionals should always be commented and so should functions.
Indentation
Indent each block two to five spaces further than the enclosing block. Doing so gives visual cues as to nesting depth and the relationship between constructs like if/else.
Modularization
Whenever possible, break your scripts up into externally linked libraries. Doing so facilitates code reuse and eases maintenance tasks.
Semicolons
Use them. Do not rely on implicit semicolon insertion.

Javascript 出错控制

function reportError(message, url, lineNumber)
{
if (message && url && lineNumber)
alert("An error occurred at "+ url + ", line " + lineNumber +
"\nThe error is: " + message);
return true;
}
window.onerror = reportError; // assign error handler
window.noSuchProperty();

此方法在FF上测试通过。

Properties and Methods of the XMLHTTP Object

The techniques we’ve covered so far use standard browser features for purposes other than that for which they were intended. As such, they lack many features you might want out of RPC-over-HTTP, such as the ability to check HTTP return codes and to specify username/password authentication information for requests. Modern browsers let you do JavaScript RPCs in a much cleaner, more elegant fashion with a flexible interface supporting the needed features missing from the previously discussed hacks.
Internet Explorer 5 and later support the XMLHTTP object and Mozilla-based browsers provide an XMLHTTPRequest object. These objects allow you to create arbitrary HTTP requests (including POSTs), send them to a server, and read the full response, including headers. Table 19-1 shows the properties and methods of the XMLHTTP object.
Table 19-1: Properties and Methods of the XMLHTTP Object
































Property or Method
Description
readyState
Integer indicating the state of the request, either : 0 (uninitialized), 1 (loading), 2 (response headers received), 3 (some response body received), or 4 (request complete).
Onreadystatechange
Function to call whenever the readyState changes.
status
HTTP status code returned by the server (e.g., “200”).
statusText
Full status HTTP status line returned by the server (e.g., “200 OK”).
responseText
Full response from the server as a string.
responseXML
A Document object representing the server's response parsed as an XML document.
abort()
Cancels an asynchronous HTTP request.
getAllResponseHeaders()
Returns a string containing all the HTTP headers the server sent in its response. Each header is a name/value pair separated by a colon, and header lines are separated by a carriage return/linefeed pair.
getResponseHeader(headerName)
Returns a string corresponding to the value of the headerName header returned by the server (e.g., request.getResponseHeader("Set-cookie")).
open(method, url [, asynchronous[, user, password]])
Initializes the request in preparation for sending to the server. The method parameter is the HTTP method to use, for example, GET or POST. The url is the URL the request will be sent to. The optional asynchronous parameter indicates whether send() returns immediately or after the request is complete (default is true, meaning it returns immediately). The optional user and password arguments are to be used if the URL requires HTTP authentication. If no parameters are specified by the URL requiring authentication, the user will be prompted to enter it.
setRequestHeader(name, value)
Adds the HTTP header given by the name (without the colon) and value parameters.
send(body)
Initiates the request to the server. The body parameter should contain the body of the request, i.e., a string containing fieldname=value&fieldname2=value2… for POSTs or the empty string ("") for GETs.


Note
Since the interfaces of these objects as well as their functionality are identical, we’ll arbitrarily refer to both as XMLHTTP objects.

Note
Internet Explorer supports two properties not listed in Table 19-1. The responseBody property holds the server’s response as a raw (undecoded) array of bytes and responseStream holds an object implementing the IStream interface through which you can access the response. Mozilla supports the onload property to which you can set a function that will be called when an asynchronous request completes. However, as these properties are all browser-specific, we don’t discuss them. You can find more information about them on the respective browser vendors’ Web sites.
Some of the properties and methods listed in Table 19-1, such as responseText and getAllResponseHeaders(), won’t be available until the request has completed. Attempting to access them before they’re ready results in an exception being thrown.

Creating and Sending Requests
XMLHTTP requests can be either synchronous or asynchronous, as specified by the optional third parameter to open(). The send() method of a synchronous request will return only once the request is complete, that is, the request completes “while you wait.” The send() method of an asynchronous request returns immediately, and the download happens in the background. In order to see if an asynchronous request has completed, you need to check its readyState. The advantage of an asynchronous request is that your script can go on to other things while it is made and the response received, for example, you could download a bunch of requests in parallel.
To create an XMLHTTP object in Mozilla-based browsers, you use the XMLHttpRequest constructor:
var xmlhttp = new XMLHttpRequest();
In IE, you instantiate a new MSXML XHMLHTTP ActiveX object:
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
Once you have an XMLHTTP object, the basic usage for synchronous requests is
Parameterize the request with open().
Set any custom headers you wish to send with setRequestHeader().
Send the request with send().
Read the response from one of the response-related properties.
The following example illustrates the concept:
if (document.all)
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
else
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://www.example.com/somefile.html", false);
xmlhttp.send("");
alert("Response code was: " + xmlhttp.status)
The sequence of steps for an asynchronous request is similar:
Parameterize the request with open().
Set any custom headers you wish to send with setRequestHeader().
Set the onreadystatechange property to a function to be called when the request is complete.
Send the request with send().
The following example illustrates an asynchronous request:
if (document.all)
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
else
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", window.location);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4)
alert("The text of this page is: " + xmlhttp.responseText);
};
xmlhttp.setRequestHeader("Cookie", "FakeValue=yes");
xmlhttp.send("");
When working with asynchronous requests, you don’t have to use the onreadystatechange handler. Instead, you could periodically check the request’s readyState for completion.

POSTs
You can POST form data to a server in much the same way as issuing a GET. The only differences are using the POST method and setting the content type of the request appropriately (i.e., to “application/x-www-form-urlencoded”).
var formData = "username=billybob&password=angelina5";
var xmlhttp = null;
if (document.all)
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
else if (XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
if (xmlhttp)
{
xmlhttp.open("POST", "http://demos.javascriptref.com/xmlecho.php", false);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.send(formData);
document.write("<hr>" + xmlhttp.responseText + "<hr>");
}

Friday, February 23, 2007

Javascript random Numbers

Random Numbers

Because the Math.random() method returns values between zero and one, you must normalize its return value to fit the range of numbers required of your application. An easy way to get random integers in the range m to n (inclusive) is as follows:
Math.round(Math.random() * (n - m)) + m;
So to simulate a die roll you would use
roll = Math.round(Math.random() * (6 - 1)) + 1;

Thursday, February 22, 2007

Functions and variables conllision of names

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.

Functions as Objects [Javascript 2.0]

JavaScript just about everything that is not primitive data is an object, and functions are no exception. Thus, it is possible to define functions in a much different way than we have seen up until now, by using the keyword new and the Function object. For example, here we define a function and assign it to the variable sayHello. Notice that Function is capitalized, as we are talking about creating an instance of JavaScript’s built-in Function object:
var sayHello = new Function("alert('Hello there');");
Later on we can then use the assigned variable sayHello just like a regular function call:
sayHello();
Because functions are first-class data types, the function can even be assigned to another variable and used by that name instead.
var sayHelloAgain = sayHello;
sayHelloAgain();
To expand the example, we could define a function with a parameter to print out
var sayHello2 = new Function("msg","alert('Hello there '+msg);");
and call it:
sayHello2('Thomas');
The general syntax for the Function() constructor is
var functionName = new Function("argument 1",..."argument n",
"statements for function body");
As we have already seen, functions can have zero arguments, so the actual number of parameters to Function() will vary. The only thing we have to do is pass, as the final argument, the set of statements that are to execute as the body of the function.
If you have coded JavaScript before, you may not have seen this style of function definition and might wonder what its value is. The main advantage of declaring a function using the new operator is that a script can create a function after a document loads.
Note
Since JavaScript 1.2, you can create functions using new anywhere in the script; previously, you could only define them globally and not within a block such as those associated with if statements, loops, or other functions.
Function Literals and Anonymous Functions

As we have seen in the previous section, defining a function using a new operator doesn’t give the function a name. A similar way to define a function without a name and then assign it to something is by using a function literal. Function literals use the function keyword but without an explicit function name.
A simple use of a function literal is
var sayHi = function(name) { alert('Hi my name is '+name); };
sayHi('Fritz');
We assign a function literal to sayHi and can then use it as we would any other function.
The previous example wasn’t particularly compelling, but function literals do have their uses. Their primary use is when creating methods for user-defined objects. A simple example showing function literals used in this manner is presented here. We have defined a function SimpleRobot that is used as an object constructor—a function that creates an object. Within the function we have defined three methods that are assigned function literals.
function SimpleRobot(robotName)
{
this.name = robotName;
this.sayHi = function () { alert('Hi my name is '+this.name); };
this.sayBye = function () { alert('Bye!'); };
this.sayAnything = function (msg) { alert(this.name+' says '+msg); };
}
It is now simple to create an object using the new operator in conjunction with our SimpleRobot constructor function, as shown here:
var fred = new SimpleRobot("Fred");
Invoking the various functions, or, more correctly, methods, is simply a matter of invoking their names, similar to plain function calls:
fred.sayHi();
fred.sayAnything("I don't know what to say");
fred.sayBye();
The result of the previous example is shown here:

You might wonder why not just use the following new-style syntax in the constructor function:
function SimpleRobot(robotName)
{
this.name = robotName;
this.sayHi = new Function ("alert('Hi my name is '+this.name); ");
this.sayBye = new Function ("alert('Bye!'); ");
this.sayAnything = new Function("msg","alert(this.name+' says '+msg);" );
}
The reality is you could, and everything would still operate properly. The only downside to this approach is that it might use substantially more memory, as new function objects are created every time you create a new object.
A similar kind of nameless function doesn’t even get assigned a name at any time. An anonymous function is one that cannot be further referenced after assignment or use. For example, we may want to sort arrays in a different manner than what the built-in sort() method provides; in such cases, we may pass an anonymous function:
var myArray = [2, 4, 2, 17, 50, 8];
myArray.sort( function(x, y)
{
// function statements to do sort
}
);
The creation of an anonymous function is in this case carried out by using a function literal. While the function is accessible to sort() because it was passed a parameter, the function is never bound to a visible name, so it is considered anonymous.

Object-Oriented JavaScript

Object-Oriented JavaScript
Before jumping into the specifics of using JavaScript’s object-oriented features, let’s first understand why an object-oriented approach might be useful. The primary reason is that it allows you to write cleaner scripts, that is, scripts in which data and the code that operates upon it are encapsulated in one place. Consider the Document object. It encapsulates the currently displayed document and presents an interface by which you can examine and manipulate the document in part or as a whole. Can you imagine how confusing document manipulation would be if all of the document-related data and methods were just sitting in the global namespace (i.e., not accessed as document.something but just as something)? What would happen if all of JavaScript’s functionality were so exposed? Even simple programming tasks would be a nightmare of namespace collisions and endless hunting for the right function or variable. The language would be essentially unusable. This is an extreme example, but it illustrates the point. Even smaller-scale abstractions are often best implemented as objects.
But we haven’t really said why it is desirable to have any more advanced object-oriented features in JavaScript than those we’ve already seen (generic Objects with programmer-settable instance properties). The reason is that doing anything but small-scale object-oriented programming with the techniques covered so far would be incredibly laborious. For objects of the same type, you’d be forced to set the same properties and methods of each instance manually. What would be more efficient would be to have a way to specify those properties and methods common to all objects of a certain type once, and have every instance of that type “inherit” the common data and logic. This is the key motivator of JavaScript’s object-oriented features.
Prototype-Based Objects

Java and C++ are class-based object-oriented languages. An object’s properties are defined by its class—a description of the code and data that each object of that class contains. In these languages, a class is defined at compile-time, that is, by the source code the programmer writes. You can’t add new properties and methods to a class at runtime, and a program can’t create new data types while it’s running.
Because JavaScript is interpreted (and therefore has no visible distinction between compile-time and runtime), a more dynamic approach is called for. JavaScript doesn’t have a formal notion of a class; instead, you create new types of objects on the fly, and you can modify the properties of existing objects whenever you please.
JavaScript is a prototype-based object-oriented language, meaning that every object has a prototype, an object from which it inherits properties and methods. When a property of an object is accessed or a method invoked, the interpreter first checks to see if the object has an instance property of the same name. If so, the instance property is used. If not, the interpreter checks the object’s prototype for the appropriate property. In this way the properties and methods common to all objects of that type can be encapsulated in the prototype, and each object can have instance properties representing the specific data for that object. For example, the Date prototype should contain the method that turns the object into a string, because the way it does so is the same for all Date objects. However, each individual Date should have its own data indicating the specific date and time it represents.
The only further conceptual aspect to the way objects work in JavaScript is that the prototype relationship is recursive. That is, an object’s prototype is also an object, and can therefore itself have a prototype, and so on. This means that if a property being accessed isn’t found as an instance property of an object, and isn’t found as a property of its prototype, the interpreter “follows” the prototype chain to the prototype’s prototype and searches for it there. If it still hasn’t been found, the search continues “up” the prototype chain. You might ask, “Where does it end?” The answer is easy: at the generic Object. All objects in JavaScript are ultimately “descendent” from a generic Object, so it is here that the search stops. If the property isn’t found in the Object, the value is undefined (or a runtime error is thrown in the case of method invocation).
Note
The fact that Object is the “superclass” of all other objects explains why we said with confidence in Table 6-2 that the properties and methods listed there are present in every object: because these are exactly the properties and methods of a generic Object!
Now that we’ve explained the theoretical basis for JavaScript’s object-oriented features, let’s see how it translates into implementation. If you’re feeling a bit lost at this point, that’s okay; we’ll reiterate the theory as we cover the concrete details.
Constructors

Object instances are created with constructors, which are basically special functions that prepare new instances of an object for use. Every constructor contains an object prototype that defines the code and data that each object instance has by default.
Note
Before delving any deeper, some commentary regarding nomenclature is appropriate. Because everything in JavaScript except primitive data and language constructs is an object, the term “object” is used quite often. It is important to differentiate between a type of object, for example, the Array or String object, and an instance of an object, for example, a particular variable containing a reference to an Array or String. A type of object is defined by a particular constructor. All instances created with that constructor are said to have the same “type” or “class” (to stretch the definition of class a bit). To keep things clear, remember that a constructor and its prototype define a type of object, and objects created with that constructor are instances of that type.
We’ve seen numerous examples of object creation, for example,
var s = new String();
This line invokes the constructor for String objects, a function named String(). JavaScript knows that this function is a constructor because it is called in conjunction with the new operator.
We can define our own constructor by defining a function:
function Robot()
{

}
This function by itself does absolutely nothing. However, we can invoke it as a constructor just like we did for String():
var guard = new Robot();
We have now created an instance of the Robot object. Obviously, this object is not particularly useful. More information about object construction is necessary before we proceed.
Note
Constructors don’t have to be named with an initial uppercase. However, doing so is preferable because it makes the distinction clear between a constructor (initial uppercase) that defines a type and an instance of a type (initial lowercase).
When a constructor is invoked, the interpreter allocates space for the new object and implicitly passes the new object to the function. The constructor can access the object being created using this, a special keyword that holds a reference to the new object. The reason the interpreter makes this available is so the constructor can manipulate the object it is creating easily. For example, it could be used to set a default value, so we can redefine
our constructor to reflect this ability:
function Robot()
{
this.hasJetpack = true;
}
This example adds an instance property hasJetpack to each new object it creates. After creating an object with this constructor, we can access the hasJetpack property as one would expect:
var guard = new Robot();
var canFly = guard.hasJetpack;
Since constructors are functions, you can pass arguments to constructors to specify initial values. We can modify our constructor again so that it takes an optional argument:
function Robot(needsToFly)
{
if (needsToFly == true)
this.hasJetpack = true;
else
this.hasJetpack = false;
}
// create a Robot with hasJetpack == true
var guard = new Robot(true);
// create a Robot with hasJetpack == false
var sidekick = new Robot();
Note that in this example we could have explicitly passed in a false value when creating the sidekick instance. However, by passing in nothing, we implicitly have done so, since the parameter needsToFly would be undefined. Thus, the if statement fails properly.
We can also add methods to the objects we create. One way to do so is to assign an instance variable an anonymous function inside of the constructor, just as we added an instance property. However, this is a waste of memory because each object created would have its own copy of the function. A better way to do this is to use the object’s prototype.
Prototypes

Every object has a prototype property that gives it its structure. The prototype is a reference to an Object describing the code and data that all objects of that type have in common. We can populate the constructor’s prototype with the code and data we want all of our Robot objects to possess. We modify our definition to the following:
Robot.prototype.hasJetpack = false;
Robot.prototype.doAction = function()
{
alert("Intruders beware!");
};
function Robot(flying)
{
if (flying == true)
this.hasJetpack = true;
}
Several substantial changes have been made. First, we moved the hasJetpack property into the prototype and gave it the default value of false. Doing this allows us to remove the else clause from the constructor. Second, we added a function doAction() to the prototype of the constructor. Every Robot object we create now has both properties:
var guard = new Robot(true);
var canFly = guard.hasJetpack;
guard.doAction();
Here we begin to see the power of prototypes. We can access these two properties (hasJetpack and doAction()) through an instance of an object, even though they weren’t specifically set in the object. As we’ve stated, if a property is accessed and the object has no instance property of that name, the object’s prototype is checked, so the interpreter finds the properties even though they weren’t explicitly set. If we omit the argument to the Robot() constructor and then access the hasJetpack property of the object created, the interpreter finds the default value in the prototype. If we pass the constructor true, then the default value in the prototype is overridden by the constructor adding an instance variable called hasJetpack whose value is true.
Methods can refer to the object instance they are contained in using this. We can redefine our class once again to reflect the new capability:
Robot.prototype.hasJetpack = false;
Robot.prototype.actionValue = "Intruders beware!";
Robot.prototype.doAction = function() { alert(this.actionValue); };

function Robot(flying, action)
{
if (flying == true)
this.hasJetpack = true;
if (action)
this.actionValue = action;
}
We have added a new property to the prototype, actionValue. This property has a default value that can be overridden by passing a second argument to the constructor. If a value for action is passed to the constructor, invoking doAction() will show its value rather than the default ("Intruders beware!"). For example,
var guard = new Robot(true, "ZAP!");
guard.doAction();
results in “ZAP!” being alerted rather than “Intruders beware.”
Dynamic Types
A very important aspect of the prototype is that it is shared. That is, there is only one copy of the prototype that all objects created with the same constructor use. An implication of this is that a change in the prototype will be visible to all objects that share it! This is why default values in the prototype are overridden by instance variables, and not changed directly. Changing them in the prototype would change the value for all objects sharing that prototype.
Modifying the prototypes of built-in objects can be very useful. Suppose you need to repeatedly extract the third character of strings. You can modify the prototype of the String object so that all strings have a method of your definition:
String.prototype.getThirdChar = function()
{
return this.charAt(2);
}
You can invoke this method as you would any other built-in String method:
var c = "Example".getThirdChar(); // c set to 'a'
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,
Robot.isMetallic = true;
defines a class property of the Robot 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 Robot.isMetallic.
Inheritance via the Prototype Chain

Inheritance in JavaScript is achieved through prototypes. It is clear that instances of a particular object “inherit” the code and data present in the constructor’s prototype. But what we haven’t really seen so far is that it is also possible to derive a new object type from a type that already exists. Instances of the new type inherit all the properties of their own type in addition to any properties embodied in their parent.
As an example, we can define a new object type that inherits all the capabilities of our Robot object by “chaining” prototypes:
function UltraRobot(extraFeature)
{
if (extraFeature)
this.feature = extraFeature;
}
UltraRobot.prototype = new Robot();
UltraRobot.prototype.feature = "Radar";
The only new concept in this example is setting UltraRobot’s prototype to a new instance of a Robot object. Because of the way properties are resolved via prototypes, UltraRobot objects “contain” the properties of the UltraRobot object as well as those of Robot:
var guard = new UltraRobot("Performs Calculus");
var feature = guard.feature;
var canFly = guard.hasJetpack;
guard.doAction();
The way the interpreter resolves property access in this example is analogous to the resolution that was previously discussed. The object’s instance properties are first checked for a match, then, if none is found, its prototype (UltraRobot) is checked. If no match is found in the prototype, the parent prototype (Robot) is checked, and the process repeats recursively finally to Object.
Overriding Properties

It is often useful to provide specific properties for user-defined objects that override the behavior of the parent. For example, the default value of toString() for objects is "[object Object]". You might wish to override this behavior by defining a new, more appropriate toString() method for your types:
Robot.prototype.toString = function() { return "[object Robot]"; };
Those classes inheriting from Robot might wish to also override the method, for example:
UltraRobot.prototype.toString = function() { return "[object UltraRobot]"; };
This is not only good programming practice, it is useful in case of debugging as well since “object Object” really doesn’t tell you what you are looking at.

Sunday, February 11, 2007

MAC OS X 10.4.8 快捷命令

文章来源:远景论坛

苹果机快捷键入门简介


一、开机时按下……
滑鼠按键 弹出抽取式媒介(2.4f1版以前的Boot ROM可能不包括退出CD片)
Option键 在配备「New World」韧体系统的机种上叫出「Open Firmware」开机系统选择功能。
苹果键+Option键 按住这两个键,直到电脑发出二次声响,就会改以Mac OS 9开机。
苹果键+x(有时只按住x键) 如果Mac OS 9和Mac OS X在同一个开机用的硬碟区段(partition)上,按这个键会强迫以OS X开机。
苹果键+Option+shift+delete 跳过原定的启动磁碟,改以外接磁碟(或光碟机)开机。这个按键的主要作用,其实是强迫电脑不要从预设的启动磁碟读入系统档案,所以会产生从其他磁碟开机的「副作用」。如果您的Mac是配备SCSI介面的机种,它会从编号(ID)最高的磁碟机往下搜寻,直到找出可以开机的磁碟区段为止。至於在配备IDE介面的机种上则不确定它的搜寻顺序。
苹果键+Option+shift+delete+# 从指定ID的SCSI磁碟开?#代表SCSI编号)。
苹果键+Option+p+r 清除系统参数记忆体(PRAM),必须按住不放,等发出两次响声之後再放开。
苹果键+Option+n+v 清除NV RAM,类似在Open Firmware中做「重置全部」(reset+all)的动作。
苹果键+Option+o+f 开机时进入open firmware。
苹果键+Option+t+v 强制Quadra AV机种使用外接电视机当作显示器。
苹果键+Option+x+o 以唯读记忆体中所烧录的系统软体开机(仅适用於Mac Classic机种)。
苹果键+Option+a+v 强制电脑辨识苹果AV显示器。
c 使用光碟开机。如果原先设定由OS X开机,但光碟机里没有放置开机光碟,则可能会改由OS 9开机。
d 强制以内建磁碟机开机。
n 按住n键直到萤幕上出现Mac标志,电脑会尝试透过BOOTP或TFTP以网路伺服器开机。
r 强制PowerBook重置萤幕设定。
t 强制配备FireWire介面的机种进入外接磁碟模式(FireWire Target Disk mode)。
shift 关闭所有延伸功能(OS 9或OS X之下的Classic环境)。
shift 关闭登入项目,同时也会关闭所有不必要的程式核心(kernel)延伸功能(也就是所谓安全开机模式,仅适用OS X 10.1.3或更新的系统版本)。
苹果键 开机时关闭虚拟记忆体(Virtual Memory,仅适用OS 9或OS X之下的Classic环境)。
空白键 开机时启动延伸功能管理程式(OS 9或OS X之下的Classic环境)。
苹果键+v 开机过程中显示控制台讯息(仅适用OS X)。
苹果键+s 开机後进入单一使用者模式(仅适用OS X)。
苹果键+Option+c+i 先将系统时钟设定为日期1989年9月20日,然後以这个按键组合开机,就可以看到萤幕上显示特殊的系统小秘密(仅适用於Mac IIci机种)。
苹果键+Option+f+x 先将系统时钟设定为日期1990年3月19日,然後以这个按键组合开机,就可以看到萤幕上显示特殊的系统小秘密(仅适用於Mac IIfx机种)。
二、萤幕上出现小Mac笑脸时按下……
空白键 开机时启动延伸功能管理程式(OS 9或OS X之下的Classic环境)。
shift 关闭包括MacsBug(一种程式设计师工具程式)在内的所有延伸功能(OS 9或OS X之下的Classic环境)。
shift+Option 关闭除了MacsBug之外的所有延伸功能(OS 9或OS X之下的Classic环境)。
Control 中断开机过程,进入MacsBug除错模式。
三、系统画面出现後按下……
苹果键+Option 当OS 9或OS X中的Classic环境连接磁碟机时,可以重建磁碟机的桌面档案。
Option 不要开启任何系统视窗(Mac OS 9)。
shift 在系统档案(Finder)启动时暂时不要开启系统视窗。这些视窗并没有被真的关闭,只要您重新开机,这些视窗都就会照常出现(Mac OS X)。
shift 不要执行任何「启动项目」软体(Mac OS 9)。
--------------------------------------------------------------------------------
四、在系统画面中按下……
按住Option键,再以滑鼠游标
按视窗上的关闭方块 关闭所有的系统视窗(除了弹出式视窗之外);按苹果键+Option+w键也可以获得一样的效果。
苹果键+shift+Option+w 关闭所有的系统视窗(包括弹出式视窗)。
苹果键+右箭头键 在档案视窗以列表模式显示时,开启一个档案夹。
苹果键+Option+右箭头键 在档案视窗以列表模式显示时,重复开启档案夹、以及其下所包含的多层档案夹。
苹果键+左箭头键 在档案视窗以列表模式显示时,关闭一个档案夹。
苹果键+Option+左箭头键 在档案视窗以列表模式显示时,重复关闭档案夹、以及其下所包含的多层档案夹。
苹果键+上箭头键 开启上一层档案夹。在Mac OS X中,如果事先并未选定档案夹、而且没有开启任何视窗,这个按键会开启现在使用者的专属目录。
苹果键+Option+上箭头键 开启上一层档案夹,并关闭现用档案夹。
苹果键+Option+shift+上箭头键 将桌面变成现用视窗,并且选择最上层磁碟机。
苹果键+下箭头键 开启选取的项目。在Mac OS X中,如果事先并未选定档案夹、而且没有开启任何视窗,这个按键会开启桌面档案夹。
苹果键+Option+下箭头键 开启选取的项目,并关闭现用的档案夹。
Option+滑鼠按键 按条列档案视窗中的小三角形图像时,可以显示或隐藏下层档案夹中的内容。
tab键 选择名称以下一个英文字母开头的档案夹。
shift+tab键 选择名称以上一个英文字母开头的档案夹。
苹果键+delete 把选取的项目搬进垃圾桶
五、在系统画面中的「视窗」选单中……
苹果键+选取项目 关闭视窗。
苹果键+shift+选取项目 将弹出式视窗归位。
苹果键+Option+选取项目 展开选取的视窗,并关闭其他所有视窗。
Control+选取项目 展开选取的视窗,并隐藏其他视窗的内容。
•Control+Option+选取项目 启动选取视窗,并展开所有的其他视窗。
六、系统启动完毕之後……
在有电源按钮的机种上
电源按钮 在萤幕上显示包括「关机」、「睡眠」、以及「重新开机」按钮的对话框(请参阅下一节)。
苹果键+Control+电源按钮 强制重新开机。这种方式非必要不建议使用,因为有可能损坏磁碟上的资料内容。
Control+苹果键+Option+电源按钮 快速关机。
苹果键+电源按钮 启动程式除错软体(如果已事先安装的话)。较早期的Mac(例如Mac II时代的机器)需要先安装由Paul Mercer所写的除错延伸功能(debugger init)来使用这个功能;不过这个功能在配备68040处理器的Mac机种上,已经成为系统韧体内容的一部份。
苹果键+Option+电源按钮 让後期型式的PowerBook和桌上型Mac进入睡眠状态。
苹果键+Option+Control+电源按钮 重新设定电源管理程式(Power Manager;仅适用PowerBook 500系列)。
shift+fn+Control+电源按钮 重新设定电源管理程式(Power Manager;仅适用PowerBook G3与G4系列)。
七、在没有电源按钮的机种上
Control+退片按钮 「退片」按钮位於新款USB键盘的最右上角,平常用於退出光碟片。按下这个组合可以在萤幕上显示包括「关机」、「睡眠」、以及「重新开机」按钮的对话框(请参阅下一节)。
苹果键+Control+退片按钮 强制重新开机,正常状况下不建议使用。
Control+苹果键+Option+退片按钮 快速关机。
苹果键+退片按钮 启动程式除错软体(如果已事先安装的话)。较早期的Mac(例如Mac II时代的机器)需要先安装由Paul Mercer所写的除错延伸功能(debugger init)来使用这个功能;不过这个功能在配备68040处理器的Mac机种上,已经成为系统韧体内容的一部份。
苹果键+Option+退片按钮 让後期型式的PowerBook和桌上型Mac进入睡眠状态。
八、在所有机种上
苹果键+Option+esc 强迫退出目前使用中的软体。
苹果键+shift+0 让後期型式的PowerBook与桌上型Mac进入睡眠状态,不过在OS X上不适用。如果在可以配备三部软碟机的Mac机种上(如Mac SE),这个按键可以退出第三部软碟机中的碟片。
苹果键+shift+1或2 弹出内藏或外接软碟机中的碟片。在可以配备两部软碟机的Mac(如Mac SE或Mac II)上,则是依次退出两部软碟机种的碟片。
苹果键+shift+3 拍摄萤幕图片
苹果键+shift+4 拍摄使用者定义的萤幕区域。在Mac OS 9中,如果在选定区域时按下Control键,则拍摄的内容会被储存在记忆体中的剪贴板里,可以直接在其他软体中「贴」上文件。
苹果键+shift+大写固定键+4 如果按下大写固定键(也就是「caps lock」键),则可以拍摄使用者选定的视窗内容(仅适用於Mac OS 9或OS X下的Classic环境)。
苹果键+Control+shift+3 将萤幕图片拍摄至记忆体剪贴板。
苹果键+Control+shift+4 将使用者指定的萤幕区域拍摄至记忆体剪贴板。
苹果键+Control+shift+大写固定键+4 将使用者指定的视窗内容拍摄至记忆体剪贴板(仅适用於Mac OS 9或OS X下的Classic环境)。
苹果键+tab 切换执行中应用软体。
苹果键+space 切换使用的语言系统(如果已安装一种以上的语言系统)。
Option+F3、Option+F4、
或是Option+F5 开启Mac OS X的「系统预置」视窗(仅在「系统预置」尚未执行的时候才有作用)。
苹果键+F1 在Mac OS X中侦测显示器。
苹果键+F2 在Mac OS X中切换萤幕同步显示内容。
F12 退出CD或DVD(在 (在Mac OS X 10.1.2或以上的版本中须按住不放)。如果光碟可以被退出,按这个键就会退出。如果不能退出(例如正在使用中),则按键没有作用。
F14 让萤幕变暗(适用於G4 Cube、iMac G4、或许还有其他机种)。
F15 让萤幕变亮(适用於G4 Cube、iMac G4、或许还有其他机种)。
苹果键+Control+shift+0 在执行Mac OS 9的PowerBook上,强制硬碟停止转动。
Option+「清除垃圾」选单指令 不显示「有档案已经锁住」警示,直接清除垃圾桶内容;锁住的项目也会被删除。

--------------------------------------------------------------------------------
九、在睡眠/重新开机对话框中
S键 睡眠
R键 重新开机
esc键 取消
苹果键+.(英文句号) 取消
Return或Enter键 关机
电源按钮 取消(可能仅适用於Mac OS 9.2.x)
十、在其他对话框中
esc键 取消
苹果键+.(英文句号) 取消
Enter键 预设按钮
Return键 预设按钮(如果同时没有其他文字栏位会用到return键)
苹果键+d 不储存(在储存/□取消/□不储存对话框中)
十一、在有「fn」键的键盘上
fn+backspace 往前删除字元
十二、滑鼠按钮
Optionion+以滑鼠游标按
另一个应用软体的视窗 切换到另一软体,并隐藏现用软体。
苹果键+拖移视窗 拖移视窗,但不将该视窗切换至最前方(该应用软体必须支援视窗在对话框之後运作的功能)。
苹果键+拖移视窗内容 在系统视窗中,利用滑鼠游标来搬动视窗的内容。
苹果键+以游标按视窗标题栏 显示该视窗在硬碟中所在位置的路径(基本上仅适用於系统档案视窗,但某些软体也支援这个功能)。
Optionion+按视窗标题栏
两下以隐藏视窗内容 隐藏所有视窗的内容,仅馀标题栏显示在萤幕上(Mac OS 9或Classic环境)、或将视窗全部隐藏至Dock中(Mac OS X)。
Optionion+视窗标题栏中的
缩放方块 将视窗放大至全萤幕。
Optionion+视窗上的黄色按钮 将所有的软体视窗隐藏在Dock中(仅适用Mac OS X)。
Optionion+视窗上的绿色按钮 将视窗放大至全萤幕(仅适用部份软体)。
十三、仅适用Mac OS X的Dock项目
苹果键+滑鼠按钮 显示项目在系统视窗中的位置。
苹果键+Option+滑鼠按钮 启动某一软体、隐藏其他软体
Control+滑鼠按钮
(或以滑鼠按钮按住项目不放) 显示项目特色选单
苹果键+拖移项目至Dock 停止目前的Dock项目移动,以便将其他文件图像拖移到应用软体图像上。
苹果键+Option+拖移项目至Dock 强制Dock上的软体开启拖移上去的文件。
十四、控制条板
Option+拖移整个控制条板 移动控制条板。
Option+拖移某个控制条板模组 重新安排模组的顺序。
Option+将模组拖移至垃圾桶 解除安装某一模组。
Option+将模组拖移至条板以外的地方 将模组档案拷贝到拖移的位置。

Friday, February 09, 2007

Rails 1.2.1 RHTML GB2312编码错误

Rails升级到1.2.1后,RHTML文件中的LINK_TO链接里有中文时,页面编译报错,需要在Config/environment.rb中最后面加$KCODE="GB2312",RHTML用GB2312编码,Application中headers中设置Content-Type为GB2312。

Rails Mysql 中文乱码问题

http://www.7say.com/article.asp?id=201

一、MySQL设置:
将MySQL的Character设置成为utf8(或GBK或GB2312,只要和ROR里的Character设置统一就行)。

修改方法有3种:
1、用MySQL Server Instance Config Wizard设置character-set为utf8;
2、修改MySQL的配置文件,改其中的两处default-character-set= utf8(推荐,改完后重启MySQL生效);
3、在建表时指定表的character-set为utf8

二、Ruby On Rails设置:
修改application.rb告知MySql使用UTF8
下面在@headers.[]=这个方法已经作废,直接用headers.[]=方法。
class ApplicationController < ActionController::Base
before_filter :configure_charsets
def configure_charsets
@headers["Content-Type"] = "text/html; charset=utf-8"
# Set connection charset. MySQL 4.0 doesn’t support this so it
# will throw an error, MySQL 4.1 needs this
suppress(ActiveRecord::StatementInvalid) do
ActiveRecord::Base.connection.execute 'SET NAMES utf8'
end
end
end

三、修改environment.rb
$KCODE = 'u'
require 'jcode'

Ruby on Rails 模板及MYSQL中文乱码问题

原文http://www.javaeye.com/article/34399

1、render使用中的问题
当页面错误要跳转到固定的页面的时候,用了Render
这样的代码,总说页面找不到,没找到原因,后台看了路径显示好像也没有问题
render :file => "#{RAILS_ROOT}/public/404.html",
:status => '404 Not Found'

换成下面的代码就可以了
render :text => File.read("#{RAILS_ROOT}/public/400.html"),
:layout => 'application',
:status => "500 Error"

2、中文字符截取的问题
原理就不多说了,正常用中文或则日文的时候长度是>1的,解决办法
在config/environment.rb里加上一行:
$KCODE = 'utf8'

或则在启动的时候加上ruby.exe -KU script/server
然后就可以用split方法把string转成char来进行截取

<%= @title.split(//)[0,10] %> #截取title字段的前10个字符

3、把开发工具和工程的编码改为UTF-8,能显示中文,但mysql的中文全是乱码

在database.yml里面加上
encoding: utf8

Wednesday, February 07, 2007

Using Zend framework Components In CakePHP

原文

Before we can start baking we have to do some preparations. First of all, this article is for those who are at least familiar with using CakePHP at a very basic level. If you are not yet introduced to CakePHP, please check out the Overview on CakePHP by Fabio Cevasco here at A/R/T. Now, onto the actual preparations:

1. Make sure you installed PHP 5 as the Zend framework requires PHP 5.

2. I assume you have already installed CakePHP. If that is not the case, download it from http://cakeforge.org/projects/cakephp/ and follow the installation instructions on http://manual.cakephp.org/chapter/3. I used version 1.1.6.3264 of CakePHP for this article.

3. Download the Zend framework from http://framework.zend.com/download.

4. Copy the content of the directory ZendFramework-0.1.5/library from the zipped file to /app/vendors.

With that, the preparations are done. We are ready for baking our cake.

Baking, first iteration
In our first iteration we will build the skeleton of our application. Our goal is to get an empty page when calling our controller. Yes, I know, the result of an iteration should be something of value for the user, so this iteration is an exception.

We start with the model which we call simply “Flickr”. What functionality should our model provide? For our simple application we only need one method which returns images for a tag. So we get the following class:

Listing 1 – Toggle plain text mode – Select listing

// app/models/flickr.php
class Flickr extends AppModel
{
var $useTable = false;

function getImagesByTag($tag)
{
return array();
}
}

Notice that we have to add “var $useTable = false;” as our model will use a webservice and not a table.

Our model will be used, of course, by a controller. To make use of CakePHP's magic we name it “FlickrController”. The functionality of our controller is simple: it needs a method which gets the data from the Flickr model and hands the data over to the view. So we can write our controller:

Listing 2 – Toggle plain text mode – Select listing

// app/controllers/flickr_controller.php
class FlickrController extends AppController
{
function show($tag = null)
{
$this->set('images', $this->Flickr->getImagesByTag($tag));
}
}

The last step is the view. It is self-explanatory.

Listing 3 – Toggle plain text mode – Select listing

// app/views/flickr/show.thtml
foreach ($images as $image)
{
}

Our first iteration is almost done. Time to test what we have done. Open /flickr/show/tree in your browser and you should get an empty page. Not really interesting, is it? So we move directly to the second iteration.

Baking, second iteration
The goal of the second iteration is to retrieve images from Flickr and to display them. To include third-party libraries in CakePHP the function “vendor()” is used. We give it a try and add it to our model.

Listing 4 – Toggle plain text mode – Select listing

// app/models/flickr.php
vendor('Zend/Service/Flickr');

class Flickr extends AppModel
{
var $useTable = false;

function getImagesByTag($tag)
{
return array();
}
}

To check if the library can be included we swap to our browser and reload the page. Huch, an error:

Listing 5 – Toggle plain text mode – Select listing

Warning: require_once(Zend/Service/Rest.php) [function.require-once]
:failed to open stream: No such file or directory in
/home/dho/projects/test/app/vendors/Zend/Service/Flickr.php
on line 26

Fatal error: require_once() [function.require]:
Failed opening required 'Zend/Service/Rest.php'
(include_path='.:/usr/share/php:/usr/share/pear:
/home/dho/projects/test:/home/dho/projects/test/app/') in
/home/dho/projects/test/app/vendors/Zend/Service/Flickr.php
on line 26

Hmm, a problem with the include_path. We could add something like “ini_set('include_path',ini_get('include_path').PATH_SEPARATOR . dirname(APP.'vendors/Zend.php'));” to our model, but that is not very elegant. So we write a small helper script we can place in the vendors directory:

Listing 6 – Toggle plain text mode – Select listing

// app/vendors/zend_flickr.php
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR .
dirname(__FILE__));
require_once('Zend/Service/Flickr.php');

In our model we have to adapt the parameter for the “vendor()” function. At the same time we can implement the “getImagesByTag()” method.

Listing 7 – Toggle plain text mode – Select listing

// app/models/flickr.php
vendor('zend_flickr');

class Flickr extends AppModel
{
var $useTable = false;

function getImagesByTag($tag)
{
$result = array();

if (!empty($tag))
{
$flickr = new Zend_Service_Flickr('YOUR_API_KEY');
$result = $flickr->tagSearch($tag);
}

return $result;
}
}

In our controller we do not have to change anything, so we can move directly to our view. In our view we want to display thumbnails of the images with a link to the original image.

The handling of the results from the model is a little bit different from what we are used to with CakePHP. In CakePHP, the data are stored in multi-dimensional arrays, whereas the Zend framework uses arrays of objects.

Listing 8 – Toggle plain text mode – Select listing

// app/views/flickr/show.thtml
foreach ($images as $image)
{
if (is_object($image->Original))
{
echo $html->link($html->image($image->Thumbnail->uri),
$image->Original->uri, null, false, false);
}
}

Notice that we have to add “if (is_object($image->Original))” as for some reason this object is not always set. Now comes the moment of truth, does our application work? We swap to our browser and reload the page. You should see something like:

Time to celebrate our great application. Ehm, wait a moment. There is still some work we have to do.

Baking, third iteration
So we come to the third iteration. The goal of this iteration is to replace our helper script by a more flexible solution.

The helper script works fine for our simple application. But if we want to use multiple Zend framework components it is tedious to write such a helper script for each component we want to use. So we write a simple class to replace our helper script.

Listing 9 – Toggle plain text mode – Select listing

// app/vendors/zend_loader.php
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR .
dirname(__FILE__));

class ZendLoader
{
static function load($lib)
{
require_once('Zend'.DS.$lib.'.php');
}
}

To use our new ZendLoader class we have to make some changes in our model. We have to use “zend_loader” as parameter for the vendor function, and we have to load the component(s) we want to use in the constructor.

Listing 10 – Toggle plain text mode – Select listing

// app/models/flickr.php
vendor('zend_loader');

class Flickr extends AppModel
{
var $useTable = false;

function __construct()
{
ZendLoader::load('Service/Flickr');
}

function getImagesByTag($tag)
{
$result = array();

if (!empty($tag))
{
$flickr = new Zend_Service_Flickr('YOUR_API_KEY');
$result = $flickr->tagSearch($tag);
}

return $result;
}
}

With that we have finished our simple application. Hooray!

Conclusion
As we have seen it is relatively easy to use Zend framework components in a CakePHP application. It allows CakePHP users to profit from the growing number of Zend framework components. A minor disadvantage is that the two frameworks use partly different coding standards, and that the data handling is different: CakePHP uses multi-dimensional arrays whereas the Zend framework uses arrays of objects. But in the final analysis, integration of these two powerful frameworks is a plus for all PHP developers!

Happy baking :)

Daniel Hofstetter is a software engineer from Switzerland. He writes about his experiences using the CakePHP web framework, the CakePHP world, and everything that could be interesting for a cake baker.

MYSQL ODBC 乱码问题

在使用MYSQL5 ODBC时,碰到中文字符变成???这种情况,在网上找了下资料,安装最新MyODBC后,用如下几种方法,分别尝试:
1、建一个 ODBC 数据源,指向你的数据库,并在该数据源配置项 Initial Statement 中填入 SET CHARACTER SET GBK
2、Initial Statement中填入 set names gbk;
3、在Advanced-->Flag 3-->Read Options From my.cnf,并在Windows下建立my.cnf文件,写入:
[client]
default-character-set=gbk

第3个方法尝试后中文数据终于正常显示。

Tuesday, February 06, 2007

Use darwinports

Using DarwinPorts
The port command

Using the DarwinPorts port command is very straight-forward. Most of the time all you need to do is execute a single command to install a port. For example, if you want to install the text editor vile, you would simply type:

sudo port install vile

That will fetch, build and install vile and anything else it needs to work. All of the examples below use the vile for as an example. You should use whatever port you actually want to install.

The port command provides several other 'actions' that can be performed:

Searching

If you aren't sure the exact name of the port you want, you can use the search option. For example, if you wanted to find out if there was anything called vile in in the ports, you could do:

port search 'vile'

The search facility uses standard regular expression syntax, so you can also do much more complex searches.
Additional Steps: fetch, configure, build, destroot, install

You may want to break up the installation of a port into a number of steps. fetch, configure, build, destroot and finally install are all available and perform part of the build or install process. Using the steps individually is not normally needeed unless you are developing a new port or trying to diagnose a problem.
Cleaning a Port

Once the port has been installed, you may want to delete all the intermediate files that DarwinPorts has created while building the port. To do this, simply use the clean option:

port clean vile

It is possible to make the clean option remove the distfile, the archive and the work directory.

To remove the ports distfile

port clean --dist vile

To remove a archive created by a port

port clean --archive vile

To remove the working directory

port clean --work vile or port clean vile

If you want to do all of the above (remove the distfile and archive, and clean the workdirectory), you can:

port clean --all vile
Getting Information about a Port

You may want to get information about a port, such as a description, its maintainer, and more. You can do this by using the info option:

port info vim
Listing available Ports

You may want a list of all the ports that are available. You can do this two ways, first by using the search option:

port search '.+'

Or, by using the list option:

port list
Discovering which ports are installed

To determine which ports have been installed, and what their versions are, use:

port installed

To determine the installed version of a particular port, use:

port installed
Discovering which ports are out-of-date

To determine which ports are out-of-date (the current Portfile provides a newer version than the installed version of the port) use:

port outdated
Contents of a Port

Once the port has been installed, you might want to check what files are associated with that port. The contents option will list all of the files that were installed by the port:

port contents vile
Variants and Dependencies

Before you install a port, you may want to check what variations of that port are available to use. Variants provide additional configuration options for a port. To see what variations a port has, use the variants option:

port variants vile

You also may want to see what dependencies a port has. You can use the deps option to check:

port deps vile

If you want to find out which ports depends on a port you have installed, use:

port dependents gettext

For more information you should look at the port manpage by entering: man port.
The portindex command

Most of the time you won't need to use this command as it is used to build the index of all the available ports, but sometimes the index you have is out of date or innacurate for some reason. When this occurs you will get an error message like 'port search failed: expected integer but got "PortIndex"'. You can fix problem by moving to the dports directory (/Users/mike/darwinports/dports in our examples) and executing: portindex. This will go through all the available ports in the dport directory and build an index file called PortIndex.
Removing ports

Ports are removed using the port command described above, simply execute the command: sudo port uninstall vile
Upgrading ports

You can check if a port is outdated with the following command:
port outdated gnome

To check if you have any outdated ports:
port outdated

To upgrade a port execute:
sudo port upgrade gnome

This will deactivate the old version and install the new, and also install the newer versions of the dependencies of the port.

If you would like to upgrade the port, but not the dependencies of the port, you can:
sudo port -n upgrade gnome

To upgrade all installed ports simply do:
sudo port upgrade installed

If you dont like that upgrade just deactivates the old version of the port, you can get it to uninstall the old version by using the -u option:
sudo port -u upgrade gnome

Using force
While upgrading you can run into cases when you have to use force (-f). This is especially true if you are upgrading a port that wants to install a file that another port allready has installed, or if you use the -u option to upgrade (and uninstall) a port that could be installed as a dependency. Allways remember to use the -f option with caution.

KOMODO editor 中文支持问题

这是Free的一个文本编辑工具,功能强大,尤其喜欢其文字色彩设置。
内置中文支持做得不是很好。需要在Mozilla\components目录下面找到koEncodingServices.py文件,在第80行插入
('GB2312', 'Chinese(GB-2312)', 'GB2312', '', 1,'GB2312'),
('GBK', 'Chinese(GBK)', 'GBK', '', 1,'GBK'),
('GB18030', 'Chinese(GB18030)', 'GB18030', '', 1,'GB18030'),

Compiling GD on Mac OS X HOWTO

1. Introduction and Prerequisites
2. Setting up the environment
3. Getting the archives
4. Unpacking the archives
5. Building zlib
6. Building libpng
7. Building libjpeg
8. Building freetype2
9. Building GD
10. Testing GD
11. Cleaning up
12. If anything fails…

1. Introduction and Prerequisites

This document explains (in the prescriptive, somewhat haughty tone characteristic of other HOWTOS) in a step-by-step fashion the procedure for compiling and installing GD 2.0.33 (the latest version as of 2006-01-19) from sources on Tiger (Mac OS X 10.4). However, this HOWTO also assumes a more-than-passing acquaintance with the Mac OS X Terminal application and the UNIX command line.

I am a tcsh user, and that is what these instructions assume you use as shell. If you are an irredent bash user, do not despair: when applicable, I have noted the differences. If any discrepancies remain, please tell me so that I can correct them.

Also, and this might seem obvious, it is imperative to have installed the Mac OS X Development Tools. It is an excellent idea to keep current with the latest, as available on Apple's ADC site. The instructions assume you have installed the XCode and the X11 SDK, as found on the XCode CD (the third one). If not, things that depend on X11's header files won't work (fontconfig support comes to mind.)

That said, I can't foresee every possible operating environment (and I'm certain to have overlooked some critical assumption or other.) I'm not able to test this procedure on any earlier version of Mac OS X, and I've not taken much care to avoid breakage. I apologize of any inconvenience. In any case, you might find helpful the previous version of this document.

The primary objective of this endeavor was to compile GD4O (GD for OCaml), which I did.

Many thanks to Brad Koehn, Jules, Felipe Wettstein, Scott Forbes, Christie P. Robertson, Ted Fines, Gerd Pleyer and Erik Anderson, whose helpful hints and comments contributed to make this HOWTO more correct.
2. Setting up the environment

First of all, make sure you have /usr/local/bin in your PATH. If you are using tcsh, this variable is slave to the path list variable. Add the following to your .cshrc, .tcshrc or, if you have it, ~/Library/init/tcsh/path:

set path = ( /usr/local/bin ${path} )

If you have bash, add the following to your .profile:

export PATH=/usr/local/bin:$PATH

Probably the easiest thing to do for the changes to take effect is to log out from your terminal session, and then back in. Alternatively, you may source the init script.
3. Getting the archives

Caveat: Whenever there is a choice of archive format (.tar.gz, .tar.bz, .zip), prefer .tar.gz for reasons of uniformity and coherence of the instructions. However, if you are confident in the process, feel free to use the format that you prefer, and be sure to modify the unpacking instructions as appropriate.

Download zlib 1.2.3, libpng 1.2.12 (do not download any later version, as GD 2.0.33 doesn't support it), libjpeg v6b, FreeType 2.1.10, and GD 2.0.33 (version numbers are verified as of 2006-09-25).

The official URLs for these libraries are:

zlib
http://www.gzip.org/zlib/
libpng
http://www.libpng.org/pub/png/libpng.html
libjpeg
ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
freetype2
http://freetype.sourceforge.net/download.html
GD
http://www.boutell.com/gd/

I advise to locally compute and compare MD5 checksums, if the distribution home lists them. You do that by executing:

% md5 filename

4. Unpacking the archives

With all archives in the same directory (on the Desktop, for instance), do:

% ls *gz | xargs -n 1 tar zxvf

(I know, xargs is evil). If you downloaded any Bzipped archives, do:

% ls *.bz2 | xargs -n 1 tar jxvf

5. Building zlib

It's a simple matter of

% cd zlib-1.2.3; ./configure --shared && make && sudo make install

You may omit the --shared parameter if you don't care for shared libraries. If you do, you may test the build by executing ./example after installation.
6. Building libpng

Change into libpng's build directory, and copy the relevant Makefile:

% cd ../libpng-1.2.12
% cp scripts/makefile.darwin Makefile

The Makefile needs configuring to find zlib. You have to uncomment and recomment lines 14–17 to read:

# Where the zlib library and include files are located
ZLIBLIB=/usr/local/lib
ZLIBINC=/usr/local/include
#ZLIBLIB=../zlib
#ZLIBINC=../zlib

Now build and install:

% make && sudo make install

Finally, to test the build, you may execute:

% setenv srcdir .; ./test-pngtest.sh

(If you use bash, use instead export srcdir=.; ./test-pngtest.sh). You could have used configure instead to create the Makefile; however, the compiler options hardwired in makefile.darwin seem to be especially tuned.
7. Building libjpeg

As pointed out to me by a kind correspondent, Mac OS X 10.3 and later ship with GNU libtool, albeit under a slightly different name, glibtool. We need only link to it to build the dynamic version of libjpeg that GD4O needs to work. Change into the build directory:

% cd ../jpeg-6b/
% ln -s `which glibtool` ./libtool

Furthermore, on Mac OS X 10.4 (Tiger), the libtool needs to be specified the build environment. Enter:

% setenv MACOSX_DEPLOYMENT_TARGET 10.4

in tcsh, or:

$ export MACOSX_DEPLOYMENT_TARGET=10.4

in bash. Now configure with shared library support, then build and install:

% ./configure --enable-shared && make && sudo make install

configure will complain about ltconfig: cannot guess host type; you must specify one. An alternative to symlinking libtool is to copy its skeletal configuration defaults, as suggested by a correspondent (meaning, I haven't verified this):

cd ../jpeg-6b
cp /usr/share/libtool/config.sub .
cp /usr/share/libtool/config.guess .
./configure --enable-shared
make
sudo make install
sudo ranlib /usr/local/lib/libjpeg.a

8. Building freetype2

Enter freetype2's build directory:

% cd ../freetype-2.1.10

By default, freetype2's support for hinting TrueType fonts is disabled. US citizens using this library for commercial purposes might be liable for patent infringement by turning it back on; those of us to which US patents don't apply, or whomever may not care (I am not advocating infringement), edit the file include/freetype/config/ftoption.h and uncomment line 439 to read:

#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER

Proceed as before:

% ./configure && make && sudo make install

9. Building GD

First, if you have installed the X11 SDK, link fontconfig header files where GD can find them:

sudo ln -s /usr/X11R6/include/fontconfig /usr/local/include

(Beware of trailing slashes if using TAB autocompletion.)

A quick check might save you from much puzzlement later on: upon issuing a ls /usr/local/include/fontconfig/ (note the trailing slash), you should see:

fcfreetype.h fcprivate.h fontconfig.h

Now everything is in place. Go to GD's build directory, link in glibtool and configure:

% cd ../gd-2.0.33
% ./configure

Presently, configure should report that GD will support PNG, JPEG and FreeType:

** Configuration summary for gd 2.0.33:

Support for PNG library: yes
Support for JPEG library: yes
Support for Freetype 2.x library: yes
Support for Fontconfig library: yes
Support for Xpm library: yes
Support for pthreads: yes

If you don't see Freetype support, or if configure complained with a configure: WARNING: not found - disabling freetype support, you downloaded Freetype 2.2.1, which is not supported by GD. If you don't see Fontconfig support, you didn't linked correctly the fontconfig headers as indicated at the beginning of this section.

Finally, build and install:

% make && sudo make install

Nota bene: Apparently, configure insists on installing its own version of libtool, one that I suspect is not very au courant the Mac OS-on-Intel situation, and is possibly responsible for repeatedly-reported build failures on that platform. These are, as the alliteration might have alerted the astute reader, all speculations on my part; but I shan't blame you for trying. If you get an Undefined symbols error, make sure that the build process uses the version of glibtool supplied with Mac OS X: after configure does its magic, please delete libtool with rm ./libtool and then ln -s `which glibtool` ./libtool.
10. Testing GD

GD includes a battery of tests that can be run. A first, basic test, is:

% ./gdtest test/gdtest.png

(As noted in the test results, it is expected to fail on color images, and in particular, on the Windows Bitmap test.) Then, you will need a TrueType font that freetype2 can read: Windows or X-Windows .ttfs and Mac OS X .dfonts do nicely. If you don't find /Library/Fonts/Zapfino.dfont, get any one (I recommend Bitstream Vera) and copy it to your user's ~/Library/Fonts:

% ./gdtestft Zapfino.dfont

All files produced will reside in the test directory. You can view them with:

% open test/*.jpg

If fontconfig support is not available, with a little coercion GD can find fonts on its own. If in tcsh, type the following:

% setenv GDFONTPATH $HOME/Library/Fonts:/Library/Fonts:/System/Library/Fonts

In bash, type the following:

$ export GDFONTPATH=$HOME/Library/Fonts:/Library/Fonts:/System/Library/Fonts

(In any case, you might want to add the definition to your shell's init script.)
11. Cleaning up

Once you're satisfied with the results, you can proceed to clean up the build directories:

% cd ..
% rm -rf zlib-1.2.3/ libpng-1.2.12/ jpeg-6b/ freetype-2.1.10/ gd-2.0.33/

If you want to keep the .gz archives (I don't; the bandwidth incurred in downloading the archives is far less important to me than the disk space occupied), you may want to move them to your Public folder or wherever; otherwise, delete them:

% rm zlib-1.2.3.tar.gz libpng-1.2.12-config.tar.gz \
jpegsrc.v6b.tar.gz freetype-2.1.10.tar.gz \
gd-2.0.33.tar.gz

12. If anything fails…

As written, these instructions work in a clean installation of Mac OS X 10.4, updated to Mac OS X 10.4.7, with XCode 2.4. Many of the reported problems seem to be caused by GNU-Darwin, because of what it installs or the modifications it makes to the environment. If this HOWTO is your last resort after unfruitful attempts at installing GD for use with, for instance, PHP, your runtime environment is probably very polluted at this point.

I'd recommend ticking off the following checklist:

1. Review your environment variables

You can do it with setenv in tcsh, or export in bash. If you're having problems, the first thing to do is to set PATH to a sane value. I recommend having only:
* /usr/local/bin
* /usr/bin
* /bin
* /usr/local/sbin
* /usr/sbin
* /sbin

in the search path, at least until everything compiles fine. Remember to issue a rehash command whenever you modify the PATH variable in tcsh. Also, if DYLD_LIBRARY_PATH is set in Mac OS X 10.4, unset it and/or remove it from your startup scripts.
2. Review your startup scripts, and modify them accordingly, if need be (see §2).
3. Clean up /usr/local/{bin,lib,include} of any extraneous residues of previous essays. This will need care if you have compiled and installed any other programs that you might want to keep; if in doubt, abstain.

However, if you don't have already done that, or if you do not care, you needn't be subtle about this. Just:

% sudo rm -rf /usr/local/bin/* /usr/local/lib/* /usr/local/include/*

Of course, this be done at your own peril. I shan't be held liable.
4. Start anew compiling the failed module, by doing a make distclean (if that doesn't work, try make clean, or remove the source directory and unpack the archive again) and following the instructions for the module once more from the beginning.
5. Start afresh from §4, after cleaning up the build directories as per §11.

Good luck!

Author: Matías Giovannini
Last revision: 2006-09-25

Sunday, February 04, 2007

[转贴]Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X

Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X

Posted on February 02, 2007 by Dan Benjamin
Tagged as apple, code, development, mac, os x, ruby on rails, technology

This article is a major update to the older (but tried-and-true) post, Building Ruby, Rails, LightTPD, and MySQL on Tiger. Both Ruby, Rails, and their underlying infrastructure have come a long way in recent months, and this article will get you to a leaner, meaner Rails install in less time using fewer steps.

This article is updated on a regular basis as new versions of the software are released.

What follows are instructions for building and installing the following applications on Mac OS X 10.4 (Tiger) along with their supportive software. I’ve been told that these steps work just fine on Mac OS X 10.3 (Panther) as well, but I haven’t verified this myself, and your mileage may vary.

* Ruby 1.8.5
* Ruby on Rails 1.2
* Mongrel
* Subversion 1.3.2
* MySQL 5

Compiling and installing these tools this way is well worth the effort, as the end result delivers an easy-to-upgrade, system-independent, stand-alone development platform that is impervious to potential problems that can be caused by system updates, operating system upgrades, etc.

By rolling our own from source this way, we also have full control over our environment. We know what’s installed and where, what version we’ve used, where it came from, and there’s no dependence on an external ports system and the breakage or issues that come from relying on others to manage our software.

These issues and additional background information about why one might roll their own tools in this fashion are detailed in the article, Using /usr/local/, which could be considered a prerequisite for this task.
About (Not) Removing Old Versions

One of the great things about building these particular apps from source like this is that we don’t need to worry about removing older versions. When we build the new ones, they will replace the older versions as needed, and your system will be up to date with just the latest, greatest software.
The Concept

Basically, what we’re going to do here is download a bunch of open-source tools (some of which rely upon each other to work), configure them, compile them, and install them, one by one, until we have everything we need for a Mac OS X machine to run Ruby on Rails.
What’s Needed

A few things are needed to get this going:

1. Mac OS X 10.4 (and maybe 10.3)
2. Xcode 2.4 or newer (this compiles the apps for us)
3. Willingness to type commands into the Terminal application exactly as they appear here (cut-n-paste works too)
4. A tasty beverage to enjoy while things compile

Note: Xcode is not installed by default on new Macs, but can be found on the Mac OS X install DVD/CD, or downloaded from Apple’s Developer Connection free of charge.
A Quick Warning

While it’s unlikely anything we do here might do any kind of damage to the system, it’s good advice to have a current backup of everything, just in case. I don’t take any responsibility for anything that results from following these instructions (good or bad). You’re following these instructions at our own risk.
A Note about sudo

We’ll be using the command sudo quite a bit, and lots of people wonder what it does. Put simply, the sudo command allows a user (in this case, you) to execute a command as the superuser, allowing you to become the omnipotent master of your computer one command at a time.

With great power comes great responsibility, so Mac OS X may prompt you for your password prior to executing your command. It may do this only once, or several times throughout this process. Just re-enter your password as needed.
Setting Up

Open the Terminal application. It can be found in the /Applications/Utilities folder.

Each of the lines below appearing in monospaced type should be entered into Terminal, and be followed by the Return key. But everybody knew that already.

I like to create a folder to contain all of the downloaded files and their respective build folders. I tend to keep this folder around indefinitely. Source code doesn’t take up much space, and it’s useful to refer back to later to remind yourself of previous installation details or techniques, installed versions, for a fast install at a later time, or in case you want to uninstall something.

For these examples, we’ll create a folder called src in the /usr/local section of the filesystem, and change directories into that folder. It will be our workspace for everything we do here:

sudo mkdir -p /usr/local/src
sudo chgrp admin /usr/local/src
sudo chmod -R 775 /usr/local/src
cd /usr/local/src

You’ll download and compile everything in this new folder.
Paths

Do not skip this step! Most everything else will fail if you do.

Mac OS X, like other UNIX systems, uses something called a path to determine where it should look for applications on the command line (that is, when you’re using the Terminal app). The path is actually an environment variable, set by a special file that’s automatically executed when you open a new Terminal window.

We need to make sure that our path is set to look for files in /usr/local (the place where we’ll be installing the tools) before looking anywhere else. This is important.

To see if the path has been set properly, we can check the contents of the .bash_login file (the special file hidden in our home folder) for a PATH line using a text editor. TextMate, TextWrangler, BBEdit, and vi are all perfectly good options. To open the file with TextMate, for example, we can type:

mate ~/.bash_login

This will open the file if it already exists, or open a blank file if it doesn’t. Add the following line at the very end of the file:

export PATH="/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin:$PATH"

Now save and close the file.

It doesn’t matter how many other lines there are in the file, or what they say or do. Just make sure that this line comes last and you should be fine.

To make sure the changes are picked up correctly, we now need to execute the file with the following command:

. ~/.bash_login

It’s likely there will be no response from the shell here, just the prompt, but that’s OK, the changes have been picked up and we’re ready to move on.

You can also close your Terminal and open a new one instead if you’d like.

Geek Note: You may have noticed that I’ve added MySQL to the path in the line above. That’s because most users will be installing MySQL later in this tutorial. If you’re the type to want to use something like SQLite or PostGreSQL as your database instead of MySQL, you can feel free to omit the /usr/local/mysql/bin: bit from the line above, and replace it with the path to the database of your choice. If this note doesn’t make sense to you, even if you don’t plan to install MySQL later, just keep on going … the extra bit in the path statement won’t affect you at all.
Ruby

Now we’re ready to start the real work. Just type (or cut-n-paste) each one of the following lines into Terminal, one by one. When one line finishes (some will take a while and dump a lot of information to the screen), enter the next one.

As mentioned above, the first time you run the sudo command (and possible again later), you may be prompted for a password. Just enter your regular password here, and the process will continue.

We’ll start off with Ruby, but before we can compile Ruby itself, we’ll build a supportive application called readline. The commands below handle downloading, unzipping, configuring, compiling, and finally installing the code. This “pattern” will become more familiar as you move through the install step by step.

curl -O ftp://ftp.gnu.org/gnu/readline/readline-5.1.tar.gz
tar xzvf readline-5.1.tar.gz
cd readline-5.1
./configure --prefix=/usr/local
make
sudo make install
cd ..

If you get an error like the one below after typing the configure command:

checking whether make sets $(MAKE)... no
checking for gcc... no
checking for cc... no
checking for cc... no
checking for cl... no
configure: error: no acceptable C compiler found in $PATH

This means that you did not follow the instructions and don’t have Xcode installed.

If you saw lots of text fly by but didn’t get that error, it means that everything went well, and we can move on to building and installing Ruby itself.

curl -O ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.5-p12.tar.gz
tar xzvf ruby-1.8.5-p12.tar.gz
cd ruby-1.8.5-p12
./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local
make
sudo make install
sudo make install-doc
cd ..

If you saw lots of text fly by but didn’t get that error, it means that we should now have a brand new Ruby installed.

We can verify this (as well as a correct path setting) by typing the following command:

ruby -v

You should see something like this:

ruby 1.8.5 (2006-12-04 patchlevel 2) [blah]

Don’t worry about the text in the brackets, it provides details about your system architecture and isn’t important here. What is important is that you see ruby 1.8.5. This means you’ve got the new version of Ruby installed and in your path, and you’re good to go.

If you see something like this:

ruby 1.8.2 (2004-12-25)

Then either your install failed, or you didn’t correctly set your path in Terminal. Go back and check your work.
RubyGems

RubyGems is a handy command-line tool for managing the installation of Ruby packages, like Rails and Mongrel.

curl -O http://rubyforge.rubyuser.de/rubygems/rubygems-0.9.0.tgz
tar xzvf rubygems-0.9.0.tgz
cd rubygems-0.9.0
sudo /usr/local/bin/ruby setup.rb
cd ..

Ruby on Rails

With RubyGems installed, Rails is a simple, one-line install:

sudo gem install rails --include-dependencies

If you see an error message like this:

/usr/local/bin/gem:3:in `require': No such file to load -- rubygems (LoadError)
from /usr/local/bin/gem:3

It means you didn’t set your path as instructed in the very first step. Go back to the beginning and run that step again, then retry this step.
Mongrel

Mongrel is a fast, stand-alone HTTP library and server for Ruby. It allows you to run your Rails applications without having to compile or use other applications (like FastCGI, SCGI, LightTPD, or Apache).

Even better, Mongrel is also a gem. Type this command:

sudo gem install mongrel --include-dependencies

You’ll be prompted to select the appropriate gem for your platform, and you’ll be shown a list something like this one:

Select which gem to install for your platform
1. mongrel 1.0.1 (ruby)
2. mongrel 1.0.1 (mswin32)
3. mongrel 1.0 (mswin32)
4. mongrel 1.0 (ruby)
5. Skip this gem
6. Cancel installation

Although version numbers may be different, you should always select the one closest to the top of the list that ends with “(ruby)” ... this is usually the first option. Just type the number and press enter.
Subversion (Optional)

Subversion is an open-source version control system. It remembers every change ever made to the files and directories in your projects. This allows you to recover older versions of your data, or examine the history of how your data changed. You can read more about Subversion (svn) in the online Subversion book.

While it’s not mandatory to have svn running in order to use Rails, it’s highly recommended. It’s used by the Rails team for distribution management, by most web hosts for deployment (via Capistrano), and by most Rails developers to manage their code. The install process is pretty typical:

curl -O http://subversion.tigris.org/downloads/subversion-1.3.2.tar.gz
tar xzvf subversion-1.3.2.tar.gz
cd subversion-1.3.2
./configure --prefix=/usr/local --with-openssl --with-ssl --with-zlib
make
sudo make install
cd ..

Geek Note: Some people have asked why I’m still using version 1.3.2 instead of the newer 1.4.x branch. Although 1.4 introduces a number of great features, there are some issues when using the newer client with an older (1.3.x) repository. If all of your repositories have moved to 1.4, feel free to download the latest version of 1.4.x and build it using the configure line above.
Capistrano

Capistrano is a utility which may be used to automate the deployment of your Rails applications. Many Rails applications and webhosts require it, and while this is technically an optional step, it’s simple, fast, and highly recommended.

sudo gem install capistrano --include-dependencies

I also recommend installing termios, a gem that’s a wrapper for the UNIX termios command, which will prevent passwords you enter in Capistrano from being displayed in your Terminal for all to see.

sudo gem install termios --include-dependencies

Technically, you could stop right here. But most Rails applications need a database ...
MySQL

While it’s possible to compile and install MySQL ourselves, using the Mac OS X MySQL package is actually advantageous. Not only is the package-installer much faster and easier, but it includes a handy startup item and a preference panel, and the binary is tuned by the MySQL team for Mac OS X.

Even better, the package installs MySQL right into the /usr/local/ folder, just like it should!

The install still requires a few steps:

1. Download the MySQL 5.0 package for OS X PPC or the MySQL 5.0 package for OS X Intel
2. Double-click the drive image to mount it
3. Locate the MySQL installer (a file named something like mysql-standard-5.0.27-osx10.4-i686.pkg) and run it, authenticating as needed
4. Double-click MySQLStartupItem.pkg, authenticate, and let it install
5. Double-click MySQL.prefPane and install it, deciding whether to make it available to just the current user, or for all system users

Once the install is complete, start the MySQL server using the newly-installed control panel.

Note: MySQL installs with a default user of root using no password. If you care about the privacy of your data or computer, please read this page about MySQL usernames and passwords and set a good one.
MySQL Native Bindings Gem (Optional)

This step is an optional one, but the performance gains seem to make it worth the extra step.

At the present time, there’s a problem getting this gem to compile with MySQL 5.x. Fortunately, there’s a way to fix fix it ourselves, using a patch file (originally created by juretta.com and reproduced here). Hopefully this issue will be fixed soon, but until then, we’ve got a workaround.

The command below will fail. This is OK, and you still need to execute it. Just follow along for now.

sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql

Just like the Mongrel install, you might see a prompt asking you which gem to install:

Select which gem to install for your platform
1. mysql 2.7.3 (mswin32)
2. mysql 2.7.1 (mswin32)
3. mysql 2.7 (ruby)
4. mysql 2.6 (ruby)
5. Skip this gem
6. Cancel installation

Again, just like the Mongrel install, we’ll want to pick the option closest to the top that ends in “(ruby)”. In the example above, we’d want to select option 3.

You should then see an error like this one:

mysql.c: In function 'Init_mysql':
mysql.c:2015: error: 'ulong' undeclared (first use in this function)
mysql.c:2015: error: (Each undeclared identifier is reported only once
mysql.c:2015: error: for each function it appears in.)
mysql.c:2015: error: parse error before numeric constant
mysql.c:2018: error: parse error before numeric constant
make: *** [mysql.o] Error 1

Although the build didn’t finish, RubyGems did download the source code, depositing it deep within the bowels of our filesystem … and now we can apply the patch:

mkdir -p /usr/local/src/intel-mac-mysql-gem
cd /usr/local/src/intel-mac-mysql-gem
curl -O http://hivelogic.com/downloads/intel-mac-mysql-gem.patch
cd /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7
sudo ruby extconf.rb install mysql -- --with-mysql-dir=/usr/local/mysql
sudo cp mysql.c mysql.c.dist
sudo patch mysql.c /usr/local/src/intel-mac-mysql-gem/intel-mac-mysql-gem.patch
sudo make
sudo make install
cd /usr/local/src

We’re Done

Congratulations, you now have a custom-built, properly located installation of Ruby, Ruby on Rails, MySQL, Mongrel, and Capistrano!

If you’re new to Rails and just want to create a sample app to see this all working, try this:

rails testapp
cd testapp
script/server

This will create a basic Rails app in a folder called testapp in your current folder (probably /usr/local/src if you’re doing this where the last step left off).

If all goes well, you’ll get some output that looks like this:

=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart).
** Rails signals registered. HUP => reload (without restart). It might not work well.
** Mongrel available at 0.0.0.0:3000
** Use CTRL-C to stop.

You can now check out your new app by clicking or pasting this link in your browser of choice: http://localhost:3000
What Else?

To do any real work with your new app, you’ll want to create a database for it. The Rails convention is that the database will take the same name as the name you specified when the app was created (in this case, “testapp”).

You’ll need to first start up MySQL, and then create a database. While you can start MySQL using the control panel you installed earlier, it can also be started using the command line:

sudo /Library/StartupItems/MySQLCOM/MySQLCOM start

You won’t have to run this command again, because the startup item you installed for MySQL will make sure it’s running the next time you boot your Mac. With MySQL running, you can create a new database for the test application:

mysqladmin -uroot create testapp_development

If you created a password for MySQL, you’ll need to add the -p option to the command above and you’ll be prompted for your password.

The rest is up to you. Good luck, and have fun with Rails!

http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx