<?xml version="1.0" encoding="utf-8" ?>
<!-- generator="FEEDCREATOR_VERSION" -->
<rss version="2.0" xmlns:sns="http://blog.sina.com.cn/sns">
    <channel>
        <title>Flash AS 基理殿堂</title>
        <description></description>
        <link>http://blog.sina.com.cn/yyy98</link>
        <lastBuildDate>Mon, 23 Nov 2009 20:16:14 GMT+8</lastBuildDate>
        <generator>FEEDCREATOR_VERSION</generator>
        <language>zh-cn</language>
        <copyright>Copyright 1996 - 2009 SINA Inc. All Rights Reserved.</copyright>
        <pubDate>Mon, 23 Nov 2009 12:16:14 GMT+8</pubDate>
        <item>
            <title>[AS3 狂想曲] SWF 间双向通信 [FL 车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100fx4d.html</link>
            <description><![CDATA[<span STYLE="font-weight: bold; color: rgb(0, 0, 255);">演示文件源码下载</SPAN>：<a HREF="http://kerryas.googlecode.com/files/swfs_communication.rar" TARGET="_blank">http://kerryas.googlecode.com/files/swfs_communication.rar</A><br />

<br />
假设有一个主 SWf 名为 main.swf 加载一个名为 game.swf 的游戏模块：<br />
1. main 里面使用 Loader 将 game.swf 加载进来；<br />
2. 在 game 中定义 public function moveBall(speed:Number)
方法，用于开始游戏;<br />
3. 在 main 里面使用类似 loader["content"].moveBall(speed) 的语句调用 game.swf
里面的方法；<br />
4. game.swf 与 main.swf 通信的方法，可以使用 dispatchEvent 方法与 main.swf
通信，也可以继续使用上述方法。<br />
<br />
下面请看示例：<br />
1. 首先创建被调用的 game.swf：<br />
package {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Sprite;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.Event;<br />
&nbsp;&nbsp;&nbsp; import
flash.system.Security;<br />
<br />
&nbsp;&nbsp;&nbsp; public class
Game extends Sprite {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
ball:Sprite;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
speed:Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function Game() {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 在 Flash
IDE 中执行 Debug<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
Security.allowInsecureDomain("*");<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if (stage)
init();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; else
addEventListener(Event.ADDED_TO_STAGE, init);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function init(e:Event = null):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
removeEventListener(Event.ADDED_TO_STAGE, init);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ball = new
Sprite();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
ball.graphics.beginFill(0xFF0000);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
ball.graphics.drawCircle(0, 0, 50);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
ball.graphics.endFill();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
addChild(ball);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ball.x =
50;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ball.y =
stage.stageHeight / 2;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function moveBall(speed:Number):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.speed =
speed;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
addEventListener(Event.ENTER_FRAME, onGameLoop);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function onGameLoop(e:Event):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; ball.x +=
speed;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function stopMove():void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
removeEventListener(Event.ENTER_FRAME, onGameLoop);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
在这个类里创建了一个小球实例 ball，还提供了两个公开的方法 moveBall(speed) 和
stopMove()，用于控制小球的运动与停止。最后，编译该文件将生成好的 game.swf
放到应用服务器的根目录上（http://localhost/game.swf）。<br />
<br />
2. 下面创建主程序，调用 game.swf 并与其通信<br />
package {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Loader;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Sprite;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.Event;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.MouseEvent;<br />
&nbsp;&nbsp;&nbsp; import
flash.net.URLRequest;<br />
&nbsp;&nbsp;&nbsp; import
flash.system.Security;<br />
<br />
&nbsp;&nbsp;&nbsp; public class
Main extends Sprite {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
loader:Loader;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function Main() {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if (stage)
init();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; else
addEventListener(Event.ADDED_TO_STAGE, init);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function init(e:Event = null):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
removeEventListener(Event.ADDED_TO_STAGE, init);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; //
允许访问变量、对象、属性、方法等<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
Security.allowDomain("*");<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; loader = new
Loader();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
addChild(loader);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 加载
http://localhost/game.swf 后面的参数用于防止缓存<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
loader.load(new URLRequest("http://localhost/game.swf?" + new
Date().time));<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
loader.contentLoaderInfo.addEventListener(Event.INIT,
onLoadComplete);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function onLoadComplete(e:Event):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 调用
game.swf 中的 moveBall(speed) 方法<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
loader["content"].moveBall(5);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 点击舞台后调用
game.swf 中的 stopMove() 方法<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
stage.addEventListener(MouseEvent.CLICK,
onClickStageHandler);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function onClickStageHandler(e:MouseEvent):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
loader["content"].stopMove();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
主程序中先将 game.swf 加载进来，然后调用 game.swf 中的 moveBall(speed)
方法，并侦听在舞台发生点击事件后调用 game.swf 中的 stopMove() 方法。<br />
<br />
3. game.swf 与 main.swf 通信方法：<br />
调用的方法可以和 main.swf 调用 game.swf 一样，也可以使用事件调度，下面是事件驱动方法：<br />
（1）定义 GameEvent.as 事件<br />
package {<br />
&nbsp;&nbsp;&nbsp; import
flash.events.Event;<br />
<br />
&nbsp;&nbsp;&nbsp; public class
GameEvent extends Event {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static const GAME_START:String = "game_start";<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static const GAME_OVER:String = "game_over"<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public var
score:uint;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function GameEvent(type:String, score:uint = 0) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.score =
score;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
super(type);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
（2）在 Game 中当调用 moveBall(speed) 方法时分发 GameEvent.GAME_START 事件：<br />
dispatchEvent(new GameEvent(GameEvent.GAME_START));<br />
在 Game 中当调用 stopMove() 方法时分发 GameEvent.GAME_OVER 事件：<br />
dispatchEvent(new GameEvent(GameEvent.GAME_OVER, ball.x)); // 将小球的
x 坐标作为 GameEvent 的参数发出<br />
<br />
（3）在 Main 中侦听这两个事件（当 game.swf 被加载进来后）：<br />
loader["content"].addEventListener(GameEvent.GAME_START,
onGameStartHandler);<br />
loader["content"].addEventListener(GameEvent.GAME_OVER,
onGameOverHandler);<br />
<br />
private function onClickStageHandler(e:MouseEvent):void {<br />
&nbsp;&nbsp;&nbsp;
loader["content"].stopMove();<br />
}<br />
<br />
private function onGameOverHandler(e:Object):void {<br />
&nbsp;&nbsp;&nbsp;
trace(e.score);<br />
}<br />
<br />
private function onGameStartHandler(e:Object):void {<br />
&nbsp;&nbsp;&nbsp;
trace(e.score);<br />
}<br />
<br />
请注意处理事件的类型不是 GameEvent 而是 Object，理论上应该是 GameEvent
，但是如果这样声明的话会出现“强制转换类型失败”，因此只能用 Object 来替代。<br />]]></description>
            <author>FL车在臣</author>
            <category>AS3 狂想曲</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100fx4d.html#comment</comments>
            <pubDate>Fri, 13 Nov 2009 09:07:59 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100fx4d.html</guid>
        </item>
        <item>
            <title>[KerryLib] KerryLib v0.2 更新内容 [FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100f116.html</link>
            <description><![CDATA[<span STYLE="font-weight: bold;">SVN Checkout or
Update：</SPAN>http://kerryas.googlecode.com/svn/trunk/KerryLib<br />

<br />
版本 0.2 更新内容<br />
com.kerry.effect<br />
&nbsp;&nbsp;&nbsp; --
Earthquake<br />
&nbsp;&nbsp;&nbsp; --
PerlinDistort<br />
&nbsp;&nbsp;&nbsp; --
Rippler<br />
&nbsp;&nbsp;&nbsp; --
StaticReflection<br />
com.kerry.util<br />
&nbsp;&nbsp;&nbsp; --
ArrayUtil<br />
&nbsp;&nbsp;&nbsp; --
ClassUtil<br />
&nbsp;&nbsp;&nbsp; --
MathUtil<br />
&nbsp;&nbsp;&nbsp; --
ObjectUtil<br />
&nbsp;&nbsp;&nbsp; --
StringUtil<br />
<br STYLE="font-weight: bold;" />
<br STYLE="font-weight: bold;" />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.effect#Earthquake.as</FONT><br />
package com.kerry.effect {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.DisplayObject;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.TimerEvent;<br />
&nbsp;&nbsp;&nbsp; import
flash.utils.Timer;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
Earthquake {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
source:DisplayObject;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
originalX:Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
originalY:Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
timer:Timer;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
intensity:Number<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function Earthquake(source:DisplayObject) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.source
= source;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function quake(intensity:Number = 10, times:uint = 5,
intervalSeconds:Number = 0.05):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
this.intensity = intensity;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; originalX =
source.x;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; originalY =
source.y;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; timer = new
Timer(intervalSeconds * 1000, times);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
timer.addEventListener(TimerEvent.TIMER, onQuake);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
timer.addEventListener(TimerEvent.TIMER_COMPLETE, rest);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
timer.start();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function onQuake( event:TimerEvent ): void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; source.x =
originalX + Math.random() * intensity;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; source.y =
originalY + Math.random() * intensity;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function rest(e:TimerEvent): void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; source.x =
originalX;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; source.y =
originalY;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.effect#PerlinDistort.as</FONT><br />
package com.kerry.effect {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.BitmapData;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.Point;<br />
&nbsp;&nbsp;&nbsp; import
flash.filters.DisplacementMapFilter;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Sprite;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.DisplayObject;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Bitmap;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.Event;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
PerlinDistort {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
perlinOffset:Array;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
randCount:Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
source:DisplayObject;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
bmp:BitmapData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
dmf:DisplacementMapFilter;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function PerlinDistort(source:DisplayObject, scaleX:Number,
scaleY:Number) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.source
= source;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; randCount =
Math.random() * 25;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; perlinOffset
= new Array(new Point(55, 34), new Point(20, 33));<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; bmp = new
BitmapData(source.width + 100, source.height + 100, false);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
bmp.draw(source);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; dmf = new
DisplacementMapFilter(bmp, new Point(0, 0), 1, 1, scaleX, scaleY,
"color", 0xFFFFFF, 0);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.addEventListener(Event.ENTER_FRAME, noiseOn);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function noiseOn(e:Event):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
perlinOffset[0].y -= 8;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
perlinOffset[0].x -= 5;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
perlinOffset[1].x += 8;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
perlinOffset[1].y += 5;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
bmp.perlinNoise(100, 100, 3, randCount, false, true, 1, true,
perlinOffset);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.filters = [dmf];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function removeNoise():void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.removeEventListener(Event.ENTER_FRAME, noiseOn);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.filters = [];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.effect#Rippler.as</FONT><br />
package com.kerry.effect {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.BitmapData;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.BitmapDataChannel;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.BlendMode;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.DisplayObject;<br />
&nbsp;&nbsp;&nbsp; import
flash.events.Event;<br />
&nbsp;&nbsp;&nbsp; import
flash.filters.ConvolutionFilter;<br />
&nbsp;&nbsp;&nbsp; import
flash.filters.DisplacementMapFilter;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.ColorTransform;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.Matrix;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.Point;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.Rectangle;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
Rippler {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
source:DisplayObject;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
buffer1:BitmapData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
buffer2:BitmapData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
defData:BitmapData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
fullRect:Rectangle;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
drawRect:Rectangle;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
origin:Point = new Point();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
filter:DisplacementMapFilter;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
expandFilter:ConvolutionFilter;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
colourTransform:ColorTransform;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
matrix:Matrix;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
scaleInv:Number;<br />
<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function Rippler(source:DisplayObject, strength:Number,
scale:Number = 2) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
correctedScaleX : Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
correctedScaleY : Number;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.source
= source;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; scaleInv = 1
/ scale;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; buffer1 =
new BitmapData(source.width * scaleInv, source.height * scaleInv,
false, 0x000000);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; buffer2 =
new BitmapData(buffer1.width, buffer1.height, false,
0x000000);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; defData =
new BitmapData(source.width, source.height);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
correctedScaleX = defData.width / buffer1.width;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
correctedScaleY = defData.height / buffer1.height;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; fullRect =
new Rectangle(0, 0, buffer1.width, buffer1.height);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; drawRect =
new Rectangle();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; filter = new
DisplacementMapFilter(buffer1, origin, BitmapDataChannel.BLUE,
BitmapDataChannel.BLUE, strength, strength, "wrap");<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.filters = [filter];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.addEventListener(Event.ENTER_FRAME, handleEnterFrame);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; expandFilter
= new ConvolutionFilter(3, 3, [0.5, 1, 0.5, 1, 0, 1, 0.5, 1, 0.5],
3);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
colourTransform = new ColorTransform(1, 1, 1, 1, 127, 127,
127);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; matrix = new
Matrix(correctedScaleX, 0, 0, correctedScaleY);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function drawRipple(x:int, y:int, size:int, alpha:Number):void
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var half :
int = size &gt;&gt; 1;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
intensity : int = (alpha * 0xff &amp; 0xff) *
alpha;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; drawRect.x =
( -half + x) * scaleInv;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; drawRect.y =
( -half + y) * scaleInv;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
drawRect.width = drawRect.height = size * scaleInv;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer1.fillRect(drawRect, intensity);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function getRippleImage():BitmapData {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
defData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function destroy():void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer1.dispose();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer2.dispose();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
defData.dispose();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.removeEventListener(Event.ENTER_FRAME,
handleEnterFrame);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function handleEnterFrame(e:Event):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
temp:BitmapData = buffer2.clone();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer2.applyFilter(buffer1, fullRect, origin, expandFilter);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer2.draw(temp, null, null, BlendMode.SUBTRACT, null,
false);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
defData.draw(buffer2, matrix, colourTransform, null, null,
true);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
filter.mapBitmap = defData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
source.filters = [filter];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
temp.dispose();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
switchBuffers();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private
function switchBuffers():void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
temp:BitmapData;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; temp =
buffer1;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; buffer1 =
buffer2;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; buffer2 =
temp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.effect#StaticReflection.as</FONT><br />
package com.kerry.effect {<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Bitmap;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.BitmapData;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.DisplayObject;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.GradientType;<br />
&nbsp;&nbsp;&nbsp; import
flash.display.Sprite;<br />
&nbsp;&nbsp;&nbsp; import
flash.geom.Matrix;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
StaticReflection extends Sprite {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
source:DisplayObject;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; private var
bitmap:Bitmap;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
function StaticReflection(source:DisplayObject) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; this.source
= source;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var w:Number
= source.width;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var h:Number
= source.height;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
colors:Array = [0xFF0000, 0x0000FF];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
alphas:Array = [0.4, 0];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
ratios:Array = [0, 0xFF];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
matrix:Matrix = new Matrix();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
matrix.createGradientBox(w, h, Math.PI / 2, 0, 0);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
bmd:BitmapData = new BitmapData(w, h, true, 0x00000000);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; bitmap = new
Bitmap(bmd);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
bmd.draw(source);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
addChild(bitmap);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
bitmap.scaleY = -1;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; bitmap.y =
bitmap.height;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
bitmap.cacheAsBitmap = true;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
mark:Sprite = new Sprite();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
mark.graphics.beginGradientFill(GradientType.LINEAR, colors,
alphas, ratios, matrix);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
mark.graphics.drawRect(0, 0, w, h);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
addChild(mark);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
mark.cacheAsBitmap = true;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; bitmap.mask
= mark;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.util#ArrayUtil.as</FONT><br />
package com.kerry.util {<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
ArrayUtil {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function arrayContainsValue(arr:Array, value:Object):Boolean
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
(arr.indexOf(value) != -1);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function remov_rueFromArray(arr:Array, value:Object):void
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var len:uint
= arr.length;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; for (var
i:Number = len; i &gt; -1; i--) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if (arr[i]
=== value) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
arr.splice(i, 1);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function copyArray(arr:Array):Array
{&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
arr.slice();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function arraysAreEqual(arr1:Array, arr2:Array):Boolean
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if
(arr1.length != arr2.length) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
false;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
len:Number = arr1.length;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; for (var
i:Number = 0; i &lt; len; i++) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if (arr1[i]
!== arr2[i]) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
false;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
true;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function shuffle(source:Array):Array {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if( source
== null ) return null;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
source.sort( function( ...arguments : Array ) : int { return
Math.round( Math.random() * 2 ) - 1; } );<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.util#ClassUtil.as</FONT><br />
package com.kerry.util {<br />
&nbsp;&nbsp;&nbsp; import
flash.utils.describeType;<br />
&nbsp;&nbsp;&nbsp; import
flash.utils.getDefinitionByName;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
ClassUtil {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function getInstance(Clazz:Class, ...arguments:Array):Object
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var xml:XML
= describeType(Clazz);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
if(xml.hasOwnProperty("factory")) xml = new XML( xml.child(
"factory" ));<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
constructorArgumentsLength:uint = xml.child( "constructor" ).child(
"parameter" ).length();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
switch(constructorArgumentsLength) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case 0:
return new Clazz();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case 1:
return new Clazz(arguments[0]);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case 2:
return new Clazz(arguments[0], arguments[1]);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case 3:
return new Clazz(arguments[0], arguments[1], arguments[2]);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // ... case
21<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
null;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.util#MathUtil.as</FONT><br />
package com.kerry.util {<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
MathUtil&nbsp;&nbsp;&nbsp;
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function radianToDegree (radian:Number):Number {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
radian * 180 / Math.PI;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function degreeToRadian(degree:Number):Number {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
degree / 180 * Math.PI;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function pythagoras(s1:Number , s2:Number,
searchHypotenuse:Boolean = false):Number {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if
(searchHypotenuse) return Math.sqrt( s1 * s1 + s2 * s2 );<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
hypo:Number = Math.max( s1 , s2 );<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
side:Number = Math.min( s1 , s2 );<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
Math.sqrt(hypo * hypo - side * side);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function distance(p1X:Number, p1Y:Number, p2X:Number,
p2Y:Number):Number {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
dx:Number = p1X - p2X;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
dy:Number = p1Y - p2Y;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
Math.sqrt(dx * dx + dy * dy);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.util#ObjectUtil.as</FONT><br />
package com.kerry.util {<br />
&nbsp;&nbsp;&nbsp; import
flash.utils.ByteArray;<br />
&nbsp;&nbsp;&nbsp; import
flash.utils.describeType;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
ObjectUtil&nbsp;&nbsp;&nbsp;
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function copyProperties(fromObject:Object,
toObject:Object):void {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
isDynamicObject:Boolean = isDynamic(toObject);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;for (var prop:String in fromObject) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;if (isDynamicObject ||
toObject.hasOwnProperty(prop)) toObject[prop] =
fromObject[prop];<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function copy (obj:Object):Object {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
buffer:ByteArray = new ByteArray();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer.writeObject(obj);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
buffer.position = 0;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
buffer.readObject();<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function isDynamic(obj:Object):Boolean {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var xml:XML
= describeType(obj);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
xml.@isDynamic == "true";<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">&#9632;
com.kerry.util#StringUtil.as</FONT><br />
package com.kerry.util {<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public class
StringUtil {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function trim(input:String):String {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
StringUtil.ltrim(StringUtil.rtrim(input));<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function ltrim(input:String):String {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
size:Number = input.length;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; for (var
i:Number = 0; i &lt; size; i++) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if
(input.charCodeAt(i) &gt; 32) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
input.substring(i);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
"";<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function rtrim(input:String):String {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; var
size:Number = input.length;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; for (var
i:Number = size; i &gt; 0; i--) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; if
(input.charCodeAt(i - 1) &gt; 32) {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
input.substring(0, i);<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
"";<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function stringHasValue(s:String):Boolean {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return (s !=
null &amp;&amp; s.length &gt;
0);&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function isEmail(s:String):Boolean {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i.test( s );<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; public
static function isWhitespace(s:String):Boolean {<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; switch(s)
{<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case "
":<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case
"\t":<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; case "\r"
:<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case "\n" :<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case "\f" :<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
true;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; return
false;<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
<font STYLE="font-size: 20px; font-weight: bold;">KerryLib v0.2 部分
demo 程序效果：</FONT><br />
com.kerry.effect.Rippler 及 com.kerry.effect.StaticReflection
结合<br />
=&gt; StaticReflectionWithRipplerDemo<br />
<a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static5.photo.sina.com.cn/orignal/3ecb9b11t7375b71e7144&amp;690" TARGET="_blank"><img SRC="http://static5.photo.sina.com.cn/bmiddle/3ecb9b11t7375b71e7144&amp;690" STYLE="" /></A><br />]]></description>
            <author>FL车在臣</author>
            <category>KerryLib</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100f116.html#comment</comments>
            <pubDate>Sun, 13 Sep 2009 13:32:15 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100f116.html</guid>
        </item>
        <item>
            <title>[视频教程] Flash AS 3.0 项目开发实践 [FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eysl.html</link>
            <description><![CDATA[1. 内容介绍及 FlashDevelop 安装使用<br />
<div><embed NAME="articlevblog" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer" SRC="http://vhead.blog.sina.com.cn/player/outer_player.swf?auto=0&amp;vid=24480545&amp;uid=1053530897&amp;pid=346&amp;tid=1" WIDTH="480" HEIGHT="370" TYPE="application/x-shockwave-flash" AllowScriptAccess="samedomain" ALLOWFULLSCREEN="true"></EMBED></DIV>
<br />
2. Flash 与后台（Java, PHP, Rails）通信及 HttpWatch 使用<br />
<div><embed NAME="articlevblog" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer" SRC="http://vhead.blog.sina.com.cn/player/outer_player.swf?auto=0&amp;vid=24483773&amp;uid=1053530897&amp;pid=346&amp;tid=1" WIDTH="480" HEIGHT="370" TYPE="application/x-shockwave-flash" AllowScriptAccess="samedomain" ALLOWFULLSCREEN="true"></EMBED></DIV>
<br />
3. Json 数据交换、AS3corelib 以及 Alcon 调试工具<br />
<div><embed NAME="articlevblog" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer" SRC="http://vhead.blog.sina.com.cn/player/outer_player.swf?auto=0&amp;vid=24514213&amp;uid=1053530897&amp;pid=346&amp;tid=1" WIDTH="480" HEIGHT="370" TYPE="application/x-shockwave-flash" AllowScriptAccess="samedomain" ALLOWFULLSCREEN="true"></EMBED></DIV>
<p><br />
4. AMFPHP、KerryLib 及 swfobject.js</P>
<p><div><object id="articlevblog" width="480" height="370" > <param name="allowScriptAccess" value="always" /> <embed pluginspage="http://www.macromedia.com/go/getflashplayer" src="http://vhead.blog.sina.com.cn/player/outer_player.swf?auto=0</embed></object></div></P>
<p>&nbsp;</P>
<p><span STYLE="FonT-WeiGHT: bold; CoLor: rgb(0,0,255)">演示文件源码下载</SPAN>：<a HREF="http://kerryas.googlecode.com/files/flashas3_develop.rar" TARGET="_blank">http://kerryas.googlecode.com/files/flashas3_develop.rar</A></P>
<p><font STYLE="FonT-siZe: 20px"><strong>内容介绍</STRONG></FONT></P>
<p>1. <strong>FlashDevelop：</STRONG>Flash 项目开发必备环境</P>
<p>2. <strong>Flash 与后台：</STRONG>Java, PHP, Rails 通信技术</P>
<p>3. <strong>HttpWatch：</STRONG>网页数据分析工具</P>
<p>4. <strong>JSON：</STRONG>轻量级的数据交换格式</P>
<p>5. <strong>As3corelib：</STRONG>Adobe 官方出品的 AS3 函数库</P>
<p>6. <strong>Alcon：</STRONG>调试工具</P>
<p>7. <strong>AMFPHP：</STRONG>让 Flash 与 PHP 无缝通信</P>
<p>8. <strong>KerryLib：</STRONG>FL车在臣 AS3 开源项目</P>
<p>9. <strong>SWFObject：</STRONG>基于 Javascript 的 Flash
媒体版本检测与嵌入模块</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>1.1 FlashDevelop
安装</STRONG></FONT><br />
安装准备：<br />
Microsoft .Net Framework2（运行环境）<br />
JRE 1.6+ （ Flex SDK 必须的必备条件）<br />
FlexSDK（FD 进行调试编译的基础）</P>
<p>下载安装 FD：<a HREF="http://www.flashdevelop.org/">www.flashdevelop.org</A></P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>1.2 FlashDevelop
开发环境配置</STRONG></FONT><br />
<strong>&#9679;</STRONG>设置 Flex SDK Location 到 Flex SDK
的根目录（Tools-&gt;Program Settings-&gt;
AS3Context）</P>
<p>&#9679;设置 Path To Flash IDE 到 Flash 安装根目录（
Tools-&gt;Program Settings-&gt;
ASCompletion ）</P>
<p>&#9679;设置 Flash View 到 [Flex SDK]/
runtimes\player\10\win\FlashPlayer.exe</P>
<p>&#9679;设置 Contextual Generator 快捷键 Ctrl + 1</P>
<p>&#9679;插件的安装（放置在 [FlashDevelop]/Plugins 目录）例如： fdbplugin 一款 FD 的 Debug
插件</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>1.3 FlashDevelop
工程创建及设置</STRONG></FONT></P>
<p>&#9679;Flash IDE 工程与 AS3 工程<br />
&#9679;Project Classpaths 与 Global Classpaths<br />
&#9679;运行平台（flash player 9/10）Output-&gt; Plantform</P>
<p><br /></P>
<p><font STYLE="FonT-siZe: 20px"><strong>1.4 FlashDevelop 创建 asDoc
文档<br /></STRONG></FONT></P>
<p>&#9679;Flash Tools -&gt; Documentation Generator<br />
Page Title：设置页面标题<br />
Output directory：设置文档输出的路径<br />
Classpaths：设置生成文档的源文件路径<br />
Excude classes：设置要排除在外的类<br />
Settings -&gt; ASDoc location：设置为 [Flex SDK]/bin</P>
<p><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static7.photo.sina.com.cn/orignal/3ecb9b11t738b9f137176&amp;690" TARGET="_blank"><img SRC="http://static7.photo.sina.com.cn/bmiddle/3ecb9b11t738b9f137176&amp;690" /></A></P>
<p><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static7.photo.sina.com.cn/orignal/3ecb9b11t738ba0386756&amp;690" TARGET="_blank"><img SRC="http://static7.photo.sina.com.cn/bmiddle/3ecb9b11t738ba0386756&amp;690" /></A></P>
<p><br /></P>
<p><font STYLE="FonT-siZe: 20px"><strong>2.1 Flash
与后台通信</STRONG></FONT></P>
<p>var request:URLRequest = new URLRequest("<a HREF="http://localhost:8080/hello_flash/servlet/hello">http://localhost:8080/hello_flash/servlet/hello</A>");<br />

request.method = "post";</P>
<p>var vars:URLVariables = new URLVariables();<br />
vars.name = "kerry";<br />
vars.pass = "123456";<br />
request.data = vars;</P>
<p>&nbsp;</P>
<p>var loader:URLLoader = new URLLoader();<br />
loader.load(request);<br />
loader.addEventListener(Event.COMPLETE, onLoadComplete);</P>
<p>&nbsp;</P>
<p>private function onLoadComplete(e:Event):void {<br />
&nbsp;trace(e.target.data);<br />
}</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>2.2 Flash 与
Java</STRONG></FONT><br />
public void doPost(HttpServletRequest request, HttpServletResponse
response)<br />
throws ServletException, IOException {<br />
&nbsp;response.setContentType("text/html");<br />
&nbsp;PrintWriter out = response.getWriter();<br />
&nbsp;<br />
&nbsp;String username =
request.getParameter("name");<br />
&nbsp;String password =
request.getParameter("pass");<br />
&nbsp;<br />
&nbsp;out.println("hello from java: " + username +" "+
password);<br />
&nbsp;out.flush();<br />
&nbsp;out.close();<br />
}</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>2.3 Flash 与
PHP</STRONG></FONT><br />
&lt;?php<br />
&nbsp;$username = $_POST['name'];<br />
&nbsp;$password = $_POST['pass'];<br />
&nbsp;echo "hello from php : ".$username."
".$password;<br />
?&gt;</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>2.4 Flash 与
Rails</STRONG></FONT><br />
&#9679;F:\rails_project&gt;rails -d mysql hello_flash</P>
<p>&#9679;修改 database.yml 并创建 hello_flash 数据库</P>
<p>&#9679;ruby script/generate controller hello sayHello</P>
<p>&#9679;启动 WEBrick 服务器：ruby script/server</P>
<p>修改 app/controllers/hello_controller.rb<br />
class HelloController &lt; ApplicationController<br />
&nbsp; def sayHello<br />
&nbsp; &nbsp;username =
params['name'];<br />
&nbsp; &nbsp;password =
params['pass'];<br />
&nbsp; &nbsp;render :text =&gt;
"hello from rails:#{username} #{password}"<br />
&nbsp; end<br />
end</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>3. HttpWatch
观察请求与响应</STRONG></FONT></P>
<p>&#9679;HttpWatch最主要的功能就是对通过浏览器发送的http 请求进行监控和分析，当你在浏览器的地址栏上请求一个 URL
或者提交一份表单时，HttpWatch帮你分析 http 请求的 head 信息，访问页面的 cookie 信息，Get 和 Post
的详细数据包分析。<br />
&#9679;在 IE 下使用 Shift + F2 调出 HttpWatch 工具栏<br />
&#9679;使用 Record 记录请求与响应数据</P>
<p><br />
&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>4. JSON —
轻量级数据交换格式</STRONG></FONT><br />
XML 与 JSON 实例比较：假设有一个用户数据包括：用户名，年龄，email 地址（工作和家庭）。<br />
用 XML 表示如下：<br />
&lt;?xml version="1.0"
encoding="utf-8"?&gt;<br />
&lt;user&gt;<br />
&nbsp;&lt;name&gt;张三
&lt;/name&gt;<br />
&nbsp;&lt;age&gt;30&lt;/age&gt;<br />

&nbsp;&lt;emailaddrs&gt;&nbsp;<br />

&nbsp;&nbsp;&lt;address
type='work'&gt;kelly@seankelly.biz&lt;/address&gt;&nbsp;<br />

&nbsp;&nbsp;&lt;address
type='home'&gt;kelly@seankelly.tv&lt;/address&gt;&nbsp;<br />

&nbsp;&lt;/emailaddrs&gt;<br />
&lt;/user&gt;<br />
用 JSON 表示如下：<br />
{<br />
&nbsp;"name":"张三",<br />
&nbsp;"age":30,<br />
&nbsp;"emailaddrs": [&nbsp;<br />
&nbsp;&nbsp;{"type": "work", "value":
"<a HREF="mailto:kelly@seankelly.biz">kelly@seankelly.biz</A>"},&nbsp;<br />

&nbsp;&nbsp;{"type": "home", "value":
"<a HREF="mailto:kelly@seankelly.tv">kelly@seankelly.tv</A>"}&nbsp;<br />

&nbsp;]<br />
}<br />
与XML一样，JSON也是基于文本的，且它们都使用Unicode编码，同样具有可读性。XML比较适合于标记文档，而 JSON
却更适合于时行数据交换处理。</P>
<p>&nbsp;</P>
<font STYLE="FonT-siZe: 20px"><strong>5.1 as3corelib —
AS3开源库</STRONG></FONT><br />
As3corelib是Adobe官方出品的ActionScript 3
函数库，这个库包括了MD5、SHA1、SHA224、SHA256加密，PNG、JPG编码，JSON序列化等强大功能。<br />
地址：<a HREF="http://code.google.com/p/as3corelib/">http://code.google.com/p/as3corelib/</A>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>5.2 as3corelib — JSON
类范例</STRONG></FONT><br />
var person:Object = new Object();<br />
person.name = "张三";<br />
person.age = 30;</P>
<p>person.emailaddrs = new Array();</P>
<p>var email1:Object = new Object();<br />
email1.type = "work";<br />
email1.value = "<a HREF="mailto:kerry@work.com">kerry@work.com</A>";</P>
<p>var email2:Object = new Object();<br />
email2.type = "home";<br />
email2.value = "<a HREF="mailto:kerry@home.com">kerry@home.com</A>";<br />
person.emailaddrs.push(email1, email2);</P>
<p>var jsonStr:String = JSON.encode(person);<br />
trace(jsonStr);<br /></P>
<p>var resultPerson:Object = JSON.decode(jsonStr);<br />
trace(resultPerson.age);// 30</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>6.1 Alcon —
轻量级调试工具</STRONG></FONT><br />
Alcon 简介：为 AS 开发人员提供简单直接、方便、快捷的程序调试方法和监视器。</P>
<p>App Monitor：用于监视应用程序的帧频，帧的渲染时间以及内存消耗情况：<br />
Debug.monitor(stage, 1000);<br />
Debug.mark(0xFF0000);</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>6.2 Alcon
快速开始</STRONG></FONT><br />
将 Alcon 的源码加入到类路径，调试程序<br />
import com.hexagonstar.util.debug.Debug;</P>
<p>Debug.trace(“hello”);// 打印字符串</P>
<p>Debug.traceObj(obj); // 打印对象</P>
<p>Debug.inspect(obj); // 观察对象</P>
<p>Debug.hexDump(obj); // 打印十六进制信息</P>
<p>Debug.delimiter(); // 打印分割线</P>
<p>Debug.timerStart("循环开始");<br />
for (var i:int = 0; i &lt; 1000000; i++) {}<br />
Debug.timerStopToString();</P>
<p><br />
&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>7.1 AMFPHP
简介<br /></STRONG></FONT>&#9679; AMFPHP 是 Action Message Format（AMF）的一个开源
PHP 实现。用于在 PHP 与 Flash 无缝交换数据，不需要手动进行序列化。AMF
是基于二进制的数据传输格式，数据体积小、效率高，尤其是大数据量的传输。</P>
<p>&#9679; 运行环境<br />
Apache2.2 + PHP5 + MySQL5</P>
<p>&#9679; 下载安装：<a HREF="http://www.amfphp.org/">http://www.amfphp.org/</A></P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>7.2 AMFPHP
使用规范<br /></STRONG></FONT>一、PHP后台采用AMFPHP框架进行编码，数据通信格式为AMF3。调试方法：NetDebug::trace()。<br />

AMFPHP采用创建类的方式对业务逻辑进行封装。创建类时，以其所处理的逻辑不同进行划分。</P>
<p>&nbsp;</P>
<p>二、在AMFPHP框架中输出中文需要加入在gateway.php中加入：<br />
$gateway-&gt;setCharsetHandler( "iconv", "utf-8",
"utf-8" );</P>
<p>&nbsp;</P>
<p>三、数据封装方式：<br />
1.返回数组：<br />
$user =
array('name'=&gt;'kerry','sex'=&gt;'male','age'=&gt;23);</P>
<p>2.返回对象：<br />
$user -&gt; name = 'kerry';<br />
$user -&gt; sex = 'male';<br />
$user -&gt; age = 23;</P>
<p>&nbsp;</P>
<p>四、代码编写时，需要写明方法注释及参数定义（@param），以便提高代码的可维护性：<br />
function getUserInfo($id, $name) {…}</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>7.3 AMFPHP
后台接口示例</STRONG></FONT><br />
&lt;?php<br />
&nbsp;class User {<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;function getUserInfo($uid)
{<br />
&nbsp;&nbsp;&nbsp;$conn =
mysql_connect("localhost", "root", "");<br />
&nbsp;&nbsp;&nbsp;mysql_select_db("test");<br />

&nbsp;&nbsp;&nbsp;mysql_query("set
names utf8");<br />
&nbsp;&nbsp;&nbsp;$sql =
"select name,age from user where id = {$uid}";<br />
&nbsp;&nbsp;&nbsp;$users =
mysql_query($sql);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;$result =
array();<br />
&nbsp;&nbsp;&nbsp;while ($row =
mysql_fetch_assoc($users)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;array_push($result,
$row);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;mysql_free_result($users);<br />

&nbsp;&nbsp;&nbsp;mysql_close($conn);<br />

&nbsp;&nbsp;&nbsp;return
$result;<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
?&gt;</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>7.4 Connection
—后台调用类</STRONG></FONT><br />
package&nbsp; {<br />
&nbsp;import flash.net.NetConnection;<br />
&nbsp;import flash.net.Responder;<br />
&nbsp;<br />
&nbsp;public class Connection {<br />
&nbsp;&nbsp;private var
gateway:NetConnection;<br />
&nbsp;&nbsp;public static var
instance:Connection;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public function
Connection(gatePath:String) {<br />
&nbsp;&nbsp;&nbsp;instance =
this;<br />
&nbsp;&nbsp;&nbsp;gateway = new
NetConnection();<br />
&nbsp;&nbsp;&nbsp;gateway.connect(gatePath);<br />

&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;private function
getResponder(result:Function):Responder {<br />
&nbsp;&nbsp;&nbsp;return new
Responder(result, onFault);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;private function
onFault(info:Object):void {<br />
&nbsp;&nbsp;&nbsp;trace(info.description);<br />

&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public function
getUserInfo(callBack:Function, uid:uint):void {<br />
&nbsp;&nbsp;&nbsp;gateway.call("User.getUserInfo",
getResponder(callBack), uid);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;<br />
&nbsp;}<br />
}</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>7.5
调用后台及处理结果</STRONG></FONT><br />
前台调用<br />
new Connection("<a HREF="http://localhost/flash_hello/amfphp/gateway.php">http://localhost/flash_hello/amfphp/gateway.php</A>");<br />

Connection.instance.getUserInfo(getUserInfoSuccess, 1);</P>
<p>private function getUserInfoSuccess(result:Object):void {<br />
&nbsp;var user:Object = result[0] as Object;<br />
&nbsp;trace("user name: "&nbsp; +
user.name);<br />
&nbsp;trace("user age: "&nbsp; +
user.age);<br />
}</P>
<p>输出结果<br />
user name: 张三<br />
user age: 16</P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>8. KerryLib AS3
开源类库</STRONG></FONT><br />
安装 SVN 客户端 —— TortoiseSVN： <a HREF="http://tortoisesvn.net/downloads">http://tortoisesvn.net/downloads</A><br />

SVN Checkout： <a HREF="http://kerryas.googlecode.com/svn/trunk/KerryLib">http://kerryas.googlecode.com/svn/trunk/KerryLib</A></P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>9.1
SWFObject.js</STRONG></FONT><br />
SWFObject是一个用于在 HTML 中方面插入 Adobe Flash
媒体资源（*.swf文件）的独立、敏捷的JavaScript 模块。该模块中的 JavaScript 脚本能够自动检测 PC、Mac
机器上各种主流浏览器对 Flash 插件的支持情况。它使得插入 Flash
媒体资源尽量简捷、安全。而且它是非常符合搜索引擎优化的原则的。此外，它能够避免您的 HTML、XHTML 中出现
object、embed 等非标准标签，从而符合更加标准。<br />
下载地址（版本 2.2）：<a HREF="http://code.google.com/p/swfobject/">http://code.google.com/p/swfobject/</A></P>
<p>&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>9.2 SWFObject 将 Flash
嵌入网页</STRONG></FONT><br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp;&lt;title&gt;hello_flash&lt;/title&gt;<br />

&nbsp;&lt;script src="js/swfobject.js"
type="text/javascript"&gt;&lt;/script&gt;<br />

&nbsp;&lt;script
type="text/javascript"&gt;<br />
&nbsp;&nbsp;var flashvars = {<br />
&nbsp;&nbsp;&nbsp; gateway_path
: "<a HREF="http://localhost/flash_hello/amfphp/gateway.php">http://localhost/flash_hello/amfphp/gateway.php</A>"<br />

&nbsp;&nbsp;};<br />
&nbsp;&nbsp;var params = {};<br />
&nbsp;&nbsp;var attributes = {};<br />
&nbsp;&nbsp;swfobject.embedSWF("hello_flash.swf",
"myContent", "550", "400", "9.0.0","expressInstall.swf", flashvars,
params, attributes);<br />
&nbsp;&lt;/script&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp;&lt;div
id="myContent"&gt;&lt;/div&gt;<br />

&lt;/body&gt;<br />
&lt;/html&gt;</P>
<p><br />
&nbsp;</P>
<p><font STYLE="FonT-siZe: 20px"><strong>9.3 在 Flash
中接收页面参数</STRONG></FONT><br />
var textField:TextField = new TextField();<br />
textField.width = stage.stageWidth;<br />
addChild(textField);</P>
<p>var gateway_path:String =
<strong>stage.loaderInfo.parameters.gateway_path</STRONG>;</P>
<p>textField.text = gateway_path ? gateway_path : "no values";</P>]]></description>
            <author>FL车在臣</author>
            <category>视频教程</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eysl.html#comment</comments>
            <pubDate>Tue, 08 Sep 2009 14:34:51 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eysl.html</guid>
        </item>
        <item>
            <title>KerryLib AS3 开源项目启动 [FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100etuu.html</link>
            <description><![CDATA[<p ALIGN="center"><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static3.photo.sina.com.cn/orignal/3ecb9b11t725afa7bb902&amp;690" TARGET="_blank"><img SRC="http://static3.photo.sina.com.cn/bmiddle/3ecb9b11t725afa7bb902&amp;690" /></A></P>
<p>&nbsp;&nbsp;&nbsp; KerryLib
是基于 ActionScript 3 的开源项目，内容涉及功能代码类、特殊效果类、工具类、组件类等（内附 API 文档及使用示例
demo），作者 FL 车在臣。</P>
<p>&nbsp;&nbsp;&nbsp; KerryLib
（源码及演示程序）svn 地址：<a HREF="http://kerryas.googlecode.com/svn/trunk/KerryLib">http://kerryas.googlecode.com/svn/trunk/KerryLib</A></P>
<p>&nbsp;</P>
<p><strong>KerryLib v0.1 更新内容</STRONG></P>
<p>com.kerry.effect</P>
<p>&nbsp;&nbsp;&nbsp; --
Light</P>
<p>&nbsp;&nbsp;&nbsp; --
PowerFilters</P>
<p>com.kerry.page</P>
<p>&nbsp;&nbsp;&nbsp; --
PageSwitch</P>
<p>com.kerry.util</P>
<p>&nbsp;&nbsp;&nbsp; --
DateUtil</P>
<p><font STYLE="font-size: 22px;"><strong>KerryLib v0.1 部分 demo
程序效果：</STRONG></FONT></P>
<p><strong>com.kerry.effect.Light =&gt;
LightDemo.thunderStorm</STRONG></P>
<p><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static16.photo.sina.com.cn/orignal/3ecb9b11t725ade25bd9f&amp;690" TARGET="_blank"><img SRC="http://static16.photo.sina.com.cn/bmiddle/3ecb9b11t725ade25bd9f&amp;690" /></A></P>
<p><br /></P>
<p><strong>com.kerry.effect.PowerFilters</STRONG></P>
<p><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static2.photo.sina.com.cn/orignal/3ecb9b11t721988f9bec1&amp;690" TARGET="_blank"><img SRC="http://static2.photo.sina.com.cn/bmiddle/3ecb9b11t721988f9bec1&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static10.photo.sina.com.cn/orignal/3ecb9b11t74ff5a8cdf19&amp;690" TARGET="_blank"><img SRC="http://static10.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5a8cdf19&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static1.photo.sina.com.cn/orignal/3ecb9b11t74ff5b8a5e50&amp;690" TARGET="_blank"><img SRC="http://static1.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5b8a5e50&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static4.photo.sina.com.cn/orignal/3ecb9b11tc91f9e0e11a3&amp;690" TARGET="_blank"><img SRC="http://static4.photo.sina.com.cn/bmiddle/3ecb9b11tc91f9e0e11a3&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static15.photo.sina.com.cn/orignal/3ecb9b11t74ff63d410ce&amp;690" TARGET="_blank"><img SRC="http://static15.photo.sina.com.cn/bmiddle/3ecb9b11t74ff63d410ce&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static2.photo.sina.com.cn/orignal/3ecb9b11t74ff649fc451&amp;690" TARGET="_blank"><img SRC="http://static2.photo.sina.com.cn/bmiddle/3ecb9b11t74ff649fc451&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static11.photo.sina.com.cn/orignal/3ecb9b11tc91f9f22a3da&amp;690" TARGET="_blank"><img SRC="http://static11.photo.sina.com.cn/bmiddle/3ecb9b11tc91f9f22a3da&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static4.photo.sina.com.cn/orignal/3ecb9b11t74ff656ad8f3&amp;690" TARGET="_blank"><img SRC="http://static4.photo.sina.com.cn/bmiddle/3ecb9b11t74ff656ad8f3&amp;690" STYLE="" /></A></P>
<a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static8.photo.sina.com.cn/orignal/3ecb9b11t74ff5d2c3277&amp;690" TARGET="_blank"><img SRC="http://static8.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5d2c3277&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static16.photo.sina.com.cn/orignal/3ecb9b11t74ff5db9e28f&amp;690" TARGET="_blank"><img SRC="http://static16.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5db9e28f&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static2.photo.sina.com.cn/orignal/3ecb9b11tc91f9aecfcd1&amp;690" TARGET="_blank"><img SRC="http://static2.photo.sina.com.cn/bmiddle/3ecb9b11tc91f9aecfcd1&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static1.photo.sina.com.cn/orignal/3ecb9b11t72198976d4f0&amp;690" TARGET="_blank"><img SRC="http://static1.photo.sina.com.cn/bmiddle/3ecb9b11t72198976d4f0&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static6.photo.sina.com.cn/orignal/3ecb9b11t74ff5f9e0705&amp;690" TARGET="_blank"><img SRC="http://static6.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5f9e0705&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static13.photo.sina.com.cn/orignal/3ecb9b11t74ff5fea43ec&amp;690" TARGET="_blank"><img SRC="http://static13.photo.sina.com.cn/bmiddle/3ecb9b11t74ff5fea43ec&amp;690" STYLE="" /></A><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static11.photo.sina.com.cn/orignal/3ecb9b11t74ff618be3ea&amp;690" TARGET="_blank"><img SRC="http://static11.photo.sina.com.cn/bmiddle/3ecb9b11t74ff618be3ea&amp;690" STYLE="" /></A>]]></description>
            <author>FL车在臣</author>
            <category>KerryLib</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100etuu.html#comment</comments>
            <pubDate>Sun, 30 Aug 2009 11:46:02 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100etuu.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8553;&amp;#8549;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eskt.html</link>
            <description><![CDATA[<h2>第十六章 改进控制器和视图</H2>
<p>第2版的 R4RMusic 的控制器动作及相应模版总结</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="83">
<p ALIGN="center"><strong>控制器</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="192">
<p ALIGN="center"><strong>描述</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="120">
<p ALIGN="center"><strong>动作方法名</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="173">
<p ALIGN="center"><strong>主模板</STRONG></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Customer</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>登录</P>
<p>注销</P>
<p>注册一个新帐号</P>
<p>给购物车添加一个版本</P>
<p>查看购物车</P>
<p>结帐（购买完毕）</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>login</P>
<p>logout</P>
<p>signup</P>
<p>add_to_cart</P>
<p>view_cart</P>
<p>check_out</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>main/welcome.rhtml</P>
<p>main/welcome.rhtml</P>
<p>main/welcome.rhtml</P>
<p>customer/view_cart.rhtml</P>
<p>customer/view_cart.rhtml</P>
<p>customer/check_out.rhtml</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Main</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>欢迎访问者</P>
<p>显示给定时代的所有作品</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>welcome</P>
<p>show_period</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>main/welcome.rhtml</P>
<p>main/show_period.rhtml</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Composer</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>显示某作曲者作品的所有版本</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>show</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>composer/show.rhtml</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Edition</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>显示版本的详细出版信息</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>show</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>edition/show.rhtml</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Instrument</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>显示给定乐器的所有作品</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>show</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>instrument/show.rhtml</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Work</P>
</TD>
<td VALIGN="top" WIDTH="192">
<p>显示给定作品的所有版本</P>
</TD>
<td VALIGN="top" WIDTH="120">
<p>show</P>
</TD>
<td VALIGN="top" WIDTH="173">
<p>work/show.rhtml</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>R4RMusic 最终版下载：<a HREF="http://kerryas.googlecode.com/files/r4rmusic.rar">http://kerryas.googlecode.com/files/r4rmusic.rar</A></P>
<p>&nbsp;</P>
<h3>一、为视图模板定义辅助方法</H3>
<p>1. 组织和访问定制的辅助方法</P>
<p>在 app/helper 目录下是对于每个控制器的辅助文件
<i>controller</I>_helper.rb，例如，composer_helper.rb 包含下面内容</P>
<p>module ComposerHelper</P>
<p>end</P>
<p>把方法定义到辅助文件中可以有助于减少重复代码，可以编写一个自动产生链接的辅助方法</P>
<p>module ComposerHelper</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def link_to_composer(composer)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to (composer.whole_name,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "composer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id
=&gt; composer.id)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>下面是如何在模版中使用这个新的 link_to_composer 方法的例子</P>
<p>&lt;ul&gt;</P>
<p>&nbsp; &lt;% @composers.each do
|composer| %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%=
link_to_composer(composer)
%&gt;&lt;/li&gt;</P>
<p>&nbsp; &lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>使用其它辅助文件中的方法</P>
<p>方法一：在辅助方法的控制器中，将该方法声明为 helper，例如</P>
<p>class MainController &lt; ApplicationController</P>
<p>&nbsp; helper :composer</P>
<p>&nbsp; # etc.</P>
<p>end</P>
<p>&nbsp;</P>
<p>方法二：把辅助文件放到通用的辅助文件 application_helper.rb
中，这样对于所有的控制器和模版来说这些方法都是可见的。</P>
<p>&nbsp;</P>
<p>2. 为 R4RMusic 定制的辅助方法</P>
<p>&nbsp;</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="158">
<p ALIGN="center"><b>方法</B></P>
</TD>
<td WIDTH="161">
<p ALIGN="center"><b>定义于</B></P>
</TD>
<td WIDTH="249">
<p ALIGN="center"><b>通过</B> <b>helper</B> <b>包含到这些控制器中</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="158">
<p>link_to_composer</P>
<p>link_to_work</P>
<p>&nbsp;</P>
<p>link_to_edition</P>
<p>link_to_edition_title</P>
<p>link_to_instrument</P>
<p>two_dec</P>
</TD>
<td VALIGN="top" WIDTH="161">
<p>composer_helper.rb</P>
<p>work_helper.rb</P>
<p>&nbsp;</P>
<p>edition_helper.rb</P>
<p>edition_helper.rb</P>
<p>instrument_helper.rb</P>
<p>application_helper.rb</P>
</TD>
<td VALIGN="top" WIDTH="249">
<p>customer, edition, main</P>
<p>composer, customer, edition, instrument, main</P>
<p>customer, work</P>
<p>composer, instrument</P>
<p>main</P>
<p>可被所有控制器访问</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>&nbsp;</P>
<p>下面是前五个辅助方法的定义：</P>
<p>def link_to_composer(composer)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to(composer.whole_name,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "composer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; composer.id)</P>
<p>end</P>
<p>&nbsp;</P>
<p>def link_to_edition(edition)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to edition.description,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "edition",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; edition.id</P>
<p>end</P>
<p>&nbsp;</P>
<p>def link_to_edition_title(edition)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to edition.nice_title,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "edition",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; edition.id</P>
<p>end</P>
<p>&nbsp;</P>
<p>def link_to_work(work)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to(work.nice_title,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "work",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; work.id)</P>
<p>end</P>
<p>&nbsp;</P>
<p>def link_to_instrument(instrument)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link_to instrument.name,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "instrument",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; instrument.id</P>
<p>end</P>
<p>&nbsp;</P>
<p>第六个辅助方法将一个浮点数转换为一个包含两个十进制小数的字符串</P>
<p>module ApplicationHelper</P>
<p>&nbsp; def two_dec(n)</P>
<p>&nbsp;&nbsp;&nbsp;
sprintf("%.2f", n)</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>二、编码和部署部分视图模板</H3>
<p>1. 剖析主模板</P>
<p>首先查看 composer/show.html.erb 模板文件</P>
<p>&lt;% @page_title = "Editions of works by
#{@composer.whole_name}" %&gt;</P>
<p>&nbsp;</P>
<p>&nbsp;&lt;h2
class="info"&gt;&lt;%= @page_title
%&gt;&lt;/h2&gt;</P>
<p>&nbsp;&lt;p&gt;Click on any
edition to see details.&lt;/p&gt;</P>
<p>&nbsp;&lt;%= render :partial
=&gt; "editions" %&gt;</P>
<p>&nbsp;</P>
<p>其中 render 方法检查部分模版名字，在它前面添加一下划线，在它后面添加一个 .html.erb 后缀，下面是
composer/_editions.html.erb</P>
<p>&lt;ul&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% @composer.editions.map do |edition|
%&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%=
link_to_edition_title(edition) %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(&lt;%= edition.publisher.name %&gt;,
&lt;%= edition.year
%&gt;)&lt;/li&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>2. 在欢迎视图模板中使用部分模版</P>
<p>（1）生成作曲者链接清单</P>
<p>创建作曲者链接清单 composer/_list.html.erb</P>
<p>&lt;ul&gt;</P>
<p>&nbsp;&nbsp; &lt;%
@composers.each do |composer| %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%=
link_to_composer(composer)
%&gt;&lt;/li&gt;</P>
<p>&nbsp;&nbsp; &lt;% end
%&gt;</P>
<p>&nbsp;&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>将下面这一行放到主模板 main/welcome.html.erb 中</P>
<p>&lt;%= render :partial =&gt;
"composer/list" %&gt;</P>
<p>&nbsp;</P>
<p>（2）生成乐器链接清单</P>
<p>部分模版 instrument/_list.html.erb</P>
<p>&lt;ul&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% @instruments.each do
|instrument|%&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%=
link_to_instrument(instrument)
%&gt;&lt;/li&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>创建 instrument 控制器：</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
controller instrument show</P>
<p>&nbsp;</P>
<p>完成 instrument_controller.rb 文件：</P>
<p>class InstrumentController &lt;
ApplicationController</P>
<p>&nbsp;&nbsp; helper :work, :edition</P>
<p>&nbsp;&nbsp; def show</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
@instrument = Instrument.find(params[:id])</P>
<p>&nbsp;&nbsp; end</P>
<p>&nbsp;end</P>
<p>&nbsp;</P>
<p>（3）生成音乐时代的链接清单</P>
<p>产生音乐时代的链接清单 main/_period_list.html.erb</P>
<p>&lt;ul&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% @periods.each do |period| %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%= link_to
period,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "main",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show_period",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; period %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;% end %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/li&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>我们也需要为在 welcome 模板中加入部分模板</P>
<p>&lt;%= render :partial =&gt;
"period_list" %&gt;</P>
<p>&nbsp;</P>
<p>（4） 完整的欢迎模板（views/main/welcome.html.erb）</P>
<p>&lt;% if @c %&gt;</P>
<p>&nbsp;&nbsp;
&lt;h3&gt;Welcome, &lt;%=
@c.first_name
%&gt;.&lt;/h3&gt;</P>
<p>&nbsp;&lt;% end %&gt;</P>
<p>&nbsp;&lt;h2
class="info"&gt;Browse works
by...&lt;/h2&gt;</P>
<p>&nbsp;</P>
<p>&nbsp;&lt;table&gt;</P>
<p>&nbsp;&nbsp;
&lt;tr&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;th&gt;...Period&lt;/th&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;th&gt;...Composer&lt;/th&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;th&gt;...Instrument&lt;/th&gt;</P>
<p>&nbsp;&nbsp;
&lt;/tr&gt;</P>
<p>&nbsp;&nbsp;
&lt;tr&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= render :partial =&gt; "period_list"
%&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= render :partial =&gt;
"composer/list" %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= render :partial =&gt;
"instrument/list" %&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/td&gt;</P>
<p>&nbsp;&nbsp;
&lt;/tr&gt;</P>
<p>&nbsp;&lt;/table&gt;</P>
<p>&nbsp;</P>
<p>&nbsp;&lt;% if @c %&gt;</P>
<p>&nbsp;&nbsp; &lt;%= render
:partial =&gt; "favorites" %&gt;</P>
<p>&nbsp;&lt;% else %&gt;</P>
<p>&nbsp;&nbsp; &lt;h2
class="info"&gt;Log in or create an
account&lt;/h2&gt;</P>
<p>&nbsp;&nbsp; &lt;table
border="1"&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;tr&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;th&gt;Log in to your
account&lt;/th&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;th&gt;Sign up for an
account&lt;/th&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/tr&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;tr&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= render
:partial =&gt; "customer/login"
%&gt;&lt;/td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= render
:partial =&gt; "customer/signup"
%&gt;&lt;/td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/tr&gt;</P>
<p>&nbsp;&nbsp;
&lt;/table&gt;</P>
<p>&nbsp;&lt;% end %&gt;</P>
<p>&nbsp;</P>
<h3>三、更新主控制器</H3>
<p>Welcome 动作新面孔（main_controller.rb）：</P>
<p>class MainController &lt; ApplicationController</P>
<p>&nbsp; helper :work, :composer, :instrument</P>
<p>&nbsp;</P>
<p>&nbsp; def welcome</P>
<p>&nbsp;&nbsp;&nbsp;
@composers = Composer.find(:all).sort_by do |composer|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[composer.last_name, composer.first_name, composer.middle_name]</P>
<p>&nbsp;&nbsp;&nbsp; end</P>
<p>&nbsp;&nbsp;&nbsp; @periods
= Work.all_periods</P>
<p>&nbsp;&nbsp;&nbsp;
@instruments = Instrument.find(:all, :order =&gt; "name
ASC" )</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>&nbsp; def show_period</P>
<p>&nbsp;&nbsp;&nbsp; @period =
params[:id]</P>
<p>&nbsp;&nbsp;&nbsp; works =
Work.find(:all).select do |work|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(work.period == @period) || (work.century == @period)</P>
<p>&nbsp;&nbsp;&nbsp; end</P>
<p>&nbsp;&nbsp;&nbsp; @editions
= Edition.of_works(works)</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>end</P>
<p>&nbsp;</P>
<h3>四、加入顾客注册的登录动作</H3>
<p>1. 登录和注册部分模板</P>
<p>（1）注册模板 customer/_signup.html.erb</P>
<p>&lt;% form_tag :controller =&gt;
"customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "signup" do %&gt;</P>
<p>&nbsp; &lt;p&gt;First
name:&nbsp;&nbsp;&nbsp;
&lt;%= text_field "customer",
"first_name"&nbsp;&nbsp;&nbsp;
%&gt; &lt;/p&gt;</P>
<p>&nbsp; &lt;p&gt;Last
name:&nbsp;
&nbsp;&nbsp;&nbsp;&lt;%=
text_field "customer",
"last_name"&nbsp;&nbsp;&nbsp;&nbsp;
%&gt; &lt;/p&gt;</P>
<p>&nbsp; &lt;p&gt;User
name:&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= text_field "customer",
"nick"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
%&gt; &lt;/p&gt;</P>
<p>&nbsp;
&lt;p&gt;Password:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= password_field "customer",
"password"&nbsp; %&gt;
&lt;/p&gt;</P>
<p>&nbsp; &lt;p&gt;Email
address: &lt;%= text_field "customer",
"email"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
%&gt; &lt;/p&gt;</P>
<p>&nbsp;
&lt;p&gt;&lt;input
type="Submit" value="Sign
up"/&gt;&lt;/p&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&nbsp;</P>
<p>（2）登录模板 customer/_login.html.erb</P>
<p>&lt;% form_tag :controller =&gt;
"customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "login" do %&gt;</P>
<p>&nbsp;&lt;p&gt;User name:
&lt;%= text_field "customer", "nick"
%&gt;&lt;/p&gt;</P>
<p>&nbsp;&lt;p&gt;Password:
&lt;%= password_field "customer",
"password"&nbsp;
%&gt;&lt;/p&gt;</P>
<p>
&nbsp;&lt;p&gt;&lt;input
type="Submit" value="Log
in"/&gt;&lt;/p&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&nbsp;</P>
<p>2. 登录和保存会话状态</P>
<p>def login</P>
<p>&nbsp; pw,nick =
params[:customer].values_at(*%w{password nick})</P>
<p>&nbsp; c = Customer.find_by_nick(nick)</P>
<p>&nbsp; if c &amp;&amp;
Digest::SHA1.hexdigest(pw) == c.password</P>
<p>&nbsp;&nbsp;&nbsp;
@session['customer'] = c.id</P>
<p>&nbsp;&nbsp;&nbsp;
redirect_to :controller =&gt; "main", :action
=&gt; "welcome"</P>
<p>&nbsp; else</P>
<p>&nbsp;&nbsp;&nbsp;
report_error("Invalid login")</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 用 before_filter 看守动作（ApplicationController.rb）</P>
<p>class ApplicationController &lt;
ActionController::Base</P>
<p>&nbsp; layout("base")</P>
<p>&nbsp;</P>
<p>&nbsp; before_filter :get_customer</P>
<p>&nbsp;&nbsp;</P>
<p>&nbsp; def get_customer</P>
<p>&nbsp;&nbsp;&nbsp; if
session['customer']</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@c = Customer.find(session['customer'])</P>
<p>&nbsp;&nbsp;&nbsp; end</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>如果 session 中已经保存了用户的 ID ，那么数据库中可以查找出该对象则 @c 不为空，否则 @c
为空那么，主界面中显示提示用户登录：</P>
<p>&lt;% if @c %&gt;</P>
<p>&nbsp; &lt;%= render :partial
=&gt; "favorites" %&gt;</P>
<p>&lt;% else %&gt;</P>
<p>&nbsp; &lt;h2
class="info"&gt;Log in or create an
account&lt;/h2&gt;</P>
<p>&nbsp; #</P>
<p>&nbsp; # display of login and signup forms handled
here</P>
<p>&nbsp; #</P>
<p>&lt;% end %&gt;</P>
<p>&nbsp;</P>
<p>我们还希望过滤器能在顾客没有登录的情况下拦截请求动作（CustomerController.rb）</P>
<p>before_filter :authorize, :except =&gt;
["signup","login"]</P>
<p>def authorize</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return true if @c</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
report_error("Unauthorized access; password required")</P>
<p>end</P>
<p>其中 report_error 是一个自制的、通过错误报告方法，被定义在 application.rb 中</P>
<p>class ApplicationController &lt;
ActionController::Base</P>
<p>&nbsp; # prior code here, then:</P>
<p>&nbsp; private</P>
<p>&nbsp; def report_error(message)</P>
<p>&nbsp;&nbsp;&nbsp; @message
= message</P>
<p>&nbsp;&nbsp;&nbsp;
render("main/error")</P>
<p>&nbsp;&nbsp;&nbsp; return
false</P>
<p>&nbsp; end</P>
<p>end</P>
<p>该方法把传入的消息赋值给 @message 实例变量，呈现在 app/views/main/error.html.erb</P>
<p>&nbsp;</P>
<p>4. 实现注册功能（CustomerController.rb）</P>
<p>def signup</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c = Customer.new(params[:customer])</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c.password = Digest::SHA1.hexdigest(c.password)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c.save</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
session['customer'] = c.id</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
redirect_to :controller =&gt; "main", :action
=&gt; "welcome"</P>
<p>end</P>
<p>&nbsp;</P>
<p>使用 before_filter 技术，进行表单数据的验证，创建一个 new_customer 的过滤器，仅让它在 signup
动作之前作为过滤器执行</P>
<p>before_filter :new_customer,
:only&nbsp;&nbsp; =&gt;
["signup"]</P>
<p>&nbsp;</P>
<p>def new_customer</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
applicant = params[:customer]</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if Customer.find_by_nick(applicant['nick'])</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
report_error("Nick already in use. Please choose another.")</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
elsif Customer.find_by_email(applicant['email'])</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
report_error("Account already exists for that email address")</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>5. 编写顾客注销脚本（在 app/view/layout/base.html.erb 中加入注销按钮，加在 body
中）</P>
<p>&lt;table&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= link_to
"Home",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "main",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "welcome"
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;% if @c %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= link_to "View
cart",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "view_cart"
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= link_to "Log
out",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "logout"
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;% end %&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&lt;/table&gt;</P>
<p>&nbsp;</P>
<h3>五、处理顾客订单</H3>
<p>首先为 app/controllers/customer_controller.rb 添加一个动作</P>
<p>def view_cart</P>
<p>end</P>
<p>&nbsp;</P>
<p>然后实现 view_cart.html.erb 视图</P>
<p>&lt;% @page_title = "Shopping cart for #{@c.nick}"
%&gt;</P>
<p>&lt;%= render :partial =&gt; "cart"
%&gt;</P>
<p>&nbsp;</P>
<p>以下是购物车视图的 customer/_cart.html.erb 部分模板</P>
<p>&lt;table border="1"&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Title&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Composer&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Publisher&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Price&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Copies&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Subtotal&lt;/th&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&nbsp;</P>
<p>&lt;% @c.editions_on_order.each do |edition|
%&gt;</P>
<p>&lt;% count = @c.copies_of(edition)
%&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%=
link_to_edition_title(edition)
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;% edition.composers.each do |composer|
%&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;%= link_to_composer(composer) %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;% end
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%=
edition.publisher.name
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td class="price"&gt;&lt;%=
two_dec(edition.price) %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td class="count"&gt;&lt;%=
count %&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td class="price"&gt;&lt;%=
two_dec(edition.price * count)
%&gt;&lt;/td&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&nbsp;
&lt;tr&gt;&lt;td
colspan="5"&gt;TOTAL&lt;/td&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;td class="price"&gt;&lt;%=
two_dec(@c.balance)
%&gt;&lt;/td&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&lt;/table&gt;</P>
<p>&lt;p&gt;&lt;%=
link_to("Complete purchases",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "check_out")
%&gt;&lt;/p&gt;</P>
<p>&nbsp;</P>
<p>2. 查看和购买一个版本</P>
<p>查看版本的主模板，edition/show.html.erb</P>
<p>&lt;% @page_title = @edition.nice_title
%&gt;</P>
<p>&lt;h2
class="info"&gt;&lt;%= @page_title
%&gt;&lt;/h2&gt;</P>
<p>&lt;%= render :partial =&gt; "details"
%&gt;</P>
<p>&nbsp;</P>
<p>查看版本的部分模板，edition/_details.html.erb 部分模板</P>
<p>&lt;ul&gt;</P>
<p>&nbsp; &lt;li&gt;Edition:
&lt;%= @edition.description
%&gt;&lt;/li&gt;</P>
<p>&nbsp; &lt;li&gt;Publisher:
&lt;%= @edition.publisher.name
%&gt;&lt;/li&gt;</P>
<p>&nbsp; &lt;li&gt;Year:
&lt;%= @edition.year
%&gt;&lt;/li&gt;</P>
<p>&nbsp; &lt;li&gt;Price:
&lt;%= two_dec(@edition.price)
%&gt;&lt;/li&gt;</P>
<p>&lt;% if @c %&gt;</P>
<p>&nbsp;&nbsp;
&lt;li&gt;&lt;%= link_to "Add
to cart",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "customer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "add_to_cart",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; @edition.id
%&gt;&lt;/li&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>
&lt;h3&gt;Contents:&lt;/h3&gt;</P>
<p>&lt;ul&gt;</P>
<p>&lt;% @edition.works.each do |work|
%&gt;</P>
<p>&nbsp;
&lt;li&gt;&lt;%=
link_to_work(work) %&gt; (&lt;%=
link_to_composer(work.composer)
%&gt;)&lt;/li&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>3. 定义 add_to_cart 动作（CustomerController.rb）</P>
<p>def add_to_cart</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
e = Edition.find(params[:id])</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
order = Order.create(:customer =&gt; @c,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;:edition&nbsp; =&gt;
e)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if order</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
redirect_to :action =&gt; "view_cart"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
report_error("Trouble with saving order")</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>4. 完成订单</P>
<p>在 CustomerController.rb 中定义</P>
<p>def check_out</P>
<p>&nbsp; @c.check_out</P>
<p>end</P>
<p>&nbsp;</P>
<p>再定义 app\views\customer\check_out.html.erb 作为结算完成视图，内容如下</P>
<p>&lt;% @page_title = "Orders complete"
%&gt;</P>
<p>&lt;h2&gt;Thanks for your order,
&lt;%= @c.first_name
%&gt;!&lt;/h2&gt;</P>
<p>&nbsp;</P>
<h3>六、通过动态代码使页面人性化</H3>
<p>1. 从排名到喜好</P>
<p>在 app/models/customer.rb 中定义</P>
<p>def rank(list)</P>
<p>&nbsp; list.uniq.sort_by do |a|</P>
<p>&nbsp;&nbsp;&nbsp;
list.select {|b| a == b }.size</P>
<p>&nbsp; end.reverse</P>
<p>end</P>
<p>&nbsp;</P>
<p>def composer_rankings</P>
<p>&nbsp; rank(edition_history.map {|ed| ed.composers
}.flatten)</P>
<p>end</P>
<p>&nbsp;</P>
<p>def instrument_rankings</P>
<p>&nbsp; rank(work_history.map {|work|
work.instruments }.flatten)</P>
<p>end</P>
<p>&nbsp;</P>
<p>def favorites(thing,options)</P>
<p>&nbsp; limit = options[:count]</P>
<p>&nbsp; rankings = send("#{thing}_rankings")</P>
<p>&nbsp; return rankings[0,limit].compact</P>
<p>end</P>
<p>其中 favorites 方法根据 thing 参数动态选择用户喜好，给定的 count
选择数组相应的条目。如果该值比排名方法返回的数组 size 要大，那么用 nil 进行填充，最后 compact 将删除这些
nil。</P>
<p>&nbsp;</P>
<p>2. 实际使用中的 favorites 特性</P>
<p>最后让我们来实现 main/_favorites.html.erb 部分模板</P>
<p>&lt;h2 class="info"&gt;Your
favorites&lt;/h2&gt;</P>
<p>&lt;% fav_composers = @c.favorites :composer,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:count =&gt; 3 %&gt;</P>
<p>&lt;% fav_instruments = @c.favorites
:instrument,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:count =&gt; 3 %&gt;</P>
<p>&lt;ul&gt;</P>
<p>&lt;% fav_composers.each do |composer|
%&gt;</P>
<p>&nbsp;
&lt;li&gt;&lt;%=
link_to_composer(composer)
%&gt;&lt;/li&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&lt;% fav_instruments.each do |instrument|
%&gt;</P>
<p>&nbsp;
&lt;li&gt;&lt;%=
link_to_instrument(instrument)
%&gt;&lt;/li&gt;</P>
<p>&lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<div ALIGN="center">
<hr ALIGN="center" WIDTH="100%" SIZE="2" /></DIV>
<p><font STYLE="FonT-siZe: 18px"><strong>至此 Ruby For Rails
最佳实践系列教程全部结束，欢迎广大&nbsp;RoR
学习和爱好者多提宝贵意见！</STRONG></FONT></P>
<p ALIGN="right"><font STYLE="FonT-siZe: 18px"><strong>----
FL车在臣</STRONG></FONT></P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eskt.html#comment</comments>
            <pubDate>Thu, 27 Aug 2009 16:46:00 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eskt.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8553;&amp;#8548;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eskr.html</link>
            <description><![CDATA[<h2>第十五章 通过编程改进 ActiveRecord 模型</H2>
<h3>一、软模型改进与硬模型改进</H3>
<p>1. 当在 ActiveRecord
模型类中编写一个新方法时，可以把方法区分为：被动方法（即那些仅仅获取数据并返回数据的方法）和主动方法（即那些生成新的数据结构的方法）</P>
<p>class Composer &lt; ActiveRecord::Base</P>
<p>&nbsp; has_many :works</P>
<p>&nbsp;</P>
<p>&nbsp; # 软改进</P>
<p>&nbsp; def editions</P>
<p>&nbsp;&nbsp;&nbsp; works.map
{|work| work.editions }.flatten.uniq</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>&nbsp; # 硬改进</P>
<p>&nbsp; def whole_name</P>
<p>&nbsp;&nbsp;&nbsp;
first_name + " " +</P>
<p>&nbsp;&nbsp;&nbsp; (if
middle_name then middle_name + " " else "" end) +</P>
<p>&nbsp;&nbsp;&nbsp;
last_name</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 软模型改进与硬模型改进：本质区别</P>
<p>本质区别在于：软改进描述给 ActiveRecord 提供辅助；硬改进涉及产生新的数据。</P>
<p>&nbsp;</P>
<h3>二、模型的软编程改进</H3>
<p>1. 通过软改进细化 Work 模型</P>
<p>（1）哪些发行商发行过该作品的版本</P>
<p>def publishers</P>
<p>&nbsp; editions.map {|e| e.publisher}.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）该作品来自哪个国家</P>
<p>def country</P>
<p>&nbsp; composer.country</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）哪些顾客订购过该作品</P>
<p>def ordered_by</P>
<p>&nbsp; editions.orders.map {|o| o.customer
}.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（4）该作品的基调是什么</P>
<p>def key</P>
<p>&nbsp; kee</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 为顾客的业务建模</P>
<p>（1）该顾客有哪些未完成的订单</P>
<p>def open_orders</P>
<p>&nbsp; orders.find(:all, :conditions
=&gt; "status = 'open'")</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）该顾客当前订单中包含哪些版本</P>
<p>def editions_on_order</P>
<p>&nbsp; open_orders.map {|order| order.edition
}.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）该顾客曾经订购过哪些版本</P>
<p>def edition_history</P>
<p>&nbsp; orders.map {|order| order.edition }.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（4）该顾客当前订单中包含哪些作品</P>
<p>def works_on_order</P>
<p>&nbsp; editions_on_order.map {|edition|
edition.works }.flatten.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（5）该顾客曾经订购过哪些作品</P>
<p>def work_history</P>
<p>&nbsp; edition_history.map {|edition| edition.works
}.flatten.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 改进 composer</P>
<p>（1）该作曲者的作品出现在哪些版本中</P>
<p>def editions</P>
<p>&nbsp; works.map {|work| work.editions
}.flatten.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）哪些发行商发行过包含该作曲者作品的版本</P>
<p>def publishers</P>
<p>&nbsp; editions.map{|edition| edition.publisher
}.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>4. 对比软改进过程中的 Ruby 和 SQL</P>
<p>最高效、最快速的数据库记录提取方式是 SQL 代码。ActiveRecord 做的很多工作就是私底下将你的 Ruby 代码翻译为
SQL 语句，然后使用这些语句查询数据库。</P>
<p>&nbsp;</P>
<p>为了提高执行速度，ActiveRecord 允许任何时候都可以使用 SQL。可是这样就失去了良好的 Ruby
外观，却获得了效率。</P>
<p>&nbsp;</P>
<p>作为对比 Ruby/SQL 的例子，我们来看一下 Composer#editions 方法：</P>
<p>def editions</P>
<p>&nbsp; works.map {|work| work.editions
}.flatten.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>该方法首先调用 works，无条件地搜集该作曲者的所有作品。调用 works 方法之后，ActiveRecord
的任务就完成了；该方法也是唯一的一个数据库查询，返回该作曲者的所有作品。剩下的都是纯 Ruby
代码：获取作品的所有版本（使用map），这些信息被存放在一个数组的数组中，然后使用 flatten 和 uniq
对该数组进行处理。最后，得到一个新数组。</P>
<p>&nbsp;</P>
<p>下面是实现 editions 方法的另一种方式，使用 SQL 语句</P>
<p>def editions</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Edition.find_by_sql("SELECT edition_id from editions_works</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
LEFT JOIN works ON editions_works.work_id = works.id</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
LEFT JOIN composers ON works.composer_id = composers.id</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
WHERE (composers.id = #{id})")</P>
<p>end</P>
<p>&nbsp;</P>
<p>Ruby 程序员在使用 Ruby 编写程序时，知道它不是特别快的语言；在碰到严重的性能瓶颈时，他们把程序的某些部分编写为 C
扩展。而在 Rails 应用开发中，SQL 也扮演着类似的角色。</P>
<p>&nbsp;</P>
<h3>三、硬模型改进</H3>
<p>1. 美化字符串属性（Work 类）</P>
<p>（1）调整作品的各乐器名的格式</P>
<p>def nice_instruments</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrs = instruments.map {|inst| inst.name }</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ordered = %w{ flute oboe violin viola cello piano orchestra }</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrs = instrs.sort_by {|i| ordered.index(i) || 0 }</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case instrs.size</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
when 0</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nil</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
when 1</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrs[0]</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
when 2</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrs.join(" and ")</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrs[0...-2].join(", ") + ", and " + instrs[-1]</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>代码中使用了 %w{…} 构造一个字符串数组，用于存放规范的乐器名顺序</P>
<p>ordered = %w{ flute oboe violin viola cello piano orchestra
}</P>
<p>接着，根据 ordered 数组中各个乐器的出现顺序（乐器名在数组中的索引序号）对 instrs
排序，如果出现不存在的乐器名，则它将出现在排序结果的最后面</P>
<p>instrs = instrs.sort_by {|i| ordered.index(i) || 0 }</P>
<p>&nbsp;</P>
<p>（2） 调整作品号的格式</P>
<p>def nice_opus</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if /^\d/.match(opus)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"op. #{opus}"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
opus</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3） 美化的作品标题</P>
<p>def nice_title</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
t,k,o,i = title, key, nice_opus, nice_instruments</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"#{t} #{"in #{k}" if k}#{", #{o}" if o}#{", for #{i}" if i}"</P>
<p>end</P>
<p>&nbsp;</P>
<p>（4） 美化的版本标题（Edition.rb）</P>
<p>def nice_title</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(title || works[0].nice_title) +</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
" (#{publisher.name}, #{year})"</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 计算作品的年代（Work 类）</P>
<p>（1）作品出自哪个世纪</P>
<p>def century</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c = (year - 1).to_s[0,2].succ</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c += case c</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when
"21" then "st"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
"th"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c + " century"</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）作品的更富描述性的时代信息</P>
<p>在 Work 类中定义一个常量</P>
<p>PERIODS = { [1650..1750, %w{ EN DE FR IT ES NL}]
=&gt; "Baroque",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[1751..1810, %w{ EN IT DE NL
}]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "Classical",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1751..1830,
%w{ FR
}]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "Classical",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1837..1901,
%w{ EN }]&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&gt;
"Victorian",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1820..1897,
%w{ DE FR
}]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "Romantic" }</P>
<p>&nbsp;</P>
<p>然后加入该方法</P>
<p>def period</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pkey = PERIODS.keys.find do |yrange, countries|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
yrange.include?(year) &amp;&amp;
countries.include?(country)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PERIODS[pkey] || century</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 剩余的顾客业务（Customer 类）</P>
<p>（1） 顾客喜好排名</P>
<p>def rank(list)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
list.uniq.sort_by do |a|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
list.select {|b| a == b }.size</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end.reverse</P>
<p>end</P>
<p>&nbsp;</P>
<p>def composer_rankings</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
rank(edition_history.map {|ed| ed.composers }.flatten)</P>
<p>end</P>
<p>&nbsp;</P>
<p>def instrument_rankings</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
rank(work_history.map {|work| work.instruments }.flatten)</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）计算订购的副本的数目</P>
<p>def copies_of(edition)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
orders.find(:all, :conditions =&gt; "edition_id =
#{edition.id}").size</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）未偿余额</P>
<p>方法一：</P>
<p>def balance</P>
<p>&nbsp; acc = 0</P>
<p>&nbsp; open_orders.each do |order|</P>
<p>&nbsp;&nbsp;&nbsp; acc +=
order.edition.price</P>
<p>&nbsp; end</P>
<p>&nbsp; "%.2f" % acc</P>
<p>end</P>
<p>&nbsp;</P>
<p>方法二（递增的累计计算可以使用 inject 方法自动完成）：</P>
<p>def balance</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"%.2f" % open_orders.inject(0) do |acc,order|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
acc + order.edition.price</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>（4）顾客结帐</P>
<p>方法一：</P>
<p>def check_out</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
orders.each do |order|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
order.status = "paid"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
order.update</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>方法二：</P>
<p>def check_out</P>
<p>&nbsp; orders.each do |order|</P>
<p>&nbsp;&nbsp;&nbsp;
order.update_attribute(:status, "paid")</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>&nbsp;</P>
<h3>四、用类方法扩展模型功能</H3>
<p>1. 确定一组作品的所有版本（app/models/edition.rb）</P>
<p>def Edition.of_works(works)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
works.map {|work| work.editions }.flatten.uniq</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 获取库存作品的所有时代（app/models/work.rb）</P>
<p>def Work.all_periods</P>
<p>&nbsp; find(:all).map {|c| c.period
}.flatten.uniq.sort</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 确定作品的销售排名（app/models/work.rb）</P>
<p>def Work.sales_rankings</P>
<p>&nbsp; r = Hash.new(0)</P>
<p>&nbsp; find(:all).each do |work|</P>
<p>&nbsp;&nbsp;&nbsp;
work.editions.each do |ed|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
r[work.id] += ed.orders.size</P>
<p>&nbsp;&nbsp;&nbsp; end</P>
<p>&nbsp; end</P>
<p>&nbsp; r</P>
<p>end</P>
<p>散列是无序的，要使用这个散列，还需要对它进行排序：</P>
<p>rankings = Work.sales_rankings</P>
<p>r_sorted = rankings.sort_by {|key,value| value }</P>
<p>&nbsp;</P>
<p>4. 确定作曲者的销售排名（app/models/composer.rb）</P>
<p>def Composer.sales_rankings</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
r = Hash.new(0)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Work.sales_rankings.map do |work,sales|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; r[work.composer.id] += sales</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
r</P>
<p>end</P>
<p>&nbsp;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eskr.html#comment</comments>
            <pubDate>Thu, 27 Aug 2009 16:41:36 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eskr.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8553;&amp;#8547;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eskp.html</link>
            <description><![CDATA[<h1>第四部分 结合 Ruby 和 Rails</H1>
<h2>第十四章 再次为 R4RMusic 应用领域建模</H2>
<h3>一、跟踪 ActiveRecord 模型实例的功能</H3>
<p>1. 模型实例功能概览：Rails 模型实例的功能来源于四个地方</P>
<p>&#9632; 通过实例所属的类继承，该实例可以调用所属类的父类（即 ActiveRecord::Base
或该类的另外一个后代）的实例方法。</P>
<p>&#9632; 根据相关的数据库表的字段名自动生成的读写方法（accessor）和其它方法。举例来说，由于数据库表 composers 中有
title 字段，所以 Composer 的对象具有 title 和 title= 方法。</P>
<p>&#9632; 在使用关联指令时，半自动生成的读写方法和其它方法。例如，在 Work 类中的 has_one: composer。</P>
<p>&#9632; 通过编程添加的任意多个实例方法，它们根据需要被添加到模型定义文件中。</P>
<p>&nbsp;</P>
<p>2. 继承的和自动获得的 ActiveRecord 模型实例行为</P>
<p>（1）ActiveRecord 对象的两种存在方式</P>
<p>ActiveRecord 和典型的 Ruby 对象之间是有差别的，ActiveRecord 对象有两种存在方式：一方面，它是一个
Ruby 类。另一方面，它是一个句柄，可以用它来直接操作数据库记录。</P>
<p>&nbsp;</P>
<p>ActiveRecord 的类方法和实例方法，以及它们与对象和数据库记录的存在状态之间的关系</P>
<p>&nbsp;</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="83">
<p ALIGN="center">&nbsp;</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">new</P>
</TD>
<td WIDTH="94">
<p ALIGN="center">create</P>
<p ALIGN="center">(new+save)</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">find</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">save</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">update</P>
</TD>
<td WIDTH="104">
<p ALIGN="center">delete</P>
<p ALIGN="center">(find+destroy)</P>
</TD>
<td WIDTH="60">
<p ALIGN="center">destroy</P>
</TD>
</TR>
<tr>
<td WIDTH="568" COLSPAN="8">
<p ALIGN="left">方法调用前：</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">Ruby 对象存在吗？</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="94">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="104">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="60">
<p ALIGN="center">存在</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">数据库记录存在吗？</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="94">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="104">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="60">
<p ALIGN="center">存在</P>
</TD>
</TR>
<tr>
<td WIDTH="568" COLSPAN="8">
<p ALIGN="left">方法调用后：</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">Ruby 对象存在吗？</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="94">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="104">
<p ALIGN="center">存在</P>
<p ALIGN="center"><i>冻结</I></P>
</TD>
<td WIDTH="60">
<p ALIGN="center">存在</P>
<p ALIGN="center"><i>冻结</I></P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">数据库记录存在吗？</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="94">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="57">
<p ALIGN="center">存在</P>
</TD>
<td WIDTH="104">
<p ALIGN="center">不存在</P>
</TD>
<td WIDTH="60">
<p ALIGN="center">不存在</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>&nbsp;</P>
<p>&#9632; 方法被调用前没有对象存在的方法是类方法（可以根据没有对象实例调用它们来判断）。</P>
<p>&#9632; 冻结意味着已经通过 Ruby 的 freeze
方法将对象实例冻结。这保证对象不会再被改变，不能再给它的实例变量赋值。在销毁一个 ActiveRecord
对象后，它会被冻结。尽管可以从数据库中彻底删除记录，但是 Ruby
中没有相应的可以彻底地删除对象的操作。因此，冻结它就是最好的指示它的生命期已经结束的方法。</P>
<p>&#9632; update、delete 和 destroy 各自有一个以 _all 结尾的变体（update_all
等），它们对数据库中所有已存的记录或相应的 Ruby 实例执行给定的操作。</P>
<p>&nbsp;</P>
<p>（2）根据数据库中的字段名自动生成的方法</P>
<p>ActiveRecord 将数据库的结构和名字都映射到 Ruby 中，将表名映射为类名，字段名映射为实例方法。Rails
是一个对象关系映射系统（ORM，Object/Relational Mapping）。</P>
<p>&nbsp;</P>
<p>3. 通过关联半自动获得的行为</P>
<p>关联准确生动地描述了 Rails 实体模型之间的“有”和“属于”关系。如 Composer 类中包含 has_many
:works，以及 Work 类中包含 belongs_to :composer。</P>
<p>&nbsp;</P>
<p>我们没有定义 has_many 方法，所以它肯定是父类 ActiveRecord::Base 的类方法，其它的关联和有
belongs_to、has_one 和 has_and_belongs_to_many。</P>
<p>&nbsp;</P>
<h3>二、改进领域模型</H3>
<p>1. 从 Edition 模型中抽取出 Publisher 模型，并设置发行商和版本之间的关系</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
model publisher</P>
<p>&nbsp;</P>
<p>修改 app/models/publisher.rb 文件</P>
<p>class Publisher &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_many :editions</P>
<p>end</P>
<p>&nbsp;</P>
<p>创建 publishers 数据表结构</P>
<p>CREATE TABLE publishers (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
name VARCHAR(60),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
city VARCHAR(30),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
country CHAR(2),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p>改变后的 editions 表以及新生成的 publishers 表</P>
<p>&nbsp;</P>
<p>&nbsp;<a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static2.photo.sina.com.cn/orignal/3ecb9b11t722233169df1&amp;690" TARGET="_blank"><img SRC="http://static2.photo.sina.com.cn/bmiddle/3ecb9b11t722233169df1&amp;690" /></A></P>
<p>2. instruments 模型和多对多关系</P>
<p>（1）我们要支持按照乐器分类来浏览乐谱，因此单独创建一个乐器的数据表</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
model instrument</P>
<p>&nbsp;</P>
<p>instruments 模型有两个属性：name（乐器名，如小提琴） 和 family（乐器族，如弦乐）</P>
<p>CREATE TABLE instruments (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
name VARCHAR(20),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
family VARCHAR(15),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p>乐器和音乐之间是多对多关系：一件作品可以被多个乐器演奏，一个乐器可以演奏多个作品。</P>
<p>实现多对多关系，首先要为 Rails 提供一个记录乐器和作品关系的表，并遵循 Rails
标准为这张表命名：instruments_works。它有两个字段：一个是针对特定乐器ID字段，另一个是针对特定作品的ID字段</P>
<p>CREATE TABLE instruments_works (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
instrument_id int(11),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
work_id int(11)</P>
<p>);</P>
<p>&nbsp;</P>
<p>（2）使用 has_and_belongs_to_many 关联</P>
<p>修改 app/models/instrument.rb 中的关联指令</P>
<p>class Instrument &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_and_belongs_to_many :works</P>
<p>end</P>
<p>&nbsp;</P>
<p>添加 app/models/work.rb 中的关联指令</P>
<p>class Work &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_and_belongs_to_many :instruments</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）instrument 模型对 work 模型的影响</P>
<p>需要给 Work 模型添加基调（key）属性，但是 key 是 SQL 的关键字，所以改名为 kee。</P>
<p>还需要增加一个作品编号（opus）字段，现在 works 表的 SQL 如下</P>
<p>CREATE TABLE works (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
composer_id INT(11),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
title VARCHAR(100),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
year INT(4),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
kee CHAR(9),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
opus VARCHAR(20),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p>（4）editions 到 works 的多对多映射</P>
<p>一件作品可以出现在多个版本中，一个版本可以包含多件作品。首先把 work_id 从 editions
表中删除，然后增加一个用于保存 works 和 editions 关系的表</P>
<p>CREATE TABLE editions_works (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
edition_id int(11),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
work_id int(11)</P>
<p>);</P>
<p>&nbsp;</P>
<p>修改 ActiveRecord，修改 edition.rb 中的 belongs_to :work</P>
<p>has_and_belongs_to_many :works</P>
<p>&nbsp;</P>
<p>在 work.rb 中加入下面代码（:order 告诉 ActiveRecord 把返回的版本按年份升序排序）</P>
<p>has_and_belongs_to_many :editions,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:order =&gt; "year ASC"</P>
<p>&nbsp;</P>
<p>3. 创建顾客和订单模型</P>
<p>（1）我们将让顾客做下面这些事：</P>
<p>&#9632; 注册</P>
<p>&#9632; 登录</P>
<p>&#9632; 选择商品并将其放入购物车中</P>
<p>&#9632; 结帐（购买商品）</P>
<p>&nbsp;</P>
<p>在 Rails 方面，需要为 customer 模型生成模型和控制器</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
model customer</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
controller customer</P>
<p>&nbsp;</P>
<p>在数据库方面，创建顾客模型的 SQL 表结构</P>
<p>CREATE TABLE customers (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
first_name VARCHAR(30),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
last_name VARCHAR(30),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nick VARCHAR(15),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
password VARCHAR(40),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
email VARCHAR(50),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p>（2）创建定单模型</P>
<p>F:\ruby_project\R4Rmusic&gt;ruby script/generate
model order</P>
<p>为记录订单时间，orders 表有一个名为 created_at 字段。该字段名在 Rails 中是一个特殊的字段名：在保存
Order 对象时，Rails 自动将保存操作发生的时间和日期。Order 模型中还包含一个 status
字段，如果订单已经付过款，该字段设置为“paid”，如果订单商品已经发出，则设置为“shipped”</P>
<p>CREATE TABLE orders (</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
edition_id INT(11),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
customer_id INT(11),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
status CHAR(4),</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
created_at DATETIME,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p>（3）建立 orders 与 customers 和 editions 的关联</P>
<p>修改 app/models/orders.rb 文件</P>
<p>class Order &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
belongs_to :customer</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
belongs_to :edition</P>
<p>end</P>
<p>&nbsp;</P>
<p>修改 app/models/customer.rb
文件，并创建依赖关系：如果顾客记录不存在，那么他的订单也随之删除，一旦所属的记录被删除，这些无主记录就没有用了。</P>
<p>class Customer &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_many :orders,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:dependent
=&gt; true,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:order&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "created_at ASC"</P>
<p>end</P>
<p>&nbsp;</P>
<p>最后在 edition 模型中，也要为 orders 添加一个关联</P>
<p>class Edition &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_many :orders</P>
<p>end</P>
<p>&nbsp;</P>
<p>4. 为订单设置默认状态</P>
<p>在 Order 类中定义 before_create 方法，在每次保存新模型实例时，自动调用该方法</P>
<p>def before_create</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self.status = "open"</P>
<p>end</P>
<p>&nbsp;</P>
<p>5. 图示新的领域模型</P>
<p>&nbsp;</P>
<p><a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static14.photo.sina.com.cn/orignal/3ecb9b11t722230795b7d&amp;690" TARGET="_blank"><img SRC="http://static14.photo.sina.com.cn/bmiddle/3ecb9b11t722230795b7d&amp;690" /></A></P>
<p>&nbsp;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eskp.html#comment</comments>
            <pubDate>Thu, 27 Aug 2009 16:37:04 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eskp.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8553;&amp;#8546;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100esko.html</link>
            <description><![CDATA[<h2>第十三章 Ruby 动态特性</H2>
<h3>一、单例类的位置和角色</H3>
<p>1. 单例方法在何处定义</P>
<p>对象的单例方法定义在对象单例类中。每个对象实际上有两个类：</P>
<p>&#9632; 多个对象实例共享的类</P>
<p>&#9632; 单例类</P>
<p>可以将某个对象的单例类看作是它独有的方法保护区，仅属于该对象，其它对象不能分享</P>
<p>obj = Object.new</P>
<p>def obj.talk</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Hi!"</P>
<p>end</P>
<p>obj.talk</P>
<p>&nbsp;</P>
<p>2. 直接检查和修改单例类</P>
<p>单例类是匿名的，可以使用 class 关键字的一个特殊形式来完成，class 后面跟一个常量</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# method and constant definitions here</P>
<p>end</P>
<p>&nbsp;</P>
<p>使用以下面特殊记法来打开单例类的定义体</P>
<p>str = "I am a string"</P>
<p>class &lt;&lt; str</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def twice</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self + " " + self</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>puts str.twice</P>
<p>&nbsp;</P>
<p>或者可以这样定义</P>
<p>def str.twice</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self + " " + self</P>
<p>end</P>
<p>&nbsp;</P>
<p>使用 class &lt;&lt; 定义类方法</P>
<p>class Ticket</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
class &lt;&lt; self</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def most_expensive(tickets)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# etc.</P>
<p>&nbsp;</P>
<p>4. 方法查找路径上的单例类</P>
<p>（1）方法查找的顺序（包含单例类）</P>
<p>&nbsp;</P>
<p>&nbsp;<a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static14.photo.sina.com.cn/orignal/3ecb9b11t72222477d81d&amp;690" TARGET="_blank"><img SRC="http://static14.photo.sina.com.cn/bmiddle/3ecb9b11t72222477d81d&amp;690" /></A></P>
<p>&nbsp;</P>
<p>（2）可以在单例类中混含模块</P>
<p>class C</P>
<p>end</P>
<p>&nbsp;</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def talk</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Hello."</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>obj = C.new</P>
<p>class &lt;&lt; obj</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>end</P>
<p>obj.talk</P>
<p>&nbsp;</P>
<p>第二种方法是使用 extend 进行扩展</P>
<p>obj = C.new</P>
<p>obj.extend(M)</P>
<p>obj.talk</P>
<p>&nbsp;</P>
<p>（3）在单例类中混含模块与在对象所属类中混含模块</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def talk</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Hi from original class!"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def talk</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Hello from module!"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new</P>
<p>c.talk # <b>输出：Hi from original class!</B></P>
<p>class &lt;&lt; c</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>end</P>
<p>c.talk # <b>输出：Hello from module!</B></P>
<p>&nbsp;</P>
<p>通过使用 ancestors 方法，可以清楚地看到任意类或模块的继承／混含层级结构</P>
<p>c = C.new</P>
<p>class &lt;&lt; c</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
p ancestors</P>
<p>end</P>
<p>输出结果为</P>
<p>[M, C, Object, Kernel]</P>
<p>&nbsp;</P>
<p>5. 更深入地学习类方法</P>
<p>class C</P>
<p>end</P>
<p>&nbsp;</P>
<p>def C.a_class_method</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Singleton method defined on C"</P>
<p>end</P>
<p>&nbsp;</P>
<p>class D &lt; C</P>
<p>end</P>
<p>&nbsp;</P>
<p>D.a_class_method # <b>输出：Singleton method defined on C</B></P>
<p>&nbsp;</P>
<h3>二、  方法族</H3>
<p>1.  执行字符串</P>
<p>&gt;&gt; ("2+2")</P>
<p>=&gt; 4</P>
<p>&nbsp;</P>
<p>编写一个可以让别人在运行时键入其方法名的方法</P>
<p>print "Method name: "</P>
<p>m = gets.chomp</P>
<p>("def #{m}; puts 'Hi!'; end")</P>
<p>(m)</P>
<p>&nbsp;</P>
<p> 的危险性：从来没有用过、将来也不打算使用  的有经验的、专家级的 Ruby 程序员并不少见。</P>
<p>&nbsp;</P>
<p>2. instance_：该方法将 self 变为 instance_ 调用的接收者</P>
<p>p self # <b>输出：main</B></P>
<p>a = []</P>
<p>a.instance_ { p self } # <b>输出：[]</B></P>
<p>&nbsp;</P>
<p>instance_ 常用于访问其它对象的私有数据——特别是实例变量</P>
<p>class C</P>
<p>&nbsp; def initialize</P>
<p>&nbsp;&nbsp;&nbsp; @x =
1</P>
<p>&nbsp; end</P>
<p>end</P>
<p>c = C.new</P>
<p>c.instance_ { puts @x }</P>
<p>&nbsp;</P>
<p>3. 最有用的  族方法：class_</P>
<p>（1）class_ （即module_）可以进入类定义体中</P>
<p>C = Class.new</P>
<p>C.class_ do</P>
<p>&nbsp; def some_method</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Created in class_"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>c = C.new</P>
<p>c.some_method</P>
<p>&nbsp;</P>
<p>（2）将外围作用的局部变量提供给 class_ 代码块</P>
<p>&gt;&gt; var = "initialized
variable"</P>
<p>=&gt; "initialized variable"</P>
<p>&gt;&gt; class C</P>
<p>&gt;&gt; puts var</P>
<p>&gt;&gt; end</P>
<p>NameError: undefined local variable or method `var' for
C:Class</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
from (irb):3</P>
<p>&gt;&gt; C.class_ { puts var }</P>
<p>initialized variable</P>
<p>&nbsp;</P>
<p>（3）如果想把外部作用域的变量硬塞到实例方法中，可以使用另外一种技术来生成方法</P>
<p>&gt;&gt; C.class_ {
<b>define_method("talk")</B> { puts var }&nbsp; }</P>
<p>=&gt;
#&lt;Proc:0x003452f4@(irb):8&gt;</P>
<p>&nbsp;</P>
<h3>三、可调对象</H3>
<p>1. Proc 对象</P>
<p>（1）用一个代码块来实例化 Proc 类，可以产生一个 Proc 对象</P>
<p>pr = Proc.new { puts "Inside a Proc's block" }</P>
<p>&nbsp;</P>
<p>执行该代码块（Proc 对象）需要显式地调用</P>
<p>pr.call # <b>输出：Inside a Proc's block</B></P>
<p>&nbsp;</P>
<p>2. 作为闭包的 Proc 对象</P>
<p>def call_some_proc(pr)</P>
<p>&nbsp; a = "irrelevant 'a' in method scope"</P>
<p>&nbsp; puts a</P>
<p>&nbsp; pr.call</P>
<p>end</P>
<p>a = "'a' to be used in Proc block"</P>
<p>pr = Proc.new { puts a }</P>
<p>pr.call</P>
<p>call_some_proc(pr)</P>
<p>输出结果（Proc 对象随身携带了它的上下文，称为闭包）</P>
<p>'a' to be used in Proc block</P>
<p>irrelevant 'a' in method scope</P>
<p>'a' to be used in Proc block</P>
<p>&nbsp;</P>
<p>3. Proc 对象的参数</P>
<p>（1）传递和接收参数</P>
<p>pr = Proc.new {|x| puts "Called with argument #{x}" }</P>
<p>pr.call(100) # <b>输出: Called with argument 100</B></P>
<p>&nbsp;</P>
<p>（2）多个参数的调用</P>
<p>&gt;&gt; pr = Proc.new {|x,y,z| p x,y,z
}</P>
<p>=&gt;
#&lt;Proc:0x001b5598@(irb):1&gt;</P>
<p>&gt;&gt; pr.call(1,2)</P>
<p>1</P>
<p>2</P>
<p>nil</P>
<p>&nbsp;</P>
<p>&gt;&gt; pr.call(1,2,3,4)</P>
<p>1</P>
<p>2</P>
<p>3</P>
<p>&nbsp;</P>
<p>（3）使用星号操作符（*）将所有的参数合并为一个参数（参数变量 x 被设置为一个数组）</P>
<p>pr = Proc.new {|*x| p x }</P>
<p>pr.call</P>
<p>pr.call(1)</P>
<p>pr.call(1,2)</P>
<p>这段代码的输出</P>
<p>[]</P>
<p>[1]</P>
<p>[1, 2]</P>
<p>&nbsp;</P>
<p>让 Proc 对象接受多个参数，而且最后一个参数具有合并多个参数的能力</P>
<p>pr = Proc.new {|x,*y| p x, y }</P>
<p>pr.call(1,2,3)</P>
<p>输出为</P>
<p>1</P>
<p>[2, 3]</P>
<p>&nbsp;</P>
<p>4. 用 lambda 关键字生成匿名函数</P>
<p>（1）lambda 关键字可以用来生成匿名函数，然后可以给它发送“call”消息执行函数</P>
<p>&gt;&gt; lam = lambda { puts "A lambda!"
}</P>
<p>=&gt;
#&lt;Proc:0x00330cb4@(irb):31&gt;</P>
<p>&gt;&gt; lam.call</P>
<p>A lambda!</P>
<p>正如我们所看到的，lambda 不是 Lambda 类的对象，它们是 Proc 类的对象</P>
<p>&gt;&gt; lam.class</P>
<p>=&gt; Proc</P>
<p>和所有的 Proc 对象一样，lambda 都是闭包。</P>
<p>&nbsp;</P>
<p>（2）lambda 和 Proc 对象的差别与 return 关键字有关</P>
<p>def return_test</P>
<p>&nbsp; l = lambda { return }</P>
<p>&nbsp; l.call</P>
<p>&nbsp; puts "Still here!"</P>
<p>&nbsp; p = Proc.new { return }</P>
<p>&nbsp; p.call # 跳出方法体</P>
<p>&nbsp; puts "You won't see this message!"</P>
<p>end</P>
<p>return_test</P>
<p>此例可见，lambda 中的 return 从 lambda 返回，而 Proc 中的 return 从外围方法返回</P>
<p>&nbsp;</P>
<p>5. 再论代码块</P>
<p>可以在方法中将代码块转换成 Proc 对象，通过一个变量捕获代码块，该变量是方法参数列表中的一个参数变量，它的名字必须以
&amp; 开头</P>
<p>def grab_block(&amp;block)</P>
<p>&nbsp; block.call</P>
<p>end</P>
<p>grab_block { puts "This block will end up in the variable
'block'" }</P>
<p>&nbsp;</P>
<p>&amp;block 变量必须是参数列表中的最后一项</P>
<p>def grab_block(x,y,*z,&amp;block)</P>
<p>&nbsp;</P>
<p>可以反过来将 Proc 对象或 lambda 转换为一个代码块，使用 &amp; 可以达到此目的</P>
<p>lam = lambda { puts "This lambda will serve as a code block"
}</P>
<p>grab_block &amp;lam</P>
<p>&nbsp;</P>
<p>下面是另一种方式</P>
<p>grab_block &amp;lambda { puts "This lambda will
serve as a code block" }</P>
<p>&nbsp;</P>
<p>6. 作为对象的方法</P>
<p>通过 method 方法，并以方法名作为参数，就可以得到一个方法对象</P>
<p>class C</P>
<p>&nbsp; def talk</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Method-grabbing test!&nbsp; self is #{self}."</P>
<p>&nbsp; end</P>
<p>end</P>
<p>c = C.new</P>
<p>meth = c.method(:talk)</P>
<p>调用它自己</P>
<p>meth.call # <b>输出：Method-grabbing test!&nbsp; self
is #&lt;C:0x353854&gt;</B></P>
<p>&nbsp;</P>
<p>可以将方法和它所绑定的对象解绑定(unbind)，然后再将它绑定到另一个对象上（bind）</P>
<p>class D &lt; C</P>
<p>end</P>
<p>&nbsp;</P>
<p>d = D.new</P>
<p>unbound = meth.unbind</P>
<p>unbound.bind(d).call</P>
<p>&nbsp;</P>
<p>如果想直接得到解绑定的方法对象，而本想通过已绑定的方法使用 unbind 来得到方法对象，则可以使用
instance_method 方法</P>
<p>unbound = C.instance_method(:talk)</P>
<p>&nbsp;</P>
<p>绑定和解绑定技术的使用范例</P>
<p>class A</P>
<p>&nbsp; def a_method</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Definition in class A"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>class B &lt; A</P>
<p>&nbsp; def a_method</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Definition in class B (subclass of A)"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>class C &lt; B</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new</P>
<p>c.a_method # <b>输出：Definition in class B (subclass of A)</B></P>
<p>默认情况下，实例会执行它在方法查找路径上找到的第一个匹配的方法；</P>
<p>&nbsp;</P>
<p>有没有办法让最底层的类实例，在接收到消息“a_method”时执行该方法</P>
<p>A.instance_method(:a_method).bind(c).call # <b>输出：Definition in
class A</B></P>
<p>&nbsp;</P>
<p>可以将此行为放在类 C 的一个方法中</P>
<p>class C</P>
<p>&nbsp; def call_original</P>
<p>&nbsp;&nbsp;&nbsp;
A.instance_method(:a_method).bind(self).call</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>四、回调方法和钩子方法</H3>
<p>1. 用 method_missing 拦截不能识别的消息</P>
<p>method 是一张安全网：提供了拦截不可响应的消息并对其进行适当处理的办法</P>
<p>class C</P>
<p>&nbsp; def method_missing(m)</P>
<p>&nbsp;&nbsp;&nbsp; puts
"There's no method called #{m} here -- please try again."</P>
<p>&nbsp; end</P>
<p>end</P>
<p>C.new.anything</P>
<p>&nbsp;</P>
<p>2. 用 Module#included 捕捉混含操作</P>
<p>module M</P>
<p>&nbsp; def self.included(c)</P>
<p>&nbsp;&nbsp;&nbsp; puts "I
have just been mixed into #{c}."</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>class C</P>
<p>&nbsp; include M</P>
<p>end</P>
<p>当 M 被混含到 C 中时，消息“I have just been mixed into C.”</P>
<p>&nbsp;</P>
<p>3. 用 Class#inherited 拦截继承</P>
<p>class C</P>
<p>&nbsp; def self.inherited(subclass)</P>
<p>&nbsp;&nbsp;&nbsp; puts
"#{self} just got subclassed by #{subclass}"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>class D &lt; C</P>
<p>end</P>
<p>当 D 继承 C 时自动触发对 inherited 的调用，因此该代码产生下面的输出</P>
<p>C just got subclassed by D</P>
<p>&nbsp;</P>
<p>4. 用 Module#const_missing 拦截引用不可识别的常量</P>
<p>class C</P>
<p>&nbsp; def self.const_missing(const)</P>
<p>&nbsp;&nbsp;&nbsp; puts
"#{const} is undefined—setting it to 1."</P>
<p>&nbsp;&nbsp;&nbsp;
const_set(const,1) ＃ 如果常量不存在，则将它设置为系统常量</P>
<p>&nbsp; end</P>
<p>end</P>
<p>puts C::A</P>
<p>puts C::A</P>
<p>&nbsp;</P>
<p>a is undefined—setting it to 1.</P>
<p>1</P>
<p>1</P>
<p>&nbsp;</P>
<h3>五、覆盖和增加核心功能</H3>
<p>Ruby
最强大的特性之一是可以修改和增强语言核心功能。可以像打开你自己的类那样，很容易地打开和修改核心类。可以按照自己的意愿为它添加方法或覆盖旧的方法。</P>
<p>&nbsp;</P>
<p>但是，当你在自己的程序中对 Ruby
核心做出改变时，必须非常非常小心，。如果编写提供给别人使用的代码库，而库中包含了改变核心类和对象的代码，那么对每个使用你的代码人来说，你修改了游戏规则。</P>
<p>&nbsp;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100esko.html#comment</comments>
            <pubDate>Thu, 27 Aug 2009 16:32:47 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100esko.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8555;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eskn.html</link>
            <description><![CDATA[<h2>第十二章 正则表达式和基于它的字符串操作</H2>
<h3>一、什么是正则表达式</H3>
<p>正则表达式可用于：在字符串中扫描某个模式的多次出现，进行字符串替换操作，基于匹配分界符将一个字符串分割为多个子字符串。</P>
<p>&nbsp;</P>
<h3>二、编写正则表达式</H3>
<p>1. 正则表达式的字面构造方法</P>
<p>（1）字面构造方法就是一对正斜杠：//</P>
<p>（2）可以从两个方向使用 match：正则表达式对象和字符串对象都可以响应 match方法</P>
<p>puts "Match!" if /abc/.match("The alphabet starts with
abc.")</P>
<p>puts "Match!" if "The alphabet starts with
abc.".match(/abc/)</P>
<p>&nbsp;</P>
<p>Ruby 还提供了模式匹配操作符 =~（等号加波浪号）</P>
<p>puts "Match!" if /abc/ =~ "The alphabet starts with abc."</P>
<p>puts "Match!" if "The alphabet starts with abc." =~ /abc/</P>
<p>&nbsp;</P>
<p>（3）match 与 =~ 的主要不同之处在于匹配时的返回值不同：</P>
<p>=~ 返回匹配开始处的字符在字符串中的数值索引，而 match 返回 MatchData 类的实例</P>
<p>&gt;&gt; "The alphabet starts with abc"
=~ /abc/</P>
<p>=&gt; 25</P>
<p>&gt;&gt; /abc/.match("The alphabet
starts with abc.")</P>
<p>=&gt;
#&lt;MatchData:0x1b0d88&gt;</P>
<p>&nbsp;</P>
<p>2. 构造一个模式</P>
<p>（1）可以来构造正则表达式的组件包括以下几个：</P>
<p>&#9632; 字面字符，表示“与该字符匹配”</P>
<p>&#9632; 圆点通配符（.），表示“与任意一个字符匹配”</P>
<p>&#9632; 字符类，表示“与这些字符中的某一个匹配”</P>
<p>&nbsp;</P>
<p>（2）特殊字符</P>
<p>对于有特殊意义的字符来说，要匹配这些特殊字符本身，需要使用反斜杠（\）来对它们进行转义：^, $, ? , ., /, \,
[, ], {, }, (, ), +, *</P>
<p>&nbsp;</P>
<p>（3）通配字符.（圆点）：匹配除换行以外的任意一个的字符</P>
<p>&nbsp;</P>
<p>（4）字符集：/[dr]ejected/ 匹配 d 或 r，其后接 ejected</P>
<p>在字符集中可以插入字符范围：/[a-z]/</P>
<p>为了与一个十六进制数字匹配，需要在字符集中使用多个字符范围：/[A-Fa-f0-9]/</P>
<p>非十六进制数字匹配的字符集，使用补集：/[^A-Fa-f0-9]/</P>
<p>&nbsp;</P>
<p>（5）常见字符集的特殊转义序列</P>
<p>\d 与任何数字相匹配</P>
<p>\w 与任何数字、字母或下划线相匹配</P>
<p>\s 与任何空白字符（空格、制表符、换行符）相匹配</P>
<p>&nbsp;</P>
<p>这些预定义字符集每一个都有一个补集</P>
<p>\D 与任何一个非数字相匹配</P>
<p>\W 与任何数字、字母或下划线之外的任何一个相匹配</P>
<p>\S 与任何一个非空白字符相匹配</P>
<p>&nbsp;</P>
<h3>三、关于匹配和 MatchData 的更多内容</H3>
<p>1.
正则表达式构造的最重要技术之一是使用小括号来指定“捕获”，为了对字符串的某部分做些处理，捕获记法可以分离出与特定的子模式匹配的字符串并保存</P>
<p>str = "Peel,Emma,Mrs.,talented amateur"</P>
<p>/([A-Za-z]+),[A-Za-z]+,(Mrs?\.)/.match(str)</P>
<p>puts $1 # <b>输出：Peel</B></P>
<p>puts $2 # <b>输出：Mrs.</B></P>
<p>Ruby 自动填写了这些变量为全局变量，它们以数字作为名字：$1, $2 等等。</P>
<p>&nbsp;</P>
<p>2. 匹配成功和匹配失败</P>
<p>（1）匹配一个电话号码并查询作为结果的 MatchData 对象</P>
<p>string = "My phone number is (123) 555-1234."</P>
<p>phone_re = /\((\d{3})\)\s+(\d{3})-(\d{4})/</P>
<p>m = phone_re.match(string)</P>
<p>unless m</P>
<p>&nbsp; puts "There was no match--sorry."</P>
<p>&nbsp; exit</P>
<p>end</P>
<p>print "The whole string we started with: "</P>
<p>puts m.string</P>
<p>print "The entire part of the string that matched: "</P>
<p>puts m[0]</P>
<p>puts "The three captures: "</P>
<p>3.times do |index|</P>
<p>&nbsp; puts "Capture ##{index + 1}:
#{m.captures[index]}"</P>
<p>end</P>
<p>puts "Here's another way to get at the first capture:"</P>
<p>print "Capture #1: "</P>
<p>puts m[1]</P>
<p>下面是代码输出结果</P>
<p>The whole string we started with: My phone number is (123)
555-1234.</P>
<p>The entire part of the string that matched: (123) 555-1234</P>
<p>The three captures:</P>
<p>Capture #1: 123</P>
<p>Capture #2: 555</P>
<p>Capture #3: 1234</P>
<p>Here's another way to get at the first capture:</P>
<p>Capture #1: 123</P>
<p>&nbsp;</P>
<p>（2）获取子匹配的两种方法</P>
<p>从 MatchData 对象中获取子匹配的一种方式是直接索引对象，就像数组那样</P>
<p>完整匹配：m[0]</P>
<p>第一个捕获：m[1]</P>
<p>第二个捕获：m[2]</P>
<p>从 1 开始的这些索引值对应于包含捕获的子字符串的全局变量 $n 中的 n。</P>
<p>MathData 对象还有一个名为 captures 的方法，并且以下等式成立</P>
<p>m[1] == m.captures[0]</P>
<p>m[2] == m.captures[1]</P>
<p>&nbsp;</P>
<p>（3）MatchData 的其它信息（电话号码匹配操作的补充代码）</P>
<p>print "The part of the string before the part that matched
was:"</P>
<p>puts m.pre_match</P>
<p>print "The part of the string after the part that matched
was:"</P>
<p>puts m.post_match</P>
<p>print "The second capture began at character "</P>
<p>puts m.begin(2)</P>
<p>print "The third capture ended at character "</P>
<p>puts m.end(3)</P>
<p>这段代码的输出如下</P>
<p>The string up to the part that matched was: My phone number
is</P>
<p>The string after the part that matched was: .</P>
<p>The second capture began at character 25</P>
<p>The third capture ended at character 33</P>
<p>&nbsp;</P>
<h3>四、更多正则表达式技术</H3>
<p>1. 量词和贪婪性</P>
<p>（1）表示“0个或1个”的特殊字符：问号（?）</P>
<p>/Mrs?\.?/ 它将匹配 ”Mr”, “Mrs”, “Mr.”, “Mrs.”</P>
<p>&nbsp;</P>
<p>（2）表示“0个或多个”的特殊字符：星号（*）</P>
<p>&lt;/p&gt;</P>
<p>&lt; /p&gt;</P>
<p>
&lt;/&nbsp;&nbsp;&nbsp;
p&gt;</P>
<p>&lt;/p</P>
<p>&gt;&nbsp;</P>
<p>要匹配 HTML 文档中的闭标签
&lt;/p&gt;：/&lt;\s*\/\s*p\s*&gt;/</P>
<p>&nbsp;</P>
<p>（3）表示“1个或多个”的特殊字符：加号（+）</P>
<p>/\d+/ 匹配一个或多个连续的数字构成的任意序列</P>
<p>&nbsp;</P>
<p>（4）贪婪量词和不贪婪量词</P>
<p>量词 * （0个或多个）和 + （1个或多个）是贪婪的：它们会匹配尽可能多的字符</P>
<p>string = "abc!def!ghi!"</P>
<p>match = /.+!/.match(string)</P>
<p>puts match[0] # <b>输出：abc!def!ghi!</B></P>
<p>&nbsp;</P>
<p>可以通过在后面放置一个问号，使它们成为不贪婪量词</P>
<p>string = "abc!def!ghi!"</P>
<p>match = /.+?!/.match(string)</P>
<p>puts match[0] # <b>输出：abc!</B></P>
<p>&nbsp;</P>
<p>（5）特定次数的重复</P>
<p>通过将一个数放在大括号 {} 中来达到此目的</P>
<p>/\d{3}-\d{4}/ 将匹配 555-1212</P>
<p>&nbsp;</P>
<p>也可以指定一个范围，如 1～10个连续数字的任意字符</P>
<p>/\d{1,10}/</P>
<p>&nbsp;</P>
<p>如果要匹配“三次或更多的数字”可以使用</P>
<p>/\d{3,}/</P>
<p>&nbsp;</P>
<p>匹配五次连续出现“一个大写字母和一个数字”的模式</P>
<p>/([A-Z]\d){5}/</P>
<p>&nbsp;</P>
<p>2. 锚和前视断言</P>
<p>（1）最常见的锚是行首（^）和行尾（$）</P>
<p>要确定哪些行是注释行，可以使用下面的正则表达式：/^\s*#/</P>
<p>&nbsp;</P>
<p>（2）正则表达式的锚</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="64">
<p ALIGN="center"><strong>记法</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="170">
<p ALIGN="center"><strong>描述</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="132">
<p ALIGN="center"><strong>示例</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="202">
<p ALIGN="center"><strong>匹配的字符串示例</STRONG></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="64">
<p>^</P>
<p>$</P>
<p>\A</P>
<p>\z</P>
<p>\Z</P>
<p>\b</P>
</TD>
<td VALIGN="top" WIDTH="170">
<p>行首</P>
<p>行尾</P>
<p>字符串的开始</P>
<p>字符串的结尾</P>
<p>字符串的结尾（不含换行）</P>
<p>单词边界</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>/^\s*#/</P>
<p>/\.$/</P>
<p>/\AFour score/</P>
<p>/from the arth.\z/</P>
<p>/from the arth.\Z/</P>
<p>/\b\w+\b/</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>“&nbsp; # A Ruby comment line”</P>
<p>“one\ntwo\nthree.\nfour”</P>
<p>“Four score”</P>
<p>“from the earth.”</P>
<p>“from the earth\n”</P>
<p>“!!!word***”(匹配 word )</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>（3）前视断言</P>
<p>假设要匹配一个数的序列，该序列以一个圆点结束。但是并不想把这个圆点本身作为匹配的一部分。实现该功能可以使用前视断言</P>
<p>str = "123 456. 789"</P>
<p>m = /\d+(?=\.)/.match(str)</P>
<p>现在 m[0] 是 “456”：字符串中其后面紧跟着一个圆点的那个数序列。</P>
<p>&nbsp;</P>
<p>下面是对其中一些术语的解释：</P>
<p>&#9632; 零宽度（zero-width）：该断言不会消耗字符串的任何字符。如果是模式继续的话，还可以对圆点进行匹配。</P>
<p>&#9632; 肯定的（positive）意味着想要规定圆点存在（?=…），否定的前视断言（?!...）。</P>
<p>&#9632; 前视断言（lookahead assertion）表示想要知道下一个指定的是什么，但并不匹配。</P>
<p>&nbsp;</P>
<p>3. 修饰语：在正则表达式最后加入一个字母：/abc/i</P>
<p>修饰语 i 使该正则表达式的匹配操作是大小写不敏感的。</P>
<p>修饰语 m 使圆点通配符可以与任何字符相匹配，包括换行符。</P>
<p>str = "This (including\nwhat's in parens\n) takes up three
lines."</P>
<p>m = /\(.*?\)/m.match(str)</P>
<p>匹配结果为</P>
<p>(including</P>
<p>what's in parens</P>
<p>)</P>
<p>&nbsp;</P>
<p>4. 字符串与正则表达式之间的转换</P>
<p>&gt;&gt; str = "def"</P>
<p>=&gt; "def"</P>
<p>&gt;&gt; /abc#{str}/</P>
<p>=&gt; /abcdef/</P>
<p>&nbsp;</P>
<p>在把字符串放入正则表达式之前，可以转义字符串中的特殊字符</P>
<p>&gt;&gt; Regexp.escape("a.c")</P>
<p>=&gt; "a\.c"</P>
<p>&gt;&gt; Regexp.escape("^abc")</P>
<p>=&gt; "\^abc"</P>
<p>&nbsp;</P>
<p>将正则表达式转换成字符串：str = /abc/.inspect</P>
<p>&nbsp;</P>
<h3>五、使用正则表达式的常见方法</H3>
<p>1. 要从一个字符串数组中找出所有至少有10个字符而且其中至少有一个数字的字符串：</P>
<p>array.find_all {|e| e.size &gt; 10 and /\d/.match(e)
}</P>
<p>&nbsp;</P>
<p>2. String#scan</P>
<p>scan 方法扫描一个字符串，重复地进行测试以寻找指定模式的各个匹配，结果返回到一个数组中</P>
<p>&gt;&gt; "testing 1 2 3 testing 4 5
6".scan(/\d/)</P>
<p>=&gt; ["1", "2", "3", "4", "5", "6"]</P>
<p>&nbsp;</P>
<p>如果在传递给 scan 的正则表达式中使用了小括号分组，它会返回一个数组的数组</P>
<p>&gt;&gt; str = "Leopold Auer was the
teacher of Jascha Heifetz."</P>
<p>=&gt; "Leopold Auer was the teacher of Jascha
Heifetz."</P>
<p>&gt;&gt; violinists =
str.scan(/([A-Z]\w+)\s+([A-Z]\w+)/)</P>
<p>=&gt; [["Leopold", "Auer"], ["Jascha",
"Heifetz"]]</P>
<p>&nbsp;</P>
<p>3. String#split</P>
<p>split 方法会将一个字符串分割为几个子字符串</P>
<p>line = "first_name=david;last_name=black;country=usa"</P>
<p>record = line.split(/=|;/)</P>
<p>&nbsp;</P>
<p>4. sub/sub! 和 gsub/gsub!</P>
<p>gsub（全局替代）：会遍历整个字符串进行修改；</P>
<p>sub：最多只进行一次替代；</P>
<p>&nbsp;</P>
<p>（1）sub 接受两个参数，一个正则表达式（或者字符串）和一个替代字符串</P>
<p>&gt;&gt; "typigraphical
error".sub(/i/,"o")</P>
<p>=&gt; "typographical error"</P>
<p>&nbsp;</P>
<p>可以使用代码块来取代替代字符串参数</P>
<p>&gt;&gt; "capitalize the first
vowel".sub(/[aeiou]/) {|s| s.upcase }</P>
<p>=&gt; "cApitalize the first vowel"</P>
<p>&nbsp;</P>
<p>（2）gsub ，与 sub 类似，只要字符串的剩余部分还能够与模式匹配就会继续替代</P>
<p>&gt;&gt; "capitalize every
word".gsub(/\b\w/) {|s| s.upcase }</P>
<p>=&gt; "Capitalize Every Word"</P>
<p>&nbsp;</P>
<p>（3）在替代字符串中使用子匹配</P>
<p>要修正小写字母后面跟着大写字母这样的错误，可以这样做：</P>
<p>&gt;&gt; "aDvid".sub(/([a-z])([A-Z])/,
'\2\1')</P>
<p>=&gt; "David"</P>
<p>&nbsp;</P>
<p>如果想将字符串的每一个单词都重复一遍，可以这样写</P>
<p>&gt;&gt; "double every
word".gsub(/\b(\w+)/, '\1 \1')</P>
<p>=&gt; "double double every every word word"</P>
<p>&nbsp;</P>
<p>5. grep：直接基于正则表达式参数进行选择操作</P>
<p>&gt;&gt; ["USA", "UK", "France",
"Germany"].grep(/[a-z]/)</P>
<p>=&gt; ["France", "Germany"]</P>
<p>&nbsp;</P>
<p>实际上可以使用 select 完成同样的事</P>
<p>["USA", "UK", "France", "Germany"].select {|c| /[a-z]/.match(c)
}</P>
<p>&nbsp;</P>
<p>选择一些国家后，将它们转换成大写并放到一个数组中返回</P>
<p>&gt;&gt; ["USA", "UK", "France",
"Germany"].grep(/[a-z]/) {|c| c.upcase }</P>
<p>=&gt; ["FRANCE", "GERMANY"]</P>
<p>&nbsp;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eskn.html#comment</comments>
            <pubDate>Thu, 27 Aug 2009 16:27:07 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eskn.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8554;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100ergw.html</link>
            <description><![CDATA[<h2>第十一章 集合、容器和可枚举性</H2>
<h3>一、数组和散列的比较</H3>
<p>数组是有序的对象集合，有序意味着可以基于连续的数字索引从集合中选择对象。</P>
<p>
散列是无序的集合，这意味着不能说第一／第二个或第N个元素是什么。散列将对象以成对的方法存储起来，每一对有一个键和一个值，通过键来索引值。散列在其它语言中有时也叫字典或联合数组。</P>
<p>&nbsp;</P>
<h3>二、使用数组</H3>
<p>1. 创建一个新数组</P>
<p>a = Array.new</P>
<p>a = []</P>
<p>a = [1,2,"three",4, [] ]</P>
<p>&nbsp;</P>
<p>用 Array.new 的好处是，允许指定数组的大小，并可对其内容进行初始化</P>
<p>&gt;&gt; Array.new(3)</P>
<p>=&gt; [nil, nil, nil]</P>
<p>&gt;&gt; Array.new(3,"abc")</P>
<p>=&gt; ["abc", "abc", "abc"]</P>
<p>&nbsp;</P>
<p>甚至可以为 Array.new 提供代码块</P>
<p>&gt;&gt; n = 0</P>
<p>=&gt; 0</P>
<p>&gt;&gt; Array.new(3) { n += 1; n * 10
}</P>
<p>=&gt; [10, 20, 30]</P>
<p>&nbsp;</P>
<p>2. 插入、检索和删除数组元素</P>
<p>（1）一次读写多个数组元素</P>
<p>&gt;&gt; a =
["red","orange","yellow","purple","gray","indigo","violet"]</P>
<p>=&gt; ["red", "orange", "yellow", "purple", "gray",
"indigo", "violet"]</P>
<p>&gt;&gt; a[3,2]</P>
<p>=&gt; ["purple", "gray"]</P>
<p>&gt;&gt; a[3,2] = "green", "blue"</P>
<p>=&gt; ["green", "blue"]</P>
<p>&gt;&gt; a</P>
<p>=&gt; ["red", "orange", "yellow", "green", "blue",
"indigo", "violet"]</P>
<p>&nbsp;</P>
<p>（2）对数组头或尾进行操作的特殊方法</P>
<p>使用 unshift 给数组头部添加一个对象</P>
<p>a = [1,2,3,4]</P>
<p>a.unshift(0) # <b>结果：[0,1,2,3,4]</B></P>
<p><b>&nbsp;</B></P>
<p>使用 push （或 &lt;&lt; 方法）给数组屋部添加一个对象</P>
<p>a = [1,2,3,4]</P>
<p>a &lt;&lt; 5 # <b>结果：[1,2,3,4,5]</B></P>
<p>a.push(6,7,8) # <b>结果：[1,2,3,4,5,6,7,8]</B></P>
<p><b>&nbsp;</B></P>
<p>使用 shift 和 pop 从数组的头和尾删除一个对象</P>
<p>a = [1,2,3,4,5]</P>
<p>print "The original array: "</P>
<p>p a</P>
<p>popped = a.pop</P>
<p>print "The popped item: "</P>
<p>puts popped</P>
<p>print "The new state of the array: "</P>
<p>p a</P>
<p>shifted = a.shift</P>
<p>print "The shifted item: "</P>
<p>puts shifted</P>
<p>print "The new state of the array: "</P>
<p>p a</P>
<p>输出结果如下</P>
<p>The original array: [1, 2, 3, 4, 5]</P>
<p>The popped item: 5</P>
<p>The new state of the array: [1, 2, 3, 4]</P>
<p>The shifted item: 1</P>
<p>The new state of the array: [2, 3, 4]</P>
<p>&nbsp;</P>
<p>3. 合并数组</P>
<p>（1）使用 concat 方法，合并多个数组，并且永久性地改变了接收者的内容</P>
<p>[1,2,3].concat([4,5,6])</P>
<p>&nbsp;</P>
<p>（2）另一种方法是使用 + 方法进行合并，不改变接收者的内容</P>
<p>[1,2,3] + [4,5,6]</P>
<p>&nbsp;</P>
<p>（3）使用 replace 替换数组</P>
<p>&gt;&gt; a = [1,2,3]</P>
<p>=&gt; [1, 2, 3]</P>
<p>&gt;&gt; a.replace([4,5,6])</P>
<p>=&gt; [4, 5, 6]</P>
<p>&gt;&gt; a</P>
<p>=&gt; [4, 5, 6]</P>
<p>此方法与重新赋值是不一样的，在于变量的引用不同</P>
<p>&nbsp;</P>
<p>（4）使用 zip 并行遍历两个数组，产生一个新的数组</P>
<p>&gt;&gt; [1,2,3].zip([4,5,6])</P>
<p>=&gt; [[1, 4], [2, 5], [3, 6]]</P>
<p>&nbsp;</P>
<p>4. 数组转换</P>
<p>（1）使用 flatten 进行数组的平坦化</P>
<p>&gt;&gt;
[1,2,[3,4,[5,6],7],[[[8,9]]]].flatten</P>
<p>=&gt; [1, 2, 3, 4, 5, 6, 7, 8, 9]</P>
<p>&nbsp;</P>
<p>（2）使用 reverse 方法反转数组内容（也有一个感叹号版本）</P>
<p>&gt;&gt;[1,2,3,4].reverse</P>
<p>=&gt; [4, 3, 2, 1]</P>
<p>&nbsp;</P>
<p>（3）使用 join 方法把数组转换成字符串</P>
<p>&gt;&gt; ["abc", "def", 123].join(",
")</P>
<p>=&gt; "abc, def, 123"</P>
<p>&nbsp;</P>
<p>（4）使用 uniq 对数组进行唯一化处理，删除原来数组中重复的元素</P>
<p>&gt;&gt; [1,2,3,1,4,3,5,1].uniq</P>
<p>=&gt; [1, 2, 3, 4, 5]</P>
<p>&nbsp;</P>
<p>5. 数组迭代、过滤及查询</P>
<p>（1）数组迭代</P>
<p>[1,2,3,4,5].each {|x| puts x * 10 }</P>
<p>&nbsp;</P>
<p>使用 each 方法的变体
each_with_index，在遍历时每次通过匿名调用给代码块传递两个值：当前数组元素及其数组索引（从0开始）</P>
<p>["a","b","c"].each_with_index {|x,i| puts "element #{i} is #{x}"
}</P>
<p>输出如下</P>
<p>element 0 is a</P>
<p>element 1 is b</P>
<p>element 2 is c</P>
<p>&nbsp;</P>
<p>（2）数组过滤</P>
<p>使用 find 方法，返回第一个满足代码块条件的元素</P>
<p>&gt;&gt; [1,2,3,4,5,6,7,8,9,10].find
{|n| n &gt; 5 }</P>
<p>=&gt; 6</P>
<p>&nbsp;</P>
<p>使用 find_all （或 select）方法，返回所有满足代码块条件的元素</P>
<p>&gt;&gt; a = [1,2,3,4,5,6,7,8,9,10]</P>
<p>=&gt; [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</P>
<p>&gt;&gt; a.find_all {|item| item
&gt; 5 }</P>
<p>=&gt; [6, 7, 8, 9, 10]</P>
<p>&gt;&gt; a.find_all {|item| item
&gt; 100 }</P>
<p>=&gt; []</P>
<p>&nbsp;</P>
<p>使用 reject 方法找出不满足代码条件的元素</P>
<p>&gt;&gt; a.reject {|item| item
&gt; 5 }</P>
<p>=&gt; [1, 2, 3, 4, 5]</P>
<p>&nbsp;</P>
<p>（3）常用的数组查询方法</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="177">
<p>方法名／调用示例</P>
</TD>
<td VALIGN="top" WIDTH="391">
<p>含义</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="177">
<p>a.size（同义词：length）</P>
<p>a.empty?</P>
<p>a.include?(item)</P>
<p>a.any? { |item| test }</P>
<p>a.all? { |item| test }</P>
</TD>
<td VALIGN="top" WIDTH="391">
<p>数组中元素的个数</P>
<p>a是空数组返回真；否则为假</P>
<p>数组a包含item时为真；否则为假</P>
<p>有一个元素通过测试就为真；否则为假</P>
<p>所有元素都通过测试就为真；否则为假</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<h3>三、散列</H3>
<p>1. 创建一个新的散列</P>
<p>h = {} 或 Hash.new</P>
<p>创建带有数据的散列使用 [] 方法</P>
<p>Hash["Connecticut" =&gt; "CT",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
"Delaware"&nbsp;&nbsp;&nbsp;
=&gt; "DE" ]</P>
<p>&nbsp;</P>
<p>2. 插入、检索和删除散列键值对</P>
<p>（1）给散列添加键—值对，键值是唯一的</P>
<p>state_hash["New York"] = "NY"</P>
<p>该语句是下面这条语句的糖衣版本</P>
<p>state_hash.[]=("New York", "NY")</P>
<p>也可以使用相同功能的 store 方法来完成</P>
<p>state_hash.store("New York", "NY")</P>
<p>&nbsp;</P>
<p>（2）从散列检索值</P>
<p>conn_abbrev = state_hash["Connecticut"]</P>
<p>另一种方法是使用 fetch 方法</P>
<p>conn_abbrev = state_hash.fetch("Connecticut")</P>
<p>注：fetch 与 [] 方法不同之处：查找一个不存在的键时，fetch 抛出异常而 [] 返回 nil。</P>
<p>&nbsp;</P>
<p>还可以在一个操作中使用多个键来检索多个值，需要使用 values_at 方法</P>
<p>two_states = state_hash.values_at("New Jersey","Delaware")</P>
<p>结果为 ["NJ","DE"]</P>
<p>&nbsp;</P>
<p>3. 指定和获取默认值</P>
<p>&gt;&gt; h = Hash.new(0)</P>
<p>=&gt; {}</P>
<p>&gt;&gt; h["no such key!"]</P>
<p>=&gt; 0</P>
<p>这种方法可以在第一次用到时，自动添加键</P>
<p>&nbsp;</P>
<p>如果不想让不存在的键时自动添加到散列，并设置默认值的话，可以这样</P>
<p>h = Hash.new {|hash,key| hash[key] = 0 }</P>
<p>可以这样来触发</P>
<p>&gt;&gt; h["new key!"]</P>
<p>=&gt; 0</P>
<p>&gt;&gt; h</P>
<p>=&gt; {"new key!"=&gt;0}</P>
<p>&nbsp;</P>
<p>4. 合并散列</P>
<p>（1）破坏型操作通过方法 update
进行，如果第二个散列与第一个散列有相同的键，那么第一个散列中的键—值对会被永久性地覆盖</P>
<p>h1 = {"Smith" =&gt; "John",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"Jones" =&gt; "Jane" }</P>
<p>h2 = {"Smith" =&gt; "Jim" }</P>
<p>h1.update(h2)</P>
<p>puts h1["Smith"] # <b>输出: Jim</B></P>
<p>&nbsp;</P>
<p>（2）要进行非破坏型散列合并，需要使用 merge 方法，merge! 与 update 是同义词</P>
<p>h1 = {"Smith" =&gt; "John",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"Jones" =&gt; "Jane" }</P>
<p>h2 = {"Smith" =&gt; "Jim" }</P>
<p>h3 = h1.merge(h2)</P>
<p>p h1["Smith"] # <b>输出: John</B></P>
<p>&nbsp;</P>
<p>5. 散列转换</P>
<p>（1）反转散列Hash#invert：交换键和值</P>
<p>&gt;&gt; h = { 1 =&gt;
"one", 2 =&gt; "two" }</P>
<p>=&gt; {1=&gt;"one",
2=&gt;"two"}</P>
<p>&gt;&gt; h.invert</P>
<p>=&gt; {"two"=&gt;2,
"one"=&gt;1}</P>
<p>&nbsp;</P>
<p>（2）清空散列Hash#clear</P>
<p>&gt;&gt; {1 =&gt; "one", 2
=&gt; "two" }.clear</P>
<p>=&gt; {}</P>
<p>&nbsp;</P>
<p>（3）替代散列的内容 replace</P>
<p>&gt;&gt; { 1 =&gt; "one", 2
=&gt; "two" }.replace({ 10 =&gt; "ten", 20
=&gt; "twenty"})</P>
<p>=&gt; {10 =&gt; "ten", 20
=&gt; "twenty"}</P>
<p>&nbsp;</P>
<p>6. 散列的迭代、过滤和查询</P>
<p>（1）一个完整的键—值对通过匿名调用以一个两元素数组的形式传给代码块</P>
<p>{1 =&gt; "one", 2 =&gt; "two" }.each do
|key,value|</P>
<p>&nbsp; puts "The word for #{key} is #{value}."</P>
<p>end</P>
<p>输出结果如下</P>
<p>The word for 1 is one.</P>
<p>The word for 2 is two.</P>
<p>&nbsp;</P>
<p>（2）迭代遍历所有的键或值</P>
<p>&gt;&gt; h = {1 =&gt; "one",
2 =&gt; "two" }</P>
<p>=&gt; {1=&gt;"one",
2=&gt;"two"}</P>
<p>&gt;&gt; h.keys</P>
<p>=&gt; [1, 2]</P>
<p>&gt;&gt; h.values</P>
<p>=&gt; ["one", "two"]</P>
<p>也可以直接对键或值进行迭代</P>
<p>h = {"apple" =&gt; "red", "banana" =&gt;
"yellow", "orange" =&gt; "orange" }</P>
<p>h.each_key {|k| puts "The next key is #{k}." }</P>
<p>h.each_value {|v| puts "The next value is #{v}." }</P>
<p>&nbsp;</P>
<p>（3）散列的过滤操作</P>
<p>&gt;&gt; { 1 =&gt; "one", 2
=&gt; "two", 3 =&gt; "three" }.select
{|k,v| k &gt; 1 }</P>
<p>=&gt; [[2, "two"], [3, "three"]]</P>
<p>&nbsp;</P>
<p>或使用 find 方法，返回一个元素或 nil</P>
<p>&gt;&gt; {1 =&gt; "un", 2
=&gt; "deux", 3 =&gt; "trois" }.find {|k,v|
k == 3 }</P>
<p>=&gt; [3, "trois"]</P>
<p>&nbsp;</P>
<p>还可以对散列进行映射操作</P>
<p>&gt;&gt; { 1 =&gt; "one", 2
=&gt; "two", 3 =&gt; "three" }.map {|k,v|
v.upcase }</P>
<p>=&gt; ["ONE", "TWO", "THREE"]</P>
<p>&nbsp;</P>
<p>7. 常用的散列查询方法及其含义</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="284">
<p>方法名／调用示例</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>含义</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="284">
<p>h.has_key?(1)</P>
<p>h.include?(1)</P>
<p>h.key?(1)</P>
<p>h.member?(1)</P>
<p>h.has_value?("three")</P>
<p>h.value?("three")</P>
<p>h.empty?</P>
<p>h.size</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>如果h有键为1，则为真</P>
<p>h.has_key? 的同义词</P>
<p>h.has_key? 的同义词</P>
<p>h.has_key? 的同义词</P>
<p>只要 h 有值为 “three”，就为真</P>
<p>has_value? 的同义词</P>
<p>如果h没有任何键-值对，就为真</P>
<p>h中键-值对个数</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>8. Ruby 和 Rails 方法调用中的散列</P>
<p>&lt;% def mini_link_to(text, specs)</P>
<p>&nbsp;&nbsp;&nbsp; target =
"/#{specs[:controller]}/#{specs[:action]}/#{specs[:id]}"</P>
<p>&nbsp;&nbsp;&nbsp; return
"&lt;a
href=\"#{target}\"&gt;#{text}&lt;/a&gt;"</P>
<p>&nbsp; end</P>
<p>%&gt;</P>
<p>&lt;%= mini_link_to "Click here",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "work",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; 1</P>
<p>%&gt;</P>
<p>将这段代码保存到文件 minilink.erb 中，然后使用 ERb 来运行它</P>
<p>$ erb minilink.erb</P>
<p>&nbsp;</P>
<p>ERb会填充模板，结果如下所示：</P>
<p>&lt;a href="/work/show/1"&gt;Click
here&lt;/a&gt;</P>
<p>&nbsp;</P>
<h3>四、集合的中心：Enumerable 模块</H3>
<p>1. 数组和散列都混含了 Enumerable 模块</P>
<p>class c</P>
<p>&nbsp; include Enumerable</P>
<p>&nbsp; def each</P>
<p>&nbsp;&nbsp;&nbsp; #
relevant code here</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 通过 each 获得可枚举性</P>
<p>each 的任务就是通过匿名调用将所有的条目传递给一个给定的代码块，每次只传一个。</P>
<p>find、select、reject、map、any? 和 all? 它们的工作方式都调用方法 each：</P>
<p>class Rainbow</P>
<p>&nbsp; include Enumerable</P>
<p>&nbsp;&nbsp;def each</P>
<p>&nbsp;&nbsp;&nbsp; yield
"red"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"orange"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"yellow"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"green"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"blue"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"indigo"</P>
<p>&nbsp;&nbsp;&nbsp; yield
"violet"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>r = Rainbow.new</P>
<p>y_color = r.find {|color| color[0,1] == 'y' }</P>
<p>puts "First color starting with 'y' is #{y_color}."</P>
<p>可以重写为：</P>
<p>class Rainbow</P>
<p>&nbsp; COLORS = ["red", "orange", "yellow",
"green",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"blue", "indigo", "violet"]</P>
<p>&nbsp; def each</P>
<p>&nbsp;&nbsp;&nbsp;
COLORS.each {|color| yield color }</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 可枚举的字符串</P>
<p>（1）使用 String#each 进行迭代</P>
<p>s = "This is\na multiline\nstring."</P>
<p>s.each {|e| puts "Next value: #{e}" }</P>
<p>这段代码将一个多行字符串（带显式嵌入的换行符\n）赋值给一个变量，然后对这个字符串进行迭代</P>
<p>Next value: This is</P>
<p>Next value: a multiline</P>
<p>Next value: string.</P>
<p>&nbsp;</P>
<p>（2）使用 each_byte 进行字符迭代</P>
<p>"abc".each_byte {|b| puts "Next byte: #{b}" }</P>
<p>&nbsp;</P>
<p>输出字符的 ASCII 码，如果想把它们转换成字符，可以调用数值的 chr 方法</P>
<p>"abc".each_byte {|b| puts "Next character: #{b.chr}" }</P>
<p>&nbsp;</P>
<p>直接对字符进行迭代，创建 String.each_char 方法</P>
<p>class String</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def each_char</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
each_byte { |b| yield b.chr}</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>五、集合排序</H3>
<p>1. 数组排序</P>
<p>&gt;&gt; [3,2,5,4,1].sort</P>
<p>=&gt; [1, 2, 3, 4, 5]</P>
<p>&nbsp;</P>
<p>2. 对象数组排序</P>
<p>[ed1,ed2,ed3,ed4,ed5].sort</P>
<p>在 Edition 类中定义&lt;=&gt;方法：</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def &lt;=&gt;(other_edition)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self.price &lt;=&gt;
other_edition.price</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 在代码块中定义排序顺序</P>
<p>year_sort = [ed1,ed2,ed3,ed4,ed5].sort do |a,b|</P>
<p>&nbsp; a.year &lt;=&gt;
b.year</P>
<p>end</P>
<p>&nbsp;</P>
<p>使用 sort_by 的简洁排序，和 sort 一样，sort_by 也是 Enumerable
的一个实例方法。它们的主要区别是：必须为 sort_by 提供一个代码块，代码块中只需要说明如何对集合中的单个条目进行处理</P>
<p>&gt;&gt; ["2",1,5,"3",4,"6"].sort_by
{|a| a.to_i }</P>
<p>=&gt; [1, "2", "3", 4, 5, "6"]</P>
<p>&nbsp;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100ergw.html#comment</comments>
            <pubDate>Tue, 25 Aug 2009 10:59:02 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100ergw.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8553;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100ergp.html</link>
            <description><![CDATA[<h2>第十章 标量对象</H2>
<h3>一、使用字符串</H3>
<p>1. 字符串引用机制概要</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="54">
<p ALIGN="center"><b>记号</B></P>
</TD>
<td WIDTH="85">
<p ALIGN="center"><b>单引或双引</B></P>
</TD>
<td WIDTH="227">
<p ALIGN="center"><b>示例</B></P>
</TD>
<td WIDTH="202">
<p ALIGN="center"><b>输出</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="54">
<p>'</P>
</TD>
<td VALIGN="top" WIDTH="85">
<p>单引</P>
</TD>
<td VALIGN="top" WIDTH="227">
<p>'You\'ll have to "escape" single quotes.'</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>You’ll have to “escape” single quotes.</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="54">
<p>"</P>
</TD>
<td VALIGN="top" WIDTH="85">
<p>双引</P>
</TD>
<td VALIGN="top" WIDTH="227">
<p>"You'll have to \"escape\" double</P>
<p>quotes."</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>You’ll have to “escape” double quotes.</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="54">
<p>%q</P>
</TD>
<td VALIGN="top" WIDTH="85">
<p>单引</P>
</TD>
<td VALIGN="top" WIDTH="227">
<p>%q{'Single-quoted' example—no</P>
<p>escape needed.}</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>Single-quoted’ example—no escape needed.</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="54">
<p>%Q</P>
</TD>
<td VALIGN="top" WIDTH="85">
<p>双引</P>
</TD>
<td VALIGN="top" WIDTH="227">
<p>%Q{"Double-quoted" example—no</P>
<p>escape needed..}</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>“Double-quoted” example—no escape needed.</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>2. 字符串操作</P>
<p>（1）合并两个字符串</P>
<p>str = "a" + "b"</P>
<p>str = "a" &lt;&lt; "b"</P>
<p>&nbsp;</P>
<p>（2）替换字符串的内容</P>
<p>str = "Hi there."</P>
<p>str.replace("Good-bye.")</P>
<p>&nbsp;</P>
<p>（3）改写字符串</P>
<p>&nbsp;</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="149">
<p ALIGN="center"><b>方法</B></P>
</TD>
<td WIDTH="230">
<p ALIGN="center"><b>示例</B></P>
</TD>
<td WIDTH="189">
<p ALIGN="center"><b>结果</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="149">
<p>capitalize</P>
<p>upcase</P>
<p>downcase</P>
<p>swapcase</P>
<p>strip</P>
<p>lstrip</P>
<p>rstrip</P>
<p>chop</P>
<p>chomp</P>
<p>reverse</P>
</TD>
<td VALIGN="top" WIDTH="230">
<p>"ruby".capitalize</P>
<p>"cobol".upcase</P>
<p>"UNIX".downcase</P>
<p>"rUBY".swapcase</P>
<p>" lose the outer spaces "</P>
<p>" lose the left spaces "</P>
<p>" lose the right spaces "</P>
<p>"remove last character"</P>
<p>"remove training newline\n"</P>
<p>" gnirts eht esrever"</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>"Ruby"</P>
<p>"COBOL"</P>
<p>"unix"</P>
<p>"Ruby"</P>
<p>"lose the outer spaces"</P>
<p>"lose the left spaces "</P>
<p>" lose the right spaces"</P>
<p>"remove last characte"</P>
<p>"remove trailing newline"</P>
<p>"reverse the string"</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>注：所有这些方法都有相应的感叹号方法</P>
<p>&nbsp;</P>
<p>4. 获取字符串的子字符串</P>
<p>字符串有一对读写方法：[]方法和[]=方法</P>
<p>（1）读方法[]</P>
<p>"abc"[2] # 输出：99</P>
<p>"abc"[2].chr # 输出：c</P>
<p>"abc"[-2].chr # 输出：b</P>
<p>"This is a string"[5,4] # 输出：is a</P>
<p>&nbsp;</P>
<p>（2）写方法[]=</P>
<p>&gt;&gt; s = "This is a string."</P>
<p>=&gt; "This is a string."</P>
<p>&gt;&gt; s[-1] = "!"</P>
<p>=&gt; "!"</P>
<p>&gt;&gt; s</P>
<p>=&gt; "This is a string!"</P>
<p>&gt;&gt; s[2,2] = "at"</P>
<p>=&gt; "at"</P>
<p>&gt;&gt; s</P>
<p>=&gt; "That is a string!"</P>
<p>&nbsp;</P>
<p>5. 比较字符串</P>
<p>（1）比较两个字符串是否相等，最常用的方法 ==</P>
<p>"a" == "a" # 输出：true</P>
<p>"a" == "b" # 输出：false</P>
<p>另一种方法是 String#eql?，如 "a".eql?("a") # 输出：true</P>
<p>第三种方法是 String#equal?，如 "a".equal?("a") #
输出：false，因为两个字符串不是同一个对象</P>
<p>&nbsp;</P>
<p>（2）字符串的比较与顺序</P>
<p>
太空船方法/操作符（&lt;=&gt;）返回-1表示右边对象较大，1表示左边对象较大，0表示相等。</P>
<p>“a”比”A”要大，因为顺序是基于 ASCII 码值定义的。</P>
<p>&nbsp;</P>
<h3>二、符号及其用法</H3>
<p>1. 符号是 Ruby 内建的 Symbol 的实例，它们的字面构造器是前导冒号</P>
<p>:a</P>
<p>:book</P>
<p>:"Here's how to make a symbol with spaces in it."</P>
<p>还可以通过对字符串调用 to_sym 方法（也可以用同意词 intern），以编程方式创建符号</P>
<p>&gt;&gt; "a".to_sym</P>
<p>=&gt; :a</P>
<p>&gt;&gt; "Converting string to symbol
with intern....".intern</P>
<p>=&gt; :"Converting string to symbol with
intern...."</P>
<p>也可以很容易将符号转换成字符串</P>
<p>&gt;&gt; :a.to_s</P>
<p>=&gt; "a"</P>
<p>&nbsp;</P>
<p>2. 符号与字符串的关键不同：对于任何给定的文本，只存在一个符号对象</P>
<p>&gt;&gt; :a.equal?(:a)</P>
<p>=&gt; true</P>
<p>&gt;&gt; "a".equal?("a")</P>
<p>=&gt; false</P>
<p>字符串与符号之间的另一个重要不同之处是：符号是不可变的，不能对符号的一部分进行增加、删除或改变。</P>
<p>
符号在内存和处理时间上是高效的。相反，字符串具备的各种功能（如字符串变长，改变内容，等等）决定了其维护与处理的开销比较大。常常会见到符号被用作方法的参数，尤其是散列的键。</P>
<p>&nbsp;</P>
<p>3. 重新讲解 Rails 风格的方法参数</P>
<p>class Work &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
belongs_to :composer</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# etc.</P>
<p>其中 :composer 是一个符号，它是 belongs_to 方法的参数。</P>
<p>&lt;%= link_to "Click here",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:controller
=&gt; "book",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; book.id %&gt;</P>
<p>这是方法参数散列的一个例子，每一个符号都是散列的键，每一个右侧值都是散列的值。</P>
<p>&nbsp;</P>
<h3>三、数值对象</H3>
<p>1. 在 Ruby 中，数是对象。和其它对象一样，可以给它们发送消息。</P>
<p>n = 98.6</P>
<p>m = n.round</P>
<p>puts m</P>
<p>x = 12</P>
<p>if x.zero?</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "x is zero"</P>
<p>else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "x is not zero"</P>
<p>end</P>
<p>puts "The ASCII character equivalent of 97 is #{97.chr}"</P>
<p>&nbsp;</P>
<p>2. 数值类层级结构</P>
<p>&nbsp;<a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static3.photo.sina.com.cn/orignal/3ecb9b11t71f53ee206a2&amp;690" TARGET="_blank"><img SRC="http://static3.photo.sina.com.cn/bmiddle/3ecb9b11t71f53ee206a2&amp;690" /></A></P>
<p>&nbsp;</P>
<p>3. 常见算术表达式及其求值结果</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="130">
<p ALIGN="center"><b>表达式</B></P>
</TD>
<td WIDTH="189">
<p ALIGN="center"><b>结果</B></P>
</TD>
<td WIDTH="249">
<p ALIGN="center"><b>评注</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="130">
<p>1 + 1</P>
<p>10/5</P>
<p>10/3</P>
<p>10.0/3.0</P>
<p>1.2 + 3.4</P>
<p>-12 - -7</P>
<p>10 % 3</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>2</P>
<p>2</P>
<p>3</P>
<p>3.3333333333</P>
<p>4.6</P>
<p>-5</P>
<p>1</P>
</TD>
<td VALIGN="top" WIDTH="249">
<p>加法</P>
<p>整数除法</P>
<p>整数除法（无自动浮点数转换）</P>
<p>浮点数除法</P>
<p>浮点数加法</P>
<p>减法</P>
<p>模运算（余数）</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>4. 非十进制数运算</P>
<p>（1）十六进制数，前导 0x 指示</P>
<p>&gt;&gt; 0x12</P>
<p>=&gt; 18</P>
<p>&gt;&gt; 0x12 + 12</P>
<p>=&gt; 30</P>
<p>&nbsp;</P>
<p>（2）八进制数，前导 0 指示</P>
<p>&gt;&gt; 012</P>
<p>=&gt; 10</P>
<p>&gt;&gt; 012 + 12</P>
<p>=&gt; 22</P>
<p>&gt;&gt; 012 + 0x12</P>
<p>=&gt; 28</P>
<p>&nbsp;</P>
<p>（3）用 to_i 方法将其它进制数转成十进制</P>
<p>&gt;&gt; "10".to_i(17)</P>
<p>=&gt; 17</P>
<p>&gt;&gt; "12345".to_i(13)</P>
<p>=&gt; 33519</P>
<p>&gt;&gt; "ruby".to_i(35)</P>
<p>=&gt; 1194794</P>
<p>&nbsp;</P>
<h3>四、时间和日期</H3>
<p>1. 时间和日期是通过三个类来操作的：Time、Date 和 DateTime。为了使用它们的全部功能，需要将 date 库或
time 库两者都请求加载到程序中或 irb 会话中</P>
<p>require 'date'</P>
<p>require 'time'</P>
<p>想知道英格兰是如何称呼1705年4月24日的吗？</P>
<p>&gt;&gt; require 'date'</P>
<p>=&gt; true</P>
<p>&gt;&gt; Date.parse("April 24
1705").england.strftime("%B %d %Y")</P>
<p>=&gt; "April 13 1705"</P>
<p>&nbsp;</P>
<p>2. 获得系统当前时间</P>
<p>require 'date'</P>
<p>d = Date.today</P>
<p>puts d</P>
<p>2009-08-21</P>
<p>&nbsp;</P>
<p>3. 日期对象可以响应 &lt;&lt; 和
&gt;&gt; 方法</P>
<p>puts d &lt;&lt; 2 #
输出：2009-06-21，两个月前的日期</P>
<p>puts d &gt;&gt; 5 #
输出：2010-01-21，五个月后的日期</P>
<p>&nbsp;</P>
<p>4. 获得年、月、日、小时、分钟、秒及微秒</P>
<p>&gt;&gt; t = Time.new</P>
<p>=&gt; Tue Jan 17 17:51:04 PST 2006</P>
<p>&gt;&gt; t.year</P>
<p>=&gt; 2006</P>
<p>&gt;&gt; t.month</P>
<p>=&gt; 1</P>
<p>&gt;&gt; t.day</P>
<p>=&gt; 17</P>
<p>&gt;&gt; t.hour</P>
<p>=&gt; 17</P>
<p>&gt;&gt; t.min</P>
<p>=&gt; 51</P>
<p>&gt;&gt; t.sec</P>
<p>=&gt; 4</P>
<p>&gt;&gt; t.usec</P>
<p>=&gt; 377285</P>
<p>5. UNIX 风格的格式字符串</P>
<p>&gt;&gt; t.strftime("%m-%d-%Y")</P>
<p>=&gt; "01-17-2006"</P>
<p>&nbsp;</P>
<p>6. 常见的时间和日期格式说明符</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="284">
<p ALIGN="center"><b>说明符</B></P>
</TD>
<td WIDTH="284">
<p ALIGN="center"><b>描述</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="284">
<p>%Y</P>
<p>%y</P>
<p>%b, %B</P>
<p>%m</P>
<p>%d</P>
<p>%e</P>
<p>%a, %A</P>
<p>%H,%I</P>
<p>%M</P>
<p>%S</P>
<p>%c</P>
<p>%x</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>年份（4位数字）</P>
<p>年份（最后2位数字）</P>
<p>月份名的缩写、月份名的全称</P>
<p>月份（数字）</P>
<p>日子（左边补0）</P>
<p>日子（左边补空格）</P>
<p>星期几的缩写、星期几的全称</P>
<p>小时（24小时进制），小时（12小时进制）</P>
<p>分钟</P>
<p>秒</P>
<p>等价于 %a %b %d %H:%M:%S %Y</P>
<p>等价于 %m/%d/%y</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>7. 一些时间格式说明符的用法示例</P>
<p>&gt;&gt; t.strftime("Today is %x")</P>
<p>=&gt; "Today is 01/17/06"</P>
<p>&gt;&gt; t.strftime("Otherwise known as
%d-%b-%y")</P>
<p>=&gt; "Otherwise known as 17-Jan-06"</P>
<p>&gt;&gt; t.strftime("Or even day %e of
%B, %Y.")</P>
<p>=&gt; "Or even day 17 of January, 2006."</P>
<p>&gt;&gt; t.strftime("The time is
%H:%m.")</P>
<p>=&gt; "The time is 17:01."</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100ergp.html#comment</comments>
            <pubDate>Tue, 25 Aug 2009 10:57:23 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100ergp.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8552;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100epnp.html</link>
            <description><![CDATA[<h1>第三部分 内建类和内建模块</H1>
<h2>第九章 内建类和内建模块基础知识</H2>
<h3>一、Ruby 的字面构造器</H3>
<p>Ruby 有很多内建类，它们中的大多数可以用 new 来实例化</P>
<p>str = String.new</P>
<p>arr = Array.new</P>
<p>有些则不可以，比如，不可以创建 Integer 类的新实例。</P>
<p>&nbsp;</P>
<p>此外，有一部分幸运的内建类还有<b>字面构造器</B>，这意味着可以用特别的记法来创建这些类的对象，而不调用 new。比如：对于
String.new 和 Array.new 来说，更常见到的是 “” 和 []</P>
<p>&nbsp;</P>
<p>内建类的字面构造器</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="83">
<p ALIGN="center"><b>类</B></P>
</TD>
<td WIDTH="132">
<p ALIGN="center"><b>字面构造器</B></P>
</TD>
<td WIDTH="353">
<p ALIGN="center"><b>示例</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>String</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>引号</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>"new string" 或 'new string'</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Symbol</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>前导冒号</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>:symbol 或 :"symbol with spaces"</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Array</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>中括号</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>[1,2,3,4,5]</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Hash</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>大括号</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>{"New York" =&gt; "NY", "Oregon" =&gt;
"OR"}</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Range</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>二个或三个圆点</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>0...10 或 0..9</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>Regexp</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>斜杠</P>
</TD>
<td VALIGN="top" WIDTH="353">
<p>/([a-z]+)/</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<h3>二、反复出现的语法糖衣</H3>
<p>有操作符风格的语法糖衣调用记法的方法</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="114">
<p ALIGN="center"><b>分类</B></P>
</TD>
<td WIDTH="64">
<p ALIGN="center"><b>名称</B></P>
</TD>
<td WIDTH="132">
<p ALIGN="center"><b>定义示例</B></P>
</TD>
<td WIDTH="145">
<p ALIGN="center"><b>调用示例</B></P>
</TD>
<td WIDTH="114">
<p ALIGN="center"><b>糖衣化记法</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="114">
<p>算术方法/</P>
<p>操作符</P>
</TD>
<td VALIGN="top" WIDTH="64">
<p>+</P>
<p>-</P>
<p>*</P>
<p>/</P>
<p>%</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>def +(x)</P>
<p>def -(x)</P>
<p>def *(x)</P>
<p>def /(x)</P>
<p>def %(x)</P>
</TD>
<td VALIGN="top" WIDTH="145">
<p>obj.+(x)</P>
<p>obj.-(x)</P>
<p>obj.*(x)</P>
<p>obj./(x)</P>
<p>obj.%(x)</P>
</TD>
<td VALIGN="top" WIDTH="114">
<p>obj + x</P>
<p>obj - x</P>
<p>obj * x</P>
<p>obj / x</P>
<p>obj % x</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="114">
<p>读/写/添加数据</P>
</TD>
<td VALIGN="top" WIDTH="64">
<p>[]</P>
<p>[]=</P>
<p>&lt;&lt;&nbsp;</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>def [](x)</P>
<p>def []=(x,y)</P>
<p>def &lt;&lt;(x)</P>
</TD>
<td VALIGN="top" WIDTH="145">
<p>obj.[](x)</P>
<p>obj.[]=(x,y)</P>
<p>obj.&lt;&lt;(x)</P>
</TD>
<td VALIGN="top" WIDTH="114">
<p>obj[x]</P>
<p>obj[x] = y</P>
<p>obj &lt;&lt; x</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="114">
<p>比较方法/</P>
<p>操作符</P>
</TD>
<td VALIGN="top" WIDTH="64">
<p>==</P>
<p>&gt;</P>
<p>&lt;</P>
<p>&gt;=</P>
<p>&lt;=</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>def ==(x)</P>
<p>def &gt;(x)</P>
<p>def &lt;(x)</P>
<p>def &gt;=(x)</P>
<p>def &lt;=(x)</P>
</TD>
<td VALIGN="top" WIDTH="145">
<p>obj.==(x)</P>
<p>obj.&gt;(x)</P>
<p>obj.&lt;(x)</P>
<p>obj.&gt;=(x)</P>
<p>obj.&lt;=(x)</P>
</TD>
<td VALIGN="top" WIDTH="114">
<p>obj == x</P>
<p>obj &gt; x</P>
<p>obj &lt; x</P>
<p>obj &gt;= x</P>
<p>obj &lt;= x</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="114">
<p>case 相等操作符</P>
</TD>
<td VALIGN="top" WIDTH="64">
<p>===</P>
</TD>
<td VALIGN="top" WIDTH="132">
<p>def ===(x)</P>
</TD>
<td VALIGN="top" WIDTH="145">
<p>obj.===(x)</P>
</TD>
<td VALIGN="top" WIDTH="114">
<p>obj === x</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>这类语法糖衣（看起来像操作符其实是方法调用）的广泛使用，揭示了作为一门编程语言的 Ruby 背后的很多哲学思想。</P>
<p>&nbsp;</P>
<p>算术方法/操作符的糖衣记法</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="284">
<p ALIGN="center"><b>糖衣记法</B></P>
</TD>
<td WIDTH="284">
<p ALIGN="center"><b>Ruby</B> <b>如何看待</B></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="284">
<p>x += 1</P>
<p>x -= 1</P>
<p>x *= 2</P>
<p>x /= 2</P>
<p>x %= 2</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>x = x + 1</P>
<p>x = x - 1</P>
<p>x = x * 2</P>
<p>x = x / 2</P>
<p>x = x % 2</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<h3>三、改变或者不改变其接收者的方法</H3>
<p>1. 改变接收者的方法的基本知识</P>
<p>（1）不改变接收者的示例，该例中 str 没有改变 capitalize 方法只返回了一个新的字符串</P>
<p>str = "hello"</P>
<p>puts str.capitalize #<b>输出：Hello</B></P>
<p>puts str&nbsp;&nbsp; #
<b>输出：hello</B></P>
<p><b>&nbsp;</B></P>
<p>（2）改变接收者的示例，原 str 字符串发生了变化</P>
<p>str = "hello"</P>
<p>str.replace("goodbye")</P>
<p>puts str # <b>输出：goodbye</B></P>
<p>&nbsp;</P>
<p>（3）改变对象而不是创建新对象的一个考虑是效率：创建新对象，就内存和处理器的资源来说开销很大。</P>
<p>&nbsp;</P>
<p>2. 感叹号 ! 方法</P>
<p>Ruby 允许定义方法名以感叹号结尾的方法。</P>
<p>&nbsp;</P>
<p>感叹号在 Ruby 内部没有什么特别的意义，不过根据惯例，感叹号表明一个方法是<b>危险的</B>。</P>
<p><b>危险</B>的意味着该方法（与和它同名的没有感叹号的方法不同）永久性地改变它的接收者。</P>
<p>&nbsp;</P>
<p>这样的方法对包括：用于数组的 sort/sort!，用于字符串的 upcase/upcase! 和
chomp/chomp!，以及用于字符串和数组的 reverse/reverse!。</P>
<p>&nbsp;</P>
<p>3. ActiveRecord 对象扩展了改变接收者的行为</P>
<p>composer = Composer.new</P>
<p>composer.first_name = "Johann"</P>
<p>composer.save</P>
<p>composer.update_attribute("last_name","Bach")</P>
<p>第一个改变将新的作曲者的名字设成 Johann，需要一个手动保存的操作才能将新的值保存到数据库中。第二个改变执行了一个
update_attribute
操作，不仅改变了内存中的对象属性，也更新了数据库中的记录，这种改变叫做横向（lateral）改变或元改变（meta-change）。</P>
<p>&nbsp;</P>
<h3>四、内建和定制的 to_*（转换）方法</H3>
<p>1. Ruby 提供了很多内建方法，这些方法可以将一个类的对象转换为另一类的对象，它们的名字以 to_
开头：to_s（转换成字符串），to_a（转换成数组），to_i（转换成整数）和 to_f（转换成浮点数）</P>
<p>&nbsp;</P>
<p>2. to_s 方法</P>
<p>&gt;&gt; "I am already a
string!".to_s</P>
<p>=&gt; "I am already a string!"</P>
<p>还可以返回扁平化的字符串</P>
<p>&gt;&gt; ["one", "two", "three", 4, 5,
6].to_s</P>
<p>=&gt; "onetwothree456"</P>
<p>也可以返回关于某个对象的描述性的字符串</P>
<p>&gt;&gt; Object.new.to_s</P>
<p>=&gt;
"#&lt;Object:0x401f81a4&gt;"</P>
<p>&nbsp;</P>
<p>3. 编写自己的 to_* 方法</P>
<p>class C</P>
<p>&nbsp; def initialize(name)</P>
<p>&nbsp;&nbsp;&nbsp; @name =
name</P>
<p>&nbsp; end</P>
<p>&nbsp; def to_s</P>
<p>&nbsp;&nbsp;&nbsp; "A C
object named #{@name}"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new("Emma")</P>
<p>puts c</P>
<p>&nbsp;</P>
<h3>五 、再论迭代器</H3>
<p>1. each 的返回值是它的接收者，即最初的数组</P>
<p>array = [1,2,3,4,5]</P>
<p>other = array.each {|n| puts "Current element is #{n}" }</P>
<p>这里，other 只是 array 的另一个引用。保存 each 的返回值没有什么意义。</P>
<p>&nbsp;</P>
<p>2. map 的返回值是一个新的数组，这个数组由所有匿名调用的操作结果构成</P>
<p>array = [1,2,3,4,5]</P>
<p>other = array.map {|n| n * 10 }</P>
<p>p other</P>
<p>这个新数组就是 map 调用的返回值：[10,20,30,40,50]</P>
<p>&nbsp;</P>
<h3>六、布尔状态、布尔对象和空对象</H3>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="189">
<p ALIGN="center"><strong>表达式</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="189">
<p ALIGN="center"><strong>表达式求值结果对象</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="189">
<p ALIGN="center"><strong>表达式的布尔值</STRONG></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="189">
<p>1</P>
<p>1+1</P>
<p>true</P>
<p>false</P>
<p>"string"</P>
<p>puts "string"</P>
<p>100 &gt; 50</P>
<p>x = 10</P>
<p>def x; end</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>1</P>
<p>2</P>
<p>true</P>
<p>false</P>
<p>"string"</P>
<p>nil</P>
<p>true</P>
<p>10</P>
<p>nil</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>true</P>
<p>true</P>
<p>true</P>
<p>false</P>
<p>true</P>
<p>false</P>
<p>true</P>
<p>true</P>
<p>false</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p><b>特殊对象 nil</B></P>
<p>nil 通过 to_s 转换为一个空字符串””；nil的整数表示为0；nil的对象id是4</P>
<p>说 nil 为空是不准确的。可以将 nil 想像成一个存在的对象，它具有一组幸存下来的方法</P>
<p>&nbsp;</P>
<h3>七、比较两个对象</H3>
<p>1. 相等性测试</P>
<p>&gt;&gt; a = Object.new</P>
<p>=&gt;
#&lt;Object:0x401c653c&gt;</P>
<p>&gt;&gt; b = Object.new</P>
<p>=&gt;
#&lt;Object:0x401c4bd8&gt;</P>
<p>&gt;&gt; a == a</P>
<p>=&gt; true</P>
<p>&gt;&gt; a == b</P>
<p>=&gt; false</P>
<p>&gt;&gt; a.eql?(a)</P>
<p>=&gt; true</P>
<p>&gt;&gt; a.eql?(b)</P>
<p>=&gt; false</P>
<p>&gt;&gt; a.equal?(a)</P>
<p>=&gt; true</P>
<p>&gt;&gt; a.equal?(b)</P>
<p>=&gt; false</P>
<p>&nbsp;</P>
<p>2. 比较和 Comparable 模块</P>
<p>（1）混含一个名为 Comparable 的模块（Ruby 提供）</P>
<p>（2）在类中定义一个名为 &lt;=&gt; 的比较方法</P>
<p>比较方法 &lt;=&gt;
（太空船操作符或太空船方法），该方法中定义了小于、等于和大于的含义</P>
<p>&nbsp;</P>
<h3>八、列出对象的方法</H3>
<p>1. 列出对象的方法，在 irb 中输入</P>
<p>"I am a String object".methods</P>
<p>对它们进行一下排序</P>
<p>"I am a String object".methods.sort</P>
<p>&nbsp;</P>
<p>2. 列出类的方法，而不是实例方法</P>
<p>String.methods.sort</P>
<p>列出 String 类的实例拥有的方法</P>
<p>String.instance_methods</P>
<p>&nbsp;</P>
<p>3. 列出对象的单例方法</P>
<p>str = "a plain old string"</P>
<p>"a plain old string"</P>
<p>def str.some_new_method; end</P>
<p>p str.singleton_methods.sort</P>
<p>&nbsp;</P>
<p>4. 产生过滤的和有选择的方法列表</P>
<p>如果想了解一个类的实例方法但不包括这个类的祖先类的实例方法，可以传入一个参数</P>
<p>String.instance_methods(false).sort</P>
<p>其它用于列举方法的方法包括以下几个</P>
<p>&#9632; obj.private_methods</P>
<p>&#9632; obj.public_methods</P>
<p>&#9632; obj.protected_methods</P>
<p>&#9632; obj.singleton_methods</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100epnp.html#comment</comments>
            <pubDate>Fri, 21 Aug 2009 11:22:10 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100epnp.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8551;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eopk.html</link>
            <description><![CDATA[<h2>第八章 控制流技术</H2>
<h3>一、条件代码执行</H3>
<p>1. if 关键字及相关构造</P>
<p><b>if condition</B></P>
<p><b>&nbsp; # code here, executed if condition uates
to true</B></P>
<p><b>end</B></P>
<p>也可以将整个 if 子句放在一行，为此需要在条件后面插入 then 关键字</P>
<p>if x &gt; 10 then puts x end</P>
<p>也可以使用分号来替代换行</P>
<p>if x &gt; 10; puts x; end</P>
<p>作为 Ruby 一个特殊规则，也可以使用冒号代替 then</P>
<p>if x &gt; 10: puts x; end</P>
<p>&nbsp;</P>
<p>2. else：可以在 if 语句中提供一个 else 分支</P>
<p><b>if condition</B></P>
<p><b>&nbsp; # code executed if condition is
true</B></P>
<p><b>else</B></P>
<p><b>&nbsp; # code executed if condition is
false</B></P>
<p><b>end</B></P>
<p>&nbsp;</P>
<p>3. elsif：使得条件逻辑可以层叠，形成比 if 和 else 更多的层次</P>
<p><b>if condition1</B></P>
<p><b>&nbsp; # code executed if condition1 is
true</B></P>
<p><b>elsif condition2</B></P>
<p><b>&nbsp; # code executed if condition1 is
false</B></P>
<p><b>&nbsp; # and condition2 is true</B></P>
<p><b>elsif condition3</B></P>
<p><b>&nbsp; # code executed if neither
condition1</B></P>
<p><b>&nbsp; # nor condition2 is true, but condition3
is</B></P>
<p><b>end</B></P>
<p>&nbsp;</P>
<p>4. unless：有时想使用否定 if 条件：如果某件事不是真的，那么执行给定的代码块</P>
<p>方法一：使用 not 关键字</P>
<p>if not (x == 1)</P>
<p>&nbsp;</P>
<p>方法二：使用否定操作符!</P>
<p>if !(x == 1)</P>
<p>&nbsp;</P>
<p>方法三：使用 unless</P>
<p>unless x == 1</P>
<p>&nbsp;</P>
<p>5. 条件修饰语：可以把条件判断直接放在语句的后面作为修饰语</P>
<p>puts "Big number!" if x &gt; 100</P>
<p>它和下面代码等价</P>
<p>if x &gt; 100</P>
<p>&nbsp; puts "Big number!"</P>
<p>end</P>
<p>也可以使用 unless 来实现</P>
<p>puts "Big number!" unless x &lt;= 100</P>
<p>条件修饰语具有会话的风格。它们不需要使用 end。不能用它们来完成太多的工作（不能带 else 或者 elsif
分支），但是在需要一个简单的条件判断时，它们往往非常合适。</P>
<p>&nbsp;</P>
<p>6. case 语句</P>
<p>print "Exit the program? (yes or no): "</P>
<p>answer = gets.chomp</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case answer</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
when "yes"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; puts "Good-bye!"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; exit</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
when "no"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; puts "OK, we'll continue"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp; puts "That's an unknown answer -- assuming you
meant 'no'"</P>
<p>end</P>
<p>&nbsp;</P>
<p>when 子句的匹配方法由 ===（三等号操作符）判断，即</P>
<p>if "yes" === answer</P>
<p>&nbsp; puts "Good-bye!"</P>
<p>&nbsp; exit</P>
<p>elsif "no" === answer</P>
<p>&nbsp; puts "OK, we'll continue"</P>
<p>else</P>
<p>&nbsp; puts "That's an unknown answer—assuming you
meant 'no'"</P>
<p>end</P>
<p>因此 case/when 逻辑的本质是 object === other_object；而 object ===
other_object 的本质是 object ===(other_object)。</P>
<p>&nbsp;</P>
<h3>二、用循环重复动作</H3>
<p>1. 用 loop 方法实现无条件循环，下面两段代码是等价的</P>
<p>loop { puts "Looping forever!" }</P>
<p>loop do puts "Looping forever!" end</P>
<p>&nbsp;</P>
<p>对循环进行控制（break 停止循环）</P>
<p>n = 1</P>
<p>loop do</P>
<p>&nbsp; n = n + 1</P>
<p>&nbsp; break if n &gt; 9</P>
<p>end</P>
<p>&nbsp;</P>
<p>使用 next 在没有完成本次循环的情况下跳到下一次循环</P>
<p>n = 1</P>
<p>loop do</P>
<p>&nbsp; n = n + 1</P>
<p>&nbsp; next unless n == 10</P>
<p>&nbsp; break</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 用 while 和 until 关键字实现条件循环</P>
<p>（1）while：在给定条件为真时循环执行代码</P>
<p>n = 1</P>
<p>while n &lt; 11</P>
<p>&nbsp; puts n</P>
<p>&nbsp; n = n + 1</P>
<p>end</P>
<p>puts "Done!"</P>
<p>&nbsp;</P>
<p>也可以把 while 子句放在循环的结束处，这时需要 begin/end 标记循环的头尾</P>
<p>n = 1</P>
<p>begin</P>
<p>&nbsp; puts n</P>
<p>&nbsp; n = n + 1</P>
<p>end while n &lt; 11</P>
<p>puts "Done!"</P>
<p>&nbsp;</P>
<p>（2）until：具有和 while 相同的用法，但是逻辑相反</P>
<p>n = 1</P>
<p>until n &gt; 10</P>
<p>&nbsp; puts n</P>
<p>&nbsp; n = n + 1</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）while 和 until 作为修饰语</P>
<p>和 if unless 一样，while 和 until 可以在语句的末尾用作修饰语</P>
<p>n = 1</P>
<p>n = n + 1 until n == 10</P>
<p>puts "We've reached 10!"</P>
<p>&nbsp;</P>
<p>3. for/in 循环：基于值列表的循环</P>
<p>celsius = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]</P>
<p>for c in celsius</P>
<p>&nbsp; puts c</P>
<p>end</P>
<p>&nbsp;</P>
<h3>三、代码块、迭代器和 yield 关键字</H3>
<p>1. 代码块：由任意多行 Ruby 代码构成，可以用大括号封装</P>
<p>object.method_name {</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# code inside block</P>
<p>}</P>
<p>也可以用 do/end 来封装</P>
<p>object.method_name do</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# code inside block</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. yield
关键字：如果在调用方法时提供了代码块，那么在该方法执行过程中可以将控制转移到该代码块（暂停方法的执行），执行代码块中的代码，最后再返回该方法继续执行</P>
<p>def demo_of_yield</P>
<p>&nbsp; puts "Executing the method body..."</P>
<p>&nbsp; puts "About to yield control to the
block..."</P>
<p>&nbsp; <b>yield</B></P>
<p>&nbsp; puts "Back from the block—finished!"</P>
<p>end</P>
<p>demo_of_yield <b>{ puts "&gt; Control has been
passed to the block!" }</B></P>
<p>该代码的输出如下</P>
<p>Executing the method body...</P>
<p>About to yield control to the block...</P>
<p>&gt; Control has been passed to the block!</P>
<p>Back from the block—finished!</P>
<p>&nbsp;</P>
<p>3.给代码块传递参数</P>
<p>可以通过 yield 将参数发送到代码</P>
<p>yield(x,y,z)</P>
<p>代码块接受参数的方法，不使用圆括号，而使用一对管道符号（||）</P>
<p>some_method {|a,b,c|</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# code here</P>
<p>}</P>
<p>示例如下</P>
<p>def yield_an_arg</P>
<p>&nbsp; puts "Yielding 10!"</P>
<p>&nbsp; yield(10)</P>
<p>end</P>
<p>yield_an_arg {|x| puts "&gt; Code block received
this argument: #{x}" }</P>
<p>&nbsp;</P>
<p>4. 从代码块返回值</P>
<p>def more_yielding</P>
<p>&nbsp; puts "The code block shall multiply a number
by 10."</P>
<p>&nbsp; result = yield(3)</P>
<p>&nbsp; puts "The result of this operation is
#{result}."</P>
<p>end</P>
<p>more_yielding {|x| x * 10 }</P>
<p>&nbsp;</P>
<p>5. 执行多个迭代</P>
<p>迭代：方法匿名调用代码块的过程</P>
<p>迭代器：任何匿名调用代码块的方法</P>
<p>使用代码块来执行温度转换方法</P>
<p>def temp_chart(temps)</P>
<p>&nbsp; for temp in temps</P>
<p>&nbsp;&nbsp;&nbsp; converted
= yield(temp)</P>
<p>&nbsp;&nbsp;&nbsp; puts
"#{temp}\t#{converted}"</P>
<p>&nbsp; end</P>
<p>end</P>
<p>celsiuses = [0,10,20,30,40,50,60,70,80,90,100]</P>
<p>temp_chart(celsiuses) {|cel| cel * 9 / 5 + 32 }</P>
<p>&nbsp;</P>
<p>6. Ruby 的代码块机制意味着：可以使用代码块来补足方法中没有完全定义的行为</P>
<p>我们可以使用同样的方法通过另外的方式转换温度：</P>
<p>fahrens = [32,62,92,122,152,182,212]</P>
<p>temp_chart(fahrens) {|fahr| (fahr - 32) * 5 / 9 }</P>
<p>&nbsp;</P>
<p>7. 关于 for 的更多内容</P>
<p>for 的本质就是迭代器：for 是调用一个特殊的迭代器 each 的一种可选方式</P>
<p>下面两段代码是等价的</P>
<p>for x in [1,2,3,4,5]</P>
<p>&nbsp; puts x * 10</P>
<p>end</P>
<p>与</P>
<p>[1,2,3,4,5].each {|x| puts x * 10 }</P>
<p>&nbsp;</P>
<h3>四、错误处理和异常</H3>
<p>1. 异常是特殊类型的对象，它是 Exception
类或它的后代类的一个实例，抛出一个异常意味着：停止程序的正常执行，处理碰到的问题或者退出程序</P>
<p>要看看实际中的异常可以试一试：</P>
<p>F:\ruby_project&gt;ruby -e '1./0'</P>
<p>Ruby 抛出一个异常</P>
<p>-e:1:in `/': divided by 0 (<b>ZeroDivisionError</B>)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
from -e:1</P>
<p>&nbsp;</P>
<p>2. 常见的异常</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="121">
<p ALIGN="center"><strong>异常名</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="258">
<p ALIGN="center"><strong>常见原因</STRONG></P>
</TD>
<td VALIGN="top" WIDTH="189">
<p ALIGN="center"><strong>怎样抛出</STRONG></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>RuntimeError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>这是 raise 方法抛出的默认异常</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>raise</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>NoMethodError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>对象收到一个找不到对应方法的消息</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>a = Object.new</P>
<p>a.some_unknown_method_name</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>NameError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>解释器碰到一个不能解析为变量或方法名的标识符</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>a = some_random_identifier</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>IOError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>读关闭的流（stream），写只读的流，或类似的操作</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>STDIN.puts("Don't write to</P>
<p>STDIN!")</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>Errno::error</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>与文件 IO 相关的一族错误</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>File.open(-12)</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>TypeError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>方法接收到它不能处理的参数</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>a = 3 + "can't add a string</P>
<p>to a number!"</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="121">
<p>ArgumentError</P>
</TD>
<td VALIGN="top" WIDTH="258">
<p>传递的参数的数目出错</P>
</TD>
<td VALIGN="top" WIDTH="189">
<p>def m(x); end; m(1,2,3,4,5)</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>3. 用 rescue 块来营救程序异常</P>
<p>print "Enter a number: "</P>
<p>n = gets.to_i</P>
<p><b>begin</B></P>
<p>&nbsp; result = 100 / n</P>
<p><b>rescue</B></P>
<p>&nbsp; puts "Your number didn't work. Was it
zero???"</P>
<p>&nbsp; exit</P>
<p><b>end</B></P>
<p>puts "100/#{n} is #{result}."</P>
<p>&nbsp;</P>
<p>指定想要营救的异常：rescue ZeroDivisionError</P>
<p>&nbsp;</P>
<p>4. 显示抛出异常</P>
<p>可以给 raise 提供第二个参数，作为抛出异常时的消息字符串</P>
<p>def fussy_method(x)</P>
<p>&nbsp; <b>raise ArgumentError, "I need a number
under 10"</B> unless x &lt; 10</P>
<p>end</P>
<p>fussy_method(20)</P>
<p>也可以在此例中使用 rescue</P>
<p>begin</P>
<p>&nbsp; fussy_method(20)</P>
<p>rescue ArgumentError</P>
<p>&nbsp; puts "That was not an acceptable number!"</P>
<p>end</P>
<p>&nbsp;</P>
<p>5. 重新抛出异常</P>
<p>def reraiser(filename)</P>
<p>&nbsp; file_handle = File.new(filename)</P>
<p>rescue Errno::ENOENT =&gt; e</P>
<p>&nbsp; puts "Something's wrong with your
filename...."</P>
<p>&nbsp; raise e</P>
<p>end</P>
<p>注意：只要 rescue 子句是方法定义体的最后部分，就不喜欢显示地使用 being/end 分隔符；</P>
<p>方法自己扮演了异常块的 end 角色。</P>
<p>此例涉及的主要新技术是那个奇特的 rescue 行。=&gt;e 构造将异常对象放入变量 e
中。</P>
<p>下面对该方法进行调用</P>
<p>reraiser("some_non_existent_filename")<br />
输出以下内容</P>
<p>Something's wrong with your filename....</P>
<p>reraiser.rb:2:in `initialize': No such file</P>
<p>&nbsp;&nbsp; or directory -
some_non_existent_filename</P>
<p>&nbsp;&nbsp; (Errno::ENOENT)</P>
<p>&nbsp;</P>
<p>6. 创建异常类：通过从 Exception 或它的后代继承</P>
<p>class MyNewException &lt; Exception</P>
<p>end</P>
<p>raise MyNewException, "some new kind of error has occurred!"</P>
<p>&nbsp;</P>
<p>7. 异常及它们在 Rails 框架中的名字</P>
<p>ActiveController 库定义了 UnknownAction,&nbsp;
UnknownController, MissingTemplate 等异常，所有这些异常类都继承自中间级别的异常类
ActionControllerError，该类是 Ruby 内建的 StandardError类的子类。</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eopk.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:53:14 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eopk.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8550;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eopi.html</link>
            <description><![CDATA[<h2>第七章 默认对象(self)和作用域</H2>
<p>一、理解当前对象或默认对象 self</P>
<p>1. 在不同上下文中判定 self</P>
<p>puts "Tol Level"</P>
<p>puts "self is #{self}" <b>#</B><b>输出 main</B></P>
<p>&nbsp;</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Class definition block:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "self is #{self}" <b>#</B><b>输出 C</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def self.x</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Class method C.x:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "self is #{self}" <b>#</B><b>输出 C</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def m</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Instance method C#x:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "self is #{self}" <b>#</B><b>输出
#&lt;C:0x2c029b4&gt;</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 在类和模块定义中的 self</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Just started class C:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self <b>#</B><b>输出 C</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Nested module C::M:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self <b>#</B><b>输出 C::M</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Back in the outer level of C:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self <b>#</B><b>输出 C</B></P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 单例方法定义和类方法定义中的 self</P>
<p>（1）在执行单例方法时，self 是拥有该方法的对象</P>
<p>obj = Object.new</P>
<p>&nbsp;</P>
<p>def obj.show_me</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
print "I'm an object; "</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "here's self inside a singleton method of mine:"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self</P>
<p>end</P>
<p>&nbsp;</P>
<p>obj.show_me</P>
<p>print "And inspecting obj from outside, "</P>
<p>puts "to be sure it's the same object:"</P>
<p>p obj</P>
<p>&nbsp;</P>
<p>输出结果</P>
<p>I'm an object; here's self inside a singleton method of
mine:</P>
<p>#&lt;Object:0x2c02dec&gt;</P>
<p>And inspecting obj from outside, to be sure it's the same
object:</P>
<p>#&lt;Object:0x2c02dec&gt;</P>
<p>&nbsp;</P>
<p>（2）类方法中的 self 就是类本身，因此</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def C.x</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Class method of class C"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>等同于</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def self.x</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Class method of class C"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts self</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>二、确定作用域</H3>
<p>1. 全局变量具有全局作用域，全局变量通过变量名前加美元符号（$）来识别</P>
<p><b>$gvar = "I'm a global!"</B></P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def examine_global</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts <b>$gvar</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>C.new.examine_global</P>
<p>&nbsp;</P>
<p>2. Ruby 内建全局变量</P>
<p>（1）$0 包含了 Ruby 正在执行的文件的名字</P>
<p>（2）$: 包含了一些目录，在加载一个外部文件时，这些目录构成了 Ruby 搜索路径</P>
<p>（3）$$ 包含了 Ruby 进程的进程ID</P>
<p>&nbsp;</P>
<p>3. 全局变量使用范例</P>
<p>class Work</P>
<p>&nbsp;&nbsp; def show_info</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
puts "Title and composer: #{<b>$title</B>},
#{<b>$composer</B>}"</P>
<p>&nbsp;&nbsp; end</P>
<p>&nbsp;end</P>
<p>&nbsp;</P>
<p>&nbsp;work = Work.new</P>
<p><b>&nbsp;$composer = "Giuseppe Verdi"</B></P>
<p><b>&nbsp;$title = "La Traviata"</B></P>
<p>&nbsp;work.show_info</P>
<p>&nbsp;</P>
<p>3. 局部作用域</P>
<p>class C</P>
<p>&nbsp;&nbsp; a = 5</P>
<p>&nbsp;&nbsp; module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
a = 4</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
module N</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
a = 3</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
class D</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
a = 2</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def show_a</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
a = 1</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts a</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts a <b>#</B><b>输出 2</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts a <b>#</B><b>输出 3</B></P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;
puts a <b>#</B><b>输出 4</B></P>
<p>&nbsp;&nbsp; end</P>
<p>&nbsp;&nbsp; puts a <b>#</B><b>输出
5</B></P>
<p>&nbsp;end</P>
<p>&nbsp;</P>
<p>&nbsp;d = C::M::N::D.new</P>
<p>&nbsp;d.show_a <b>#</B><b>输出 1</B></P>
<p><b>&nbsp;</B></P>
<p>4. 常量的作用域和解析</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
X = 2</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
class D</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
module N</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
X = 1</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>puts M::C::D::N::X <b>#</B><b>输出 1</B></P>
<p>puts M::C::X <b>#</B><b>输出 2</B></P>
<p><b>&nbsp;</B></P>
<p>5. 强制使用绝对常量路径（::）</P>
<p>class Violin</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# Violin 中再创建一个 String 类</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
class String</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
attr_accessor :pitch</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def initialize(pitch)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@pitch = pitch</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
# 如果想调用 Ruby 自带的 String 类，则使用 ::String.new(args)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def history</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b>::String.new</B>(maker + ", " + Date)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>三、部署访问权限规则</H3>
<p>1. 私有方法：Ruby
通过禁止对私有方法使用显式的接收者来获得私有特性，在所有可以省略接收者的场合，调用私有方法是没问题的</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
private</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def sayHello</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "hello"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
#或者使用 private :sayHello</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 保护方法：只要默认对象（self）和你想调用的方法所属的对象是同一类的实例，你就可以调用该保护方法</P>
<p>class C</P>
<p>&nbsp; def initialize(n)</P>
<p>&nbsp;&nbsp;&nbsp; @n =
n</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>&nbsp; def n</P>
<p>&nbsp;&nbsp;&nbsp; @n</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>&nbsp; def compare(c)</P>
<p>&nbsp;&nbsp;&nbsp; if c.n
&gt; n</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "The other object's n is bigger."</P>
<p>&nbsp;&nbsp;&nbsp; else</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "The other object's n is the same or smaller."</P>
<p>&nbsp;&nbsp;&nbsp; end</P>
<p>&nbsp; end</P>
<p>&nbsp;</P>
<p>&nbsp; protected :n</P>
<p>end</P>
<p>&nbsp;</P>
<p>c1 = C.new(100)</P>
<p>c2 = C.new(101)</P>
<p>c1.compare(c2)</P>
<p>&nbsp;</P>
<p>3. 公有方法：默认的访问级别</P>
<p>&nbsp;</P>
<h3>四、编写和使用顶层方法</H3>
<p>1. 预定义的（内建的）顶层方法：如 puts 和 print 都是 Kernel 内建的私有实例方法。</P>
<p>2. 查看所有内建私有实例方法：puts Kernel.private_instance_methods.sort</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eopi.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:48:22 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eopi.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8549;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eopd.html</link>
            <description><![CDATA[<h2>第六章 模块和程序组织</H2>
<h3>一、创建和使用模块的基础知识</H3>
<p>1. 除了使用 module 关键字来替代 class 关键字之外，编写模块和编写类很相似</P>
<p>module MyFirstModule</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def say_hello</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Hello"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 使用模块</P>
<p>class ModuleTester</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include MyFirstModule</P>
<p>end</P>
<p>mt = ModuleTester.new</P>
<p>mt.say_hello</P>
<p>&nbsp;</P>
<h3>二、封装似栈特性的模块</H3>
<p>1. 封装具有似栈性的结构和行为的 Stacklike 模块（保存到 stacklike.rb 文件中）</P>
<p>module Stacklike</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
attr_reader :stack</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def initialize</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@stack = Array.new</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def add_to_stack(obj)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@stack.push(obj)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def take_from_stack</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@stack.pop</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 将 Stacklike 模块混含到 Stack 类中，使用 Stack 类的实例</P>
<p><b>require "stacklike"</B></P>
<p>class Stack</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b>include Stacklike</B></P>
<p>end</P>
<p>&nbsp;</P>
<p>s = Stack.new</P>
<p>&nbsp;</P>
<p>s.add_to_stack("item one")</P>
<p>s.add_to_stack("item two")</P>
<p>s.add_to_stack("item three")</P>
<p>&nbsp;</P>
<p>puts "Objects currently on the stack:"</P>
<p>puts s.stack</P>
<p>taken = s.take_from_stack</P>
<p>puts "Removed this object:"</P>
<p>puts taken</P>
<p>&nbsp;</P>
<p>puts "Now on stack:"</P>
<p>puts s.stack</P>
<p>&nbsp;</P>
<p>运行结果</P>
<p>Objects currently on the stack:</P>
<p>item one</P>
<p>item two</P>
<p>item three</P>
<p>Removed this object:</P>
<p>item three</P>
<p>Now on stack:</P>
<p>item one</P>
<p>item two</P>
<p>&nbsp;</P>
<h3>三、模块、类和方法查找</H3>
<p>1. 从对象角度看方法查找</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in module M"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
End</P>
<p>end</P>
<p>&nbsp;</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>end</P>
<p>&nbsp;</P>
<p>class D &lt; C</P>
<p>end</P>
<p>&nbsp;</P>
<p>obj = D.new</P>
<p>obj.report&nbsp;# <strong>输出：'report' method in
module M</STRONG></P>
<p>&nbsp;</P>
<p>类 D 的对象实例的方法查找过程图</P>
<p><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static5.photo.sina.com.cn/orignal/3ecb9b11t71bf773e97d4&amp;690" TARGET="_blank"><img SRC="http://static5.photo.sina.com.cn/bmiddle/3ecb9b11t71bf773e97d4&amp;690" /></A></P>
<p>&nbsp;</P>
<p>2. 一条方法查找路径上的两个同名方法</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in module M"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>class C</P>
<p>include M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in class C"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new</P>
<p>c.report # <strong>输出：'report' method in class C</STRONG></P>
<p>&nbsp;</P>
<p>3. 混含定义了同名方法的两个模块</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in module M"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>module N</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in module N"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include N</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new</P>
<p>c.report # <strong>输出：'report' method in module N</STRONG></P>
<p>&nbsp;</P>
<p>4. 用 super 提升方法查找路径</P>
<p>module M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in module M"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>class C</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
include M</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def report</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "'report' method in class C"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "About to trigger the next higher-up report method..."</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
super</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "Back from the 'super' call."</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<p>c = C.new</P>
<p>c.report</P>
<p>&nbsp;</P>
<p>输出结果</P>
<p>'report' method in class C</P>
<p>About to trigger the next higher-up report method...</P>
<p>'report' method in module M</P>
<p>Back from the 'super' call.</P>
<p>&nbsp;</P>
<h3>四、类／模块的设计和命名</H3>
<p>1. 使用类还是模块？</P>
<p>
（1）<b>模块没有实例。</B>因此实体或事物最好建模为类，而实体或事物的特性最好建模为模块，因此我们倾向于使用名词作为类名，使用形容词作为模块名。</P>
<p>
（2）<b>一个类中有一个父类，但它可以混含任意多个模块。</B>如果使用继承，要慎重考虑生成一个合理的父类／子类关系。如果使用一个类唯一的父类关系最后却发现几组特性中只有一个赋予了该类，那么这个关系还是不要用的好。</P>
<p>&nbsp;</P>
<p>2. 嵌套的模块和类</P>
<p>模块和类可以相互嵌套</P>
<p>module Tools</P>
<p>class Hammer</P>
<p>要产生定义在 Tools 模块中的 Hammer 类的实例，须用双冒号（::）访问该类</P>
<p>h = Tools::Hammer.new</P>
<p>&nbsp;</P>
<p>3. Rails 源代码中样版代码中的模块组织</P>
<p>class Composer &lt; ActiveRecord::Base</P>
<p>end</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eopd.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:42:51 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eopd.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8548;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eop3.html</link>
            <description><![CDATA[<h2>第五章 用类组织对象</H2>
<h3>一、类和实例</H3>
<p>1. 第一个类</P>
<p>class Ticket</P>
<p>end</P>
<p>ticket = Ticket.new</P>
<p>&nbsp;</P>
<p>2. 实例方法与单例方法</P>
<p>（1）在类中定义、供类的所有实例使用的方法，称为实例方法（Instance methods）</P>
<p>class Ticket</P>
<p>&nbsp; def event</P>
<p>&nbsp;&nbsp;&nbsp; "Can't
really be specified yet..."</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）为一个特定的对象定义的方法，称为单例方法（Singleton methods）</P>
<p>class Ticket</P>
<p>end</P>
<p>ticket = Ticket.new</P>
<p>def ticket.price</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
117.50</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 实例变量：使得单个对象可以记忆状态</P>
<p>class C</P>
<p>&nbsp; def inst_var_init(value)</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Setting an instance variable...."</P>
<p>&nbsp;&nbsp;&nbsp; <b>@ivar
= value</B></P>
<p>&nbsp; end</P>
<p>&nbsp; def inst_var_report</P>
<p>&nbsp;&nbsp;&nbsp; puts
"Inspecting the value of the instance variable...."</P>
<p>&nbsp;&nbsp;&nbsp; <b>puts
@ivar</B></P>
<p>&nbsp; end</P>
<p>end</P>
<p>c = C.new</P>
<p>c.inst_var_init("Just some string")</P>
<p>c.inst_var_report</P>
<p>&nbsp;</P>
<p>4. 初始化对象状态</P>
<p>class Ticket</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def initialize(venue,date)</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@venue = venue</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@date = date</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def venue</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@venue</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
def date</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@date</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
end</P>
<p>end</P>
<p>&nbsp;</P>
<h3>二、设置方法</H3>
<p>（1）改变对象状态（定义方法）</P>
<p>class Ticket</P>
<p>&nbsp; def initialize(venue, date)</P>
<p>&nbsp;&nbsp;&nbsp; @venue =
venue</P>
<p>&nbsp;&nbsp;&nbsp; @date =
date</P>
<p>&nbsp; end</P>
<p>&nbsp; def set_price(amount)</P>
<p>&nbsp;&nbsp;&nbsp; @price =
amount</P>
<p>&nbsp; end</P>
<p>&nbsp; def price</P>
<p>&nbsp;&nbsp;&nbsp;
@price</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>（2）语法糖衣（Syntactic sugar）</P>
<p>def price=(amount)</P>
<p>&nbsp; @price = amount</P>
<p>end</P>
<p>&nbsp;</P>
<p>调用写方法的语法糖衣</P>
<p>ticket.price=(65.00)</P>
<p>可以这样写：</P>
<p>ticket.price = 65.00</P>
<p>&nbsp;</P>
<h3>三、属性和 attr_* 方法族</H3>
<p>1. 产生获取和设置方法 attr_* 方法族的总结</P>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="142">
<p ALIGN="center"><strong>方法名</STRONG></P>
</TD>
<td WIDTH="142">
<p ALIGN="center"><strong>效果</STRONG></P>
</TD>
<td WIDTH="142">
<p ALIGN="center"><strong>例子</STRONG></P>
</TD>
<td WIDTH="142">
<p ALIGN="center"><strong>等价的代码</STRONG></P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="142">
<p>attr_reader</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>产生读方法</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>attr_reader :venue</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>def venue</P>
<p>@venue</P>
<p>end</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="142">
<p>attr_writer</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>产生写方法</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>attr_writer :price</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>def price=(price)</P>
<p>@price = price</P>
<p>end</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="142">
<p>attr_accessor</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>产生读写方法</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>attr_accessor :price</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>def price=(price)</P>
<p>@price = price</P>
<p>end</P>
<p>def price</P>
<p>@price</P>
<p>end</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="142">
<p>attr</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>产生读方法和可选的写方法（如果第二个参数为 true）</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>1. attr :venue</P>
<p>2. attr :price, true</P>
</TD>
<td VALIGN="top" WIDTH="142">
<p>1. 参见 attr_reader</P>
<p>2. 参见 attr_accessor</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>2.属性访问修饰符的使用</P>
<p>class Ticket</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
attr_accessor :venue, :date</P>
<p>end</P>
<p>&nbsp;</P>
<h3>四、类方法和 Class 类</H3>
<p>1. 类也是对象：类是唯一具有创建新对象（实例）的能力的一类对象</P>
<p>下面定义一个类方法，找出最贵的入场券</P>
<p>def Ticket.most_expensive(*tickets)</P>
<p>&nbsp; tickets.sort_by {|t| t.price }.last</P>
<p>end</P>
<p>&nbsp;</P>
<p>我们可以用该方法找出哪张入场券是最贵的</P>
<p>th = Ticket.new("Town Hall","11/12/13")</P>
<p>cc = Ticket.new("Convention Center","12/13/14/")</P>
<p>fg = Ticket.new("Fairgrounds", "13/14/15/")</P>
<p>th.price = 12.55</P>
<p>cc.price = 10.00</P>
<p>fg.price = 18.00</P>
<p>highest = Ticket.most_expensive(th,cc,fg)</P>
<p>puts "The highest-priced ticket is #{highest.venue}."</P>
<p>&nbsp;</P>
<p>2. 类方法的调用方式</P>
<p>Ticket.most_expensive 或 Ticket::most_expensive</P>
<p>&nbsp;</P>
<h3>五、常量</H3>
<p>常量的名字以一个大写字母开头</P>
<p>class Ticket</P>
<p>&nbsp; VENUES = ["Convention Center", "Fairgrounds",
"Town Hall"]</P>
<p>end</P>
<p>puts Ticket::VENUES</P>
<p>&nbsp;</P>
<h3>六、继承</H3>
<p>1. 抽象事物和特殊事物之间的关系可以通过继承（inheritance）来表达</P>
<p>class Publication</P>
<p>&nbsp; attr_accessor :publisher</P>
<p>end</P>
<p>&nbsp;</P>
<p>class Magazine &lt; Publication</P>
<p>ddattr_accessor :editor</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 继承和 Rails 设计</P>
<p>class ComposerController &lt;
ApplicationController</P>
<p>end</P>
<p>&nbsp;</P>
<p>class ApplicationController &lt;
ActionController::Base</P>
<p>&nbsp;</P>
<p>class Composer &lt; ActiveRecord::Base</P>
<p>&nbsp;</P>
<h3>七、Object 类</H3>
<p>Object 类位于继承树的顶部。每一个类都是 Object 的直系后代</P>
<p>class C</P>
<p>end</P>
<p>&nbsp;</P>
<p>class D &lt; C</P>
<p>end</P>
<p>&nbsp;</P>
<p>puts D.superclass</P>
<p>puts D.superclass.superclass</P>
<p>&nbsp;</P>
<p>输出为：</P>
<p>C</P>
<p>Object</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eop3.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:37:14 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eop3.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8547;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eoov.html</link>
            <description><![CDATA[<h1>第二部分 Ruby 构造块</H1>
<h2>第四章 对象和变量</H2>
<h3>一、对象</H3>
<p>1. 创建类的实例——对象</P>
<p>obj = Object.new</P>
<p>&nbsp;</P>
<p>2. 定义对象方法</P>
<p>def obj.talk</P>
<p>&nbsp; puts "I am an object."</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
puts "(Do you object?)"</P>
<p>end</P>
<p>&nbsp;</P>
<p>3. 给对象发送消息</P>
<p>object.message</P>
<p>&nbsp;</P>
<p>4. 接受参数的方法</P>
<p>def obj.c2f(c)</P>
<p>&nbsp; c * 9 / 5 + 32</P>
<p>end</P>
<p># puts obj.c2f(100)</P>
<p>&nbsp;</P>
<p>5. 方法的返回值，通常不需要 return（该关键字是可选的）</P>
<p>def obj.c2f(c)</P>
<p>&nbsp; <b><i>return</I></B> c * 9 / 5 + 32</P>
<p>end</P>
<p>&nbsp;</P>
<h3>二、对象固有行为</H3>
<p>1. 列出对象的固有方法清单：</P>
<p>p Object.new.methods.sort</P>
<p>["==", "===", "=~", "__id__", "__send__", "class",</P>
<p>"clone", "display", "dup", "eql?", "equal?", "extend",</P>
<p>"freeze", "frozen?", "hash", "id", "inspect",</P>
<p>"instance_", "instance_of?", "instance_variable_get",</P>
<p>"instance_variable_set", "instance_variables", "is_a?",</P>
<p>"kind_of?", "method", "methods", "nil?", "object_id",</P>
<p>"private_methods", "protected_methods", "public_methods",</P>
<p>"respond_to?", "send", "singleton_methods", "taint",</P>
<p>"tainted?", "to_a", "to_s", "type", "untaint"]</P>
<p>&nbsp;</P>
<p>2. 用 object_id 方法唯一标识对象</P>
<p>（1）两个变量引用同一对象 object_id 相同</P>
<p>a = Object.new</P>
<p>b = a</P>
<p>puts "a's id is #{a.object_id} and b's id is
#{b.object_id}."</P>
<p>&nbsp;</P>
<p>（2）两个值相同的字符串对象 object_id 不相同</P>
<p>string_1 = "Hello"</P>
<p>string_2 = "Hello"</P>
<p>puts "string_1's id is #{string_1.object_id}."</P>
<p>puts "string_2's id is #{string_2.object_id}."</P>
<p>&nbsp;</P>
<p>3. 用 respond_to? 方法查询对象是否拥有该方法</P>
<p>obj = Object.new</P>
<p>obj.talk</P>
<p>Ruby 会告诉你：</P>
<p>undefined method 'talk' for
#&lt;Object:0x401aa18c&gt;
(NoMethodError)</P>
<p>&nbsp;</P>
<p>使用respond_to?方法可以事先判定对象是否能响应给定的消息。respond_to?常常与条件（if）逻辑一起出现</P>
<p>obj = Object.new</P>
<p>if obj.respond_to?("talk")</P>
<p>&nbsp; obj.talk</P>
<p>else</P>
<p>&nbsp; puts "Sorry, the object doesn't understand
the 'talk' message."</P>
<p>end</P>
<p>&nbsp;</P>
<p>4. 用 send 方法给对象发送消息</P>
<p>if ticket.respond_to?(request)</P>
<p>&nbsp; puts ticket.send(request)</P>
<p>else</P>
<p>&nbsp; puts "No such information available"</P>
<p>end</P>
<p>&nbsp;</P>
<p>5. 必需参数、可选参数以及默认值参数</P>
<p>（1）必需参数</P>
<p>def obj.one_arg(x)</P>
<p>end</P>
<p>obj.one_arg(1,2,3)</P>
<p>结果是：</P>
<p>ArgumentError: wrong number of arguments (3 for 1)</P>
<p>&nbsp;</P>
<p>（2）可选参数</P>
<p>def obj.multi_args(*x)</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）混合使用必需参数和可选参数</P>
<p>def two_or_more(a,b,*c)</P>
<p>&nbsp;</P>
<p>（5）参数的默认值</P>
<p>def default_args(a,b,c=1)</P>
<p>&nbsp; puts "Values of variables: ",a,b,c</P>
<p>end</P>
<p>&nbsp;</P>
<p>（6）参数的顺序</P>
<p>def opt_args(a,b,*x)&nbsp; # 正确</P>
<p>def opt_args(a,*x,b)&nbsp; # 错误</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eoov.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:31:57 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eoov.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8546;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eooq.html</link>
            <description><![CDATA[<h2>第三章 了解 Ruby 前提下的 Rails 开发</H2>
<h3>一、YAML 和实际为编程的配置</H3>
<p>YAML （按 UNIX 平台的传统，最初代表 Yet Another Markup Language，现在却代表 YAML
Ain’t Markup
Language）可以说是一个标记语言，也可以说是一个串行化格式，取决于你看问题的角度。下面是一个简单的例子：一个嵌套的数组结构转变成一个
YAML 表示，然后再由它恢复成一个数组：</P>
<p>require 'yaml'</P>
<p>array = [1, 2, 3, [4, "five", :six]]</P>
<p>puts "Original array:"</P>
<p>puts array.inspect</P>
<p>yarray = array.to_yaml</P>
<p>puts "YAML representation of array: "</P>
<p>puts yarray</P>
<p>thawed = YAML.load(yarray)</P>
<p>puts "Array re-loaded from YAML string: "</P>
<p>p thawed</P>
<p>（此例中，inspect 方法为对象产生一个详细的字符串表示；还有 p 方法，等价于 puts）。</P>
<p>运行这段脚本的输出如下：</P>
<p>Original array:</P>
<p>[1, 2, 3, [4, "five", :six]]</P>
<p>YAML representation of array:</P>
<p>---</P>
<p>- 1</P>
<p>- 2</P>
<p>- 3</P>
<p>- - 4</P>
<p>&nbsp; - five</P>
<p>&nbsp; - :six</P>
<p>Array re-loaded from YAML string:</P>
<p>[1, 2, 3, [4, "five", :six]]</P>
<p>&nbsp;</P>
<p>Rails 在几种上下文中使用 YAML，在 database.yml 中会看到如下的块：</P>
<p>development:</P>
<p>&nbsp; adapter: mysql</P>
<p>&nbsp; database: r4rmusic1_development</P>
<p>&nbsp; username: r4r</P>
<p>&nbsp; password: railzrulez</P>
<p>&nbsp; socket: /tmp/mysql.sock</P>
<p>&nbsp;</P>
<p>将这些行放到一个文件（如sample.yml）中，然后运行下面命令：</P>
<p>F:\ruby_project&gt;ruby -ryaml -e 'p
YAML.load(File.read("sample.rb"))'</P>
<p>{"development" =&gt;
{"socket"=&gt;"/tmp/mysql.sock",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"username"=&gt;"r4r",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"adapter"=&gt;"mysql",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"password"=&gt;"railzrulez",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"database"=&gt;"r4rmusic1_development"</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</P>
<p>}</P>
<p>&nbsp;</P>
<h3>二、给控制器增加功能</H3>
<p>通过点击合适的列标题，可以让列表以不同的方式排序（按标题，按作者，按状态）：</P>
<p>def all</P>
<p>&nbsp; @order = params[:order] || "number"</P>
<p>&nbsp; sort_proc = case @order</P>
<p>&nbsp;&nbsp;&nbsp; when
"author"&nbsp; then lambda {|r| [r.user.name.downcase,
r.number] }</P>
<p>&nbsp;&nbsp;&nbsp; when
"status",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"title"&nbsp;&nbsp; then lambda {|r|
[r.send(@order).downcase, r.number]}</P>
<p>&nbsp;&nbsp;&nbsp; when
"number"&nbsp; then lambda {|r| -r.number }</P>
<p>&nbsp; end</P>
<p>&nbsp; @rcrs = Rcr.find(:all).sort_by
&amp;sort_proc</P>
<p>end</P>
<p>&nbsp;</P>
<p>
变量@order（一个实例变量）设置为CGI变量order的值；如果该CGI变量的值没有设置，则它的默认值是字符串"number"。然后，变量sort_proc（排序过程）被设置为三个可能的lambda表达式（匿名函数）中的一个。选择哪一个lambda表达式取决于@order的值，这个选择是通过一个case语句来执行的。</P>
<p>&nbsp;</P>
<p>
一旦选定了正确的lambda表达式，所有现存的RCR将根据该lambda表达式的逻辑排序，这个排序需使用ActiveRecord的find方法来获取所有的RCR，以及根据sort_proc中保存的lambda表达式来使用Ruby的sort_by方法过滤这个列表。</P>
<p>&nbsp;</P>
<p>如果了解Ruby，则该方法很容易编写。但是一定要了解Ruby！确切地说，需要了解下面这些内容：</P>
<p>case语句；</P>
<p>lambda关键字，用它生成一个匿名函数；</P>
<p>send方法（请注意status和title是怎样一起处理的）；</P>
<p>sort_by方法，需要给它传递一个lambda表达式。</P>
<p>&nbsp;</P>
<h3>三、部署 Rails 的辅助文件</H3>
<p>Rails 对每一个控制器都会自动产生一个辅助文件，可以编写任意多的 Ruby 方法。位于 app\helpers 下。</P>
<p>&nbsp;</P>
<p>
下面是一个从RCRchive列表排序代码中提取的例子。在RCR的每一个视图中的每一个列标题，都超链接到rcr/all动作。这些链接只在一个方面有区别：order参数的值（“author”、“title”、“number”或“Status”）。这意味着这四个链接使用几乎完全相同的代码。为减少重复，可用一个辅助方法自动产生合适的链接。你所需要做的仅仅是传递给它一个order参数。</P>
<p>&nbsp;</P>
<p>该辅助方法定义在文件rcr_helper.rb中，如下所示：</P>
<p>def link_to_order(order)</P>
<p>&nbsp; link_to(order.capitalize,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "rcr",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "all",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:params&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; { "order" =&gt; order })</P>
<p>end</P>
<p>&nbsp;</P>
<p>在视图（app/views/rcr/all.rhtml）中，下面四行产生表的列标题：</P>
<p>&lt;th class="rcr"&gt;&lt;%=
link_to_order("number")
%&gt;&lt;/th&gt;</P>
<p>&lt;th class="rcr"&gt;&lt;%=
link_to_order("title")
%&gt;&lt;/th&gt;</P>
<p>&lt;th class="rcr"&gt;&lt;%=
link_to_order("status")
%&gt;&lt;/th&gt;</P>
<p>&lt;th class="rcr"&gt;&lt;%=
link_to_order("author")
%&gt;&lt;/th&gt;</P>
<p>&nbsp;</P>
<h3>四、给模型增加功能</H3>
<p>1. 实现预定义的回调方法</P>
<p>
如果在一个ActiveRecord模型文件中编写一个名为before_create的方法，该方法会在该模型的实例的数据库记录产生之前被执行。</P>
<p>
如果description字段有默认的字符串值，那应该更好。如果在数据库记录首次产生的时候，该edition不存在描述信息，让我们给它一个默认值"standard"。</P>
<p>def before_create</P>
<p>&nbsp; self.description = "standard" unless
description</P>
<p>end</P>
<p>&nbsp;</P>
<p>2. 自由形式的编程的模型改进</P>
<p>假设在一个视图模板中，变量@customer包含一个客户对象，你可以像下面这样显示这个人的名字：</P>
<p>&lt;p&gt;Hello, &lt;%=
@customer.title + " " + @customer.first_name + " " +</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@customer.middle_initial + ". " +</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@customer.last_name"
%&gt;&lt;/p&gt;</P>
<p>&nbsp;</P>
<p>下面让 customer 对象自己产生该名字的友好板本：</P>
<p>class Customer &lt; ActiveRecord::Base</P>
<p>&nbsp; def nice_name</P>
<p>&nbsp;&nbsp;&nbsp; title + "
" + first_name + " " +</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(if middle_initial then middle_initial + ". " else "" end) +</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
last_name</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>下面可以在视图中直接调用 @customer 中该实例的方法：</P>
<p>&lt;p&gt;Good morning,
&lt;%= @customer.nice_name
%&gt;.&lt;/p&gt;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eooq.html#comment</comments>
            <pubDate>Wed, 19 Aug 2009 08:25:59 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eooq.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8545;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eoee.html</link>
            <description><![CDATA[<h2>第二章 Rails 工作原理</H2>
<h3>一、Rails 的 MVC 框架设计实现概览</H3>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td WIDTH="83">
<p ALIGN="center">MVC 阶段</P>
</TD>
<td WIDTH="142">
<p ALIGN="center">Rails 子库</P>
</TD>
<td WIDTH="344">
<p ALIGN="center">目的</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">模型</P>
</TD>
<td WIDTH="142">
<p ALIGN="center">ActiveRecord</P>
</TD>
<td VALIGN="top" WIDTH="344">
<p>在关系数据库表和操作数据库记录的Ruby程序代码之间提供接口和绑定。Ruby方法名自动从数据库表的字段名产生，等等</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">视图</P>
</TD>
<td WIDTH="142">
<p ALIGN="center">ActionView</P>
</TD>
<td VALIGN="top" WIDTH="344">
<p>
一个基于嵌入式Ruby（ERb）的系统，用于定义服务于数据表示的表示模板。对Rails应用的每一次Web连接都导致显示一个视图</P>
</TD>
</TR>
<tr>
<td WIDTH="83">
<p ALIGN="center">控制器</P>
</TD>
<td WIDTH="142">
<p ALIGN="center">ActionController</P>
</TD>
<td VALIGN="top" WIDTH="344">
<p>
在ActiveRecord（数据库接口）和ActionView（表示引擎）之间的数据中介。ActionController提供功能设施，处理和组织来自数据库和Web表单输入的数据，然后它将这些数据递交给ActionView，ActionView将这些数据插入模板并显示</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<h3>二、图解 Ruby 和 Rails 框架</H3>
<p>&nbsp;</P>
<p>&nbsp;<a href="http://blog.photo.sina.com.cn/showpic.html#url=http://static9.photo.sina.com.cn/orignal/3ecb9b11t7168f9d9af48&amp;690" TARGET="_blank"><img SRC="http://static9.photo.sina.com.cn/bmiddle/3ecb9b11t7168f9d9af48&amp;690" /></A></P>
<h3>三、全程开发 Rails 应用，音乐店应用——R4Rmusic（PS：完整版攻略）</H3>
<p>Google Code 下载：<a HREF="http://kerryas.googlecode.com/files/R4Rmusic1.rar">http://kerryas.googlecode.com/files/R4Rmusic1.rar</A></P>
<p>&nbsp;</P>
<p><b>1.</B> <b>生成音乐店的数据库表 SQL</B> <b>命令</B></P>
<p>CREATE DATABASE r4rmusic1;</P>
<p>USE r4rmusic1;</P>
<p>DROP TABLE IF EXISTS works;</P>
<p>DROP TABLE IF EXISTS editions;</P>
<p>DROP TABLE IF EXISTS composers;</P>
<p>CREATE TABLE works (</P>
<p>&nbsp; id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>&nbsp; composer_id INT(11),</P>
<p>&nbsp; title VARCHAR(100),</P>
<p>&nbsp; PRIMARY KEY (id)</P>
<p>);</P>
<p>CREATE TABLE editions (</P>
<p>&nbsp; id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>&nbsp; work_id INT(11) NOT NULL,</P>
<p>&nbsp; description VARCHAR(30),</P>
<p>&nbsp; publisher VARCHAR(60),</P>
<p>&nbsp; YEAR INT(4),</P>
<p>&nbsp; price FLOAT,</P>
<p>&nbsp; PRIMARY KEY&nbsp; (id)</P>
<p>);</P>
<p>CREATE TABLE composers (</P>
<p>&nbsp; id INT(11) NOT NULL AUTO_INCREMENT,</P>
<p>&nbsp; first_name VARCHAR(25),</P>
<p>&nbsp; last_name VARCHAR(25),</P>
<p>&nbsp; PRIMARY KEY (id)</P>
<p>);</P>
<p>&nbsp;</P>
<p><b>2.</B> <b>产生音乐店示例库存数据的 SQL</B> <b>命令</B></P>
<p>INSERT INTO composers</P>
<p>&nbsp; VALUES (1,"Johannes","Brahms");</P>
<p>INSERT INTO composers</P>
<p>&nbsp; VALUES (2,"Claude","Debussy");</P>
<p>&nbsp;</P>
<p>INSERT INTO works</P>
<p>&nbsp; VALUES (1,1,"Sonata for Cello and Piano in F
Major");</P>
<p>INSERT INTO works</P>
<p>&nbsp; VALUES (2,2,"String Quartet");</P>
<p>&nbsp;</P>
<p>INSERT INTO editions</P>
<p>&nbsp; VALUES (1,1,"Facsimile","D. Black Music
House", 1998, 21.95);</P>
<p>INSERT INTO editions</P>
<p>&nbsp; VALUES (2,1,"Urtext","RubyTunes, Inc.", 1977,
23.50);</P>
<p>INSERT INTO editions</P>
<p>&nbsp; VALUES (3,1,"ed. Y.Matsumoto","RubyTunes,
Inc.", 2001, 22.95);</P>
<p>INSERT INTO editions</P>
<p>&nbsp; VALUES (4,2,"","D. Black Music House", 1995,
39.95);</P>
<p>INSERT INTO editions</P>
<p>&nbsp; VALUES (5,2,"Reprint of 1894 ed.",
"RubyTunes, Inc.", 2003, 35.95);</P>
<p>&nbsp;</P>
<p>3. 创建 R4Rmusic1 项目（数据库基于Mysql）</P>
<p>F:\ruby_project&gt;<b>rails -d mysql
R4Rmusic1</B></P>
<p>F:\ruby_project&gt;<b>cd R4Rmusic1</B></P>
<p>&nbsp;</P>
<p>4. 初始设置及测试</P>
<p>（1）配置数据库文件 config/database.yml</P>
<p>development:</P>
<p>&nbsp; adapter: mysql</P>
<p>&nbsp; encoding: utf8</P>
<p>&nbsp; reconnect: false</P>
<p>&nbsp; <b>database: R4Rmusic1</B></P>
<p>&nbsp; pool: 5</P>
<p><b>&nbsp; username: root</B></P>
<p><b>&nbsp; password:</B></P>
<p><b>&nbsp; host: localhost</B></P>
<p>&nbsp;</P>
<p>（2）启动 WEBrick 应用服务器</P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby
script\server</B></P>
<p>=&gt; Booting WEBrick</P>
<p>=&gt; Rails 2.3.3 application starting on
http://0.0.0.0:3000</P>
<p>=&gt; Call with -d to detach</P>
<p>=&gt; Ctrl-C to shutdown server</P>
<p>[2009-08-16 14:40:31] INFO &nbsp;WEBrick 1.3.1</P>
<p>[2009-08-16 14:40:31] INFO&nbsp; ruby 1.8.6
(2008-08-11) [i386-mswin32]</P>
<p>[2009-08-16 14:40:31] INFO&nbsp;
WEBrick::HTTPServer#start: pid=988 port=3000</P>
<p>&nbsp;</P>
<p>（3）测试服务</P>
<p>访问：<a HREF="http://localhost:3000/">http://localhost:3000/</A></P>
<p>点击：About your application’s environment
测试是否列出应用的环境列表，如果是则服务正确，如果出错需要访问log/development.log 查找原因。</P>
<p>&nbsp;</P>
<p>5. 创建 Rails 模型文件</P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
model work</B></P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
model edition</B></P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
model composer</B></P>
<p>执行后会在 app/model 目录下生成这三个模型文件：work.rb, edition.rb,
composer.rb</P>
<p>&nbsp;</P>
<p><b>将 work.rb</B> <b>修改如下：</B></P>
<p>class Work &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
belongs_to :composer</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_many :editions</P>
<p>end</P>
<p>&nbsp;</P>
<p><b>将 edition.rb</B> <b>修改如下：</B></P>
<p>class Edition &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
belongs_to :work</P>
<p>end</P>
<p>&nbsp;</P>
<p><b>将 composer.rb</B> <b>修改如下：</B></P>
<p>class Composer &lt; ActiveRecord::Base</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
has_many :works</P>
<p>end</P>
<p>&nbsp;</P>
<p>6. 创建访问主界面</P>
<p>（1）创建主界面视图及控制器</P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
controller main welcome</B></P>
<p><b>&nbsp;</B></P>
<p>（2）将 app\controllers\main_controller.rb 修改如下（编写控制器）：</P>
<p>class MainController &lt; ApplicationController</P>
<p>&nbsp; def welcome</P>
<p>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
#@composers = Composer.find(:all)</P>
<p>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
@composers = Composer.find(:all).sort_by {|c| [c.last_name,
c.first_name]}</P>
<p>&nbsp; end</P>
<p>end</P>
<p>&nbsp;</P>
<p>（3）将 app\views\main\welcome.html.erb 修改如下（编写视图）：</P>
<p>&lt;p&gt;Click on a composer's name</P>
<p>to see all of that composer's
works.&lt;/p&gt;</P>
<p>&lt;ul&gt;</P>
<p>&nbsp; &lt;% @composers.each do
|composer| %&gt;</P>
<p>&nbsp;
&lt;li&gt;&lt;%= link_to
"#{composer.first_name} #{composer.last_name}",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "composer",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; composer.id %&gt;</P>
<p>&nbsp; &lt;/li&gt;</P>
<p>&nbsp; &lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>（4）R4RMusic基本布局（在app\views\layouts 中创建base.html.erb）</P>
<p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN"</P>
<p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</P>
<p>&lt;html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en"&gt;</P>
<p>&lt;head&gt;</P>
<p>&nbsp;
&lt;title&gt;&lt;%= @page_title
%&gt;&lt;/title&gt;</P>
<p>&lt;/head&gt;</P>
<p>&lt;body&gt;</P>
<p>&lt;h1 class="banner"&gt;The R4R Music
Store&lt;/h1&gt;</P>
<p>
<b>&nbsp;&nbsp;&nbsp;&lt;%=
@content_for_layout %&gt;</B></P>
<p>&lt;hr/&gt;</P>
<p>&lt;p&gt;Copyright
&amp;copy; 2006,
R4RMusic&lt;/p&gt;</P>
<p>&lt;/body&gt;</P>
<p>&lt;/html&gt;</P>
<p>&nbsp;</P>
<p>（5）将默认布局加入到 app\controllers\ application_controller.rb 中</P>
<p>class ApplicationController &lt;
ActionController::Base</P>
<p>&nbsp; <b>layout "base"</B></P>
<p>end</P>
<p>&nbsp;</P>
<p>（6）设置应用程序入口文件，在 config/routes.rb 中加入配置：</P>
<p>map.connect '', :controller =&gt; "main", :action
=&gt; "welcome"</P>
<p>&nbsp;</P>
<p>（7）删除public/index.html（Rails 应用默认入口），重启 WEBrick 测试。</P>
<p>&nbsp;</P>
<p>7. 创建作品、版本及作曲者的控制器</P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
controller work show</B></P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
controller edition show</B></P>
<p>F:\ruby_project\R4Rmusic1&gt;<b>ruby script/generate
controller composer show</B></P>
<p>&nbsp;</P>
<p>修改 app\controllers\work_controller.rb</P>
<p>def show</P>
<p>&nbsp;&nbsp;&nbsp; @work =
Work.find(params[:id])</P>
<p>end</P>
<p>&nbsp;</P>
<p>修改 app\controllers\edition_controller.rb</P>
<p>def show</P>
<p>&nbsp;&nbsp;&nbsp; @edition
= Edition.find(params[:id])</P>
<p>end</P>
<p>&nbsp;</P>
<p>修改 app\controllers\composer_controller.rb</P>
<p>def show</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;@composer
= Composer.find(params[:id])</P>
<p>end</P>
<p>&nbsp;</P>
<p>8. 创建作品、版本及作曲者的视图</P>
<p>（1）将 app\views\work\show.html.erb</P>
<p>&lt;p&gt;Available editions of</P>
<p>&nbsp;&lt;%= @work.title
%&gt; by</P>
<p>&nbsp;&lt;%=
"#{@work.composer.first_name} #{@work.composer.last_name}"
%&gt;</P>
<p>&lt;/p&gt;</P>
<p>&lt;table&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Edition&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Publisher&lt;/th&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&nbsp; &lt;% @work.editions.each do |ed|
%&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= link_to
ed.description || "(no descr.)",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "edition",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; ed.id
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= ed.publisher
%&gt;&lt;/td&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&nbsp; &lt;% end %&gt;</P>
<p>&lt;/table&gt;</P>
<p>&nbsp;</P>
<p>（2）将 app\views\edition\show.html.erb</P>
<p>&lt;% @page_title =</P>
<p>&nbsp;&nbsp; "#{@edition.work.title}
(#{@edition.description})" %&gt;</P>
<p>&lt;p&gt;Details of &lt;%=
@edition.work.title %&gt;</P>
<p>(&lt;%= @edition.description %&gt;),</P>
<p>by</P>
<p>&lt;%= "#{@edition.work.composer.first_name}</P>
<p>&nbsp;&nbsp;
#{@edition.work.composer.last_name}"
%&gt;&lt;/p&gt;</P>
<p>&lt;table border="1"&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Publisher&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Year&lt;/th&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;th&gt;Price&lt;/th&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&nbsp; &lt;tr&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%=
@edition.publisher
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;&lt;%= @edition.year
%&gt;&lt;/td&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;td&gt;$&lt;%=
@edition.price
%&gt;&lt;/td&gt;</P>
<p>&nbsp; &lt;/tr&gt;</P>
<p>&lt;/table&gt;</P>
<p>&nbsp;</P>
<p>（3）将 app\views\composer\show.html.erb</P>
<p>&lt;% @page_title =</P>
<p>&nbsp;&nbsp; "Works by
#{@composer.first_name} #{@composer.last_name}"
%&gt;</P>
<p>&lt;p&gt;Click on any work to see all
available editions of that
work.&lt;/p&gt;</P>
<p>&lt;ul&gt;</P>
<p>&nbsp; &lt;% @composer.works.each do
|work| %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;li&gt;&lt;%= link_to
work.title,</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:controller =&gt; "work",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:action&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; "show",</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
:id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
=&gt; work.id %&gt;</P>
<p>&nbsp;&nbsp;&nbsp;
&lt;/li&gt;</P>
<p>&nbsp; &lt;% end %&gt;</P>
<p>&lt;/ul&gt;</P>
<p>&nbsp;</P>
<p>8. 最后，重新启动 WEBrick 服务器，第一个 R4RMusic 应用完成。</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eoee.html#comment</comments>
            <pubDate>Tue, 18 Aug 2009 13:13:20 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eoee.html</guid>
        </item>
        <item>
            <title>[RoR] Ruby for Rails 最佳实践&amp;#8544;[FL车在臣]</title>
            <link>http://blog.sina.com.cn/s/blog_3ecb9b110100eobv.html</link>
            <description><![CDATA[<h1 STYLE="MArGin: 17pt 0cm 16.5pt" ALIGN="center"><a HREF="http://blog.photo.sina.com.cn/showpic.html#url=http://static8.photo.sina.com.cn/orignal/3ecb9b11t7167d8fbd7b7&amp;690" TARGET="_blank"><img SRC="http://static8.photo.sina.com.cn/bmiddle/3ecb9b11t7167d8fbd7b7&amp;690" /></A></H1>
<p><b>下载 Ruby</B>：<a HREF="http://rubyforge.org/frs/?group_id=167" TARGET="_blank">http://rubyforge.org/frs/?group_id=167</A></P>
<p><b>安装 Rails</B>：gem install rails --remote</P>
<p><b>安装 Mysql</B> <b>驱动</B>：gem install mysql</P>
<p>&nbsp;</P>
<h1>第一部分 Ruby/Rails 全景</H1>
<h2>第一章 Ruby 工作原理</H2>
<h3>一、编写第一个程序文件：</H3>
<p>1. 摄氏—华氏温度转换程序（F:\ruby_project\c2f.rb）</P>
<p><b>c = 100</B></P>
<p><b>f = (c * 9 / 5) + 32</B></P>
<p><b>puts "The result is: "</B></P>
<p><b>puts f</B></P>
<p><b>puts "."</B></P>
<p>&nbsp;</P>
<p>2. 语法错误检查</P>
<p>F:\ruby_project&gt;<b>ruby -cw c2f.rb</B></P>
<p>Syntax OK</P>
<p>&nbsp;</P>
<p>3. 运行程序</P>
<p>F:\ruby_project&gt;<b>ruby c2f.rb</B></P>
<p>The result is:</P>
<p>212</P>
<p>.</P>
<p>&nbsp;</P>
<h3>二、交互式温度转换程序（F:\ruby_project\c2fi.rb）</H3>
<p>print "Hello. Please enter a Celsius value: "</P>
<p>c = gets</P>
<p>f = (c.to_i * 9 / 5) + 32</P>
<p>puts "The Fahrenheit equivalent is "</P>
<p>puts f</P>
<p>puts "."</P>
<p>===================================================</P>
<p>缩减代码：</P>
<p><b>print "Hello. Please enter a Celsius value: "</B></P>
<p><b>print "The Fahrenheit equivalent is ", gets.to_i * 9 / 5 +
32, ".\n"</B></P>
<p>===================================================</P>
<p>F:\ruby_project&gt;ruby c2fi.rb</P>
<p>Hello. Please enter a Celsius value: 100</P>
<p>The Fahrenheit equivalent is 212.</P>
<p>F:\ruby_project&gt;ruby c2fi.rb</P>
<p>Hello. Please enter a Celsius value: 23</P>
<p>The Fahrenheit equivalent is 73.</P>
<p>&nbsp;</P>
<h3>三、文件输入式温度转换程序（F:\ruby_project\c2fin.rb）</H3>
<p>print "Reading Celsius temperature value from data file..."</P>
<p>num = File.read("temp.dat")</P>
<p>c = num.to_i</P>
<p>f = (c * 9 / 5) + 32</P>
<p>puts "The number is " + num</P>
<p>print "Result: "</P>
<p>puts f</P>
<p>&nbsp;</P>
<h3>四、使用文件输出的温度转换程序（F:\ruby_project\c2fout.rb）</H3>
<p>print "Hello. Please enter a Celsius vallue: "</P>
<p>c = gets.to_i</P>
<p>f = (c * 9 / 5) + 32</P>
<p>puts "Saving result to output file 'temp.out'"</P>
<p>fh = File.new("temp.out", "w")</P>
<p>fh.puts f</P>
<p>fh.close</P>
<p>&nbsp;</P>
<h3>五、一个程序，多个文件</H3>
<p>1. 请求加载文件 require：</P>
<p>puts "This is the first (master) program file."</P>
<p><b>require 'requiree.rb'</B></P>
<p>puts "And back again to the first file."</P>
<p>&nbsp;</P>
<p>2. 加载文件 load：</P>
<p>load 是 require 的近亲。它们的主要区别在于，如果执行下面代码：</P>
<p><b>require 'requiree.rb'</B></P>
<p><b>require 'requiree.rb'</B></P>
<p>第二次执行 require 什么都不会发生，而如果执行下面代码：</P>
<p><b>load 'requiree.rb'</B></P>
<p><b>load 'requiree.rb'</B></P>
<p>Ruby 会两次读入该文件</P>
<p>&nbsp;</P>
<h3>六、ruby 解释起的命令行开关&nbsp;</H3>
<table CELLSPACING="0" CELLPADDING="0" BORDER="1">
<tbody>
<tr>
<td VALIGN="top" WIDTH="83">
<p ALIGN="center">命令行开关</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p ALIGN="center">描述</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p ALIGN="center">例子</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-c</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>不执行程序，只检查程序语法</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -c c2f.rb</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-w</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>在程序执行过程中给出警告信息</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -w c2f.rb</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-e</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>执行在命令行中引号内的代码</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -e 'puts "code demo!"'</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-v</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>显示Ruby版本信息，在详细模式下执行程序</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -v</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-l</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>行模式：如果没有换行则在每一行后输出换行</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -l -e 'print "Will jump!"'</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>-rname</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>加载指定的扩展</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby -r profile</P>
</TD>
</TR>
<tr>
<td VALIGN="top" WIDTH="83">
<p>--version</P>
</TD>
<td VALIGN="top" WIDTH="284">
<p>显示Ruby版本信息</P>
</TD>
<td VALIGN="top" WIDTH="202">
<p>ruby --version</P>
</TD>
</TR>
</TBODY>
</TABLE>
<p>&nbsp;</P>
<p>&nbsp;</P>
<h3>七、重要的标准 Ruby 工具和应用程序</H3>
<p>1. 调试器，Ruby 运行这个例子时加载了 debug 扩展</P>
<p>F:\ruby_project&gt;<b>ruby -r debug c2fi.rb</B></P>
<p>Debug.rb</P>
<p>Emacs support available.</P>
<p>&nbsp;</P>
<p>2. 性能分析</P>
<p>F:\ruby_project&gt;<b>ruby -r profile
c2fi.rb</B></P>
<p>&nbsp;</P>
<p>3. ri和RDoc</P>
<p>（1）ri（Ruby 索引）：命令行工具，获取关于Ruby的详细信息，如：</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ri require</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
获取 require 功能的完整的、官方的描述</P>
<p>（2）RDoc（Ruby 文档）：根据注释内容建立索引</P>
<p>&nbsp;</P>
<p>4. ERb （Embedded Ruby）：允许将 Ruby 代码嵌入 HTML 文件</P>
<p>（1）ERb 实例（erbdemo.rb）</P>
<p>&lt;% page_title = "Demonstration of ERb"
%&gt;</P>
<p>&lt;% salutation = "Dear programmer,"
%&gt;</P>
<p>&lt;html&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;head&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;title&gt;&lt;%= page_title
%&gt;&lt;/title&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/head&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;body&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;p&gt;&lt;%= salutation
%&gt;&lt;/p&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;p&gt;This is a bref demonstration of
how ERb fills out a template.&lt;/p&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/body&gt;</P>
<p>&lt;/html&gt;</P>
<p>&nbsp;</P>
<p>（2）F:\ruby_project&gt;<b>erb erbdemo.rb</B></P>
<p>&lt;html&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;head&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;title&gt;Demonstration of
ERb&lt;/title&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/head&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;body&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;p&gt;Dear
programmer,&lt;/p&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;p&gt;This is a bref demonstration of
how ERb fills out a template.&lt;/p&gt;</P>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;/body&gt;</P>
<p>&lt;/html&gt;</P>]]></description>
            <author>FL车在臣</author>
            <category>RoR</category>
            <comments>http://blog.sina.com.cn/s/blog_3ecb9b110100eobv.html#comment</comments>
            <pubDate>Tue, 18 Aug 2009 10:11:19 GMT+8</pubDate>
            <guid>http://blog.sina.com.cn/s/blog_3ecb9b110100eobv.html</guid>
        </item>
    </channel>
</rss>
