對抗垃圾信!請您點這裡:

我的E-mail:
我的Skype:My status

2007年9月13日

偵測DNS是否還活著.. 用Ruby

有鑒於某台主機的DNS常常掛掉.. 所以就寫了這個小程式..

while true
  `ps aux | grep named`.split("\n").each{|line|
    user, pid, cpu, mem, vsz, rss, tty, stat, start, time, *command = line.split("\s")
    flag = true if command[0] == "/usr/sbin/named"
    `/etc/init.d/named start` unless flag
  }
  sleep 300
end


2007年9月10日

線上Ruby Regular Expression Editor

Ruby/Rails寫到一半.. 忽然需要用到RegExp來驗證某個東西(Ex: E-mail),卻臨時找不到工具可以測試自己寫的RegExp是否正確該怎辦?
沒關係!這邊有個網站:http://www.rubular.com/
這個網站可以讓您線上測試RegExp是否正確唷:)
可以試試看!

資料來源:China on Rails http://chinaonrails.com/topic/view/723/1.html

2007年7月30日

WxWidgets初體驗

最近無聊想寫點小程式.. 可是不想用Visual Basic寫,用Ruby + GUI Toolkit寫
可是該選哪套GUI Toolkit? 說真的.. GTK+好難用喔ˊˋ.. Qt完完全全不想用
WindowsAPI? 那我乾脆用VB就好了=..=
選來選去看來看去.. 乾脆就看了godfat的建議,去玩wxWidgets
wxWidgets在Ruby上的binding叫做WxRuby,我們先來做準備吧。
首先,我們要安裝wxWidgets跟WxRuby
連線到http://www.wxwidgets.org/下載wxWidgets
接著打開命令提示字元,輸入gem i wxruby -y
一切搞定後,就可以開始先來寫個"哈囉握的"
開啟irb,輸入以下程式碼

require 'rubygems'
require 'wx'
include Wx # => 我比較懶XD

class HelloWorld <> on_init override
helloframe = Frame.new(nil, -1, "HelloWorld")
StaticText.new(helloframe, -1, "Wa ha ha")
helloframe.show
end
end

HelloWorld.new.main_loop

在wxWidgets中,每個視窗都是一個Frame,而StaticText則是Label(在VB中就叫做Label,SWT我不知道XD)
Okok.. 可以動對不對? 不能動那就.. (( 當作沒看到

繼續...
或許各位會認為很奇怪,為什麼要自己慢慢寫.. 不要用視覺化的開發工具呢?
現在來跟各位介紹,在GTK中有所謂的Glade,那在wxWidgets呢?當然有wxGlade!
如果不喜歡wxGlade,這邊也有列表:[網址太長請點我]
在wxWidgets中,支援一種叫做XRC(XML Resource)的格式檔案,很多視覺化工具,如wxGlade都支援輸出這種檔案。
這種檔案的好處是不管是哪種開發工具或者程式語言,都可以藉由這個XRC檔案來產生一樣的介面。
各位可以到http://wxglade.sourceforge.net/下載wxGlade,安裝後就可以開始拖拉了。
弄好一個介面後,我們選擇產生XRC檔案。
接著在同個目錄下,新增一個.rb檔案。
假設我們有一個Frame與一個Button
Frame: MainFrame
Button: btnButton
程式碼如下

require 'rubygems'
require 'wx'
include Wx

class MainFrame < btn =" find_window_by_id(xrcid('btnButton'))" xml =" XmlResource.get" xrc_file =" File.join(File.dirname(__FILE__)," main =" MainFrame.new">
OK,大致上就這樣囉..

2007年6月29日

Rails中實做下拉式選單

太久沒有寫文章了.. 最近接到一個案子.. 剛好讓我重溫Select的使用方法..
嗯.. 結果卡在multiple,不知道是我太想睡還是怎樣.. 居然傻了..
跑去#rubyonrails問,一位名為carpet_the_walls的網友給了我他寫的文章,網址是:
http://shiningthrough.co.uk/Select+helper+methods+in+Ruby+on+Rails
在此先謝謝carpet_the_walls (Thank you, carpet_the_walls)

來做個Memo.. 不然又忘記了..
在Rails中真的有一堆Select helper可以用.. 不只carpet_the_walls混淆,連我也模糊不清!
常見的有三個..
select, select_tag, collection_select(其餘的什麼select_date那些不談)
我們先來看看一個基本的下拉式選單骨架

<select name="selection">
  <option value="1">Opt1</option>
  <option value="2">Opt2</option>
</select>
在一個下拉式選單中,有一些是必備的資訊,像是"name"、"value"與"text"三個,在回傳資訊給Server時,"name"將是接收資訊用的,而"value"會傳回被選的值,而"text"則是使用者會看到的字,依上面的例子來講,Opt1、Opt2這兩個就是屬於"text"

開始講講那三種Select helper

select:
  select(object, method, choices, options = {}, html_options = {})
  在ActionView::Helpers::FormOptionsHelper中定義

  • object是一個實體化變數,這裡很明顯的就是要擺上model物件嘛!
  • method則是object的一個屬性,也是資料表中的對應欄位
  • choices就是要被選的選項,可以是陣列或者是雜湊(Hash)
  • options與html_options則是一些選項
在這邊來舉個例子吧
<%= select("project", "teacher_id", @teachers.collect{|t| [t.name, t.id]}, { :include_blank => false }) %>
<%= select("project", "student_id", {"CFC" => '1', "EF" => '2'}) %>
第一個例子中,@teachers在Controller是這樣的
@teachers = Teacher.find(:all, :select => 'id, name')

select_tag:
  select_tag(name, option_tags = nil, options = {})
  在ActionView::Helpers::FormTagHelper中定義

如果你很喜歡手動打option的話.. 那用select_tag準沒錯啦!
在select_tag中,name將會是params所接收值所用的鍵
直接看範例
<%= select_tag 'user', "<option>CFC</option>" %>
這時在Controller中將會用params[:user]來接收傳過來的值
但是select_tag也可以搭配options_for_select或者options_from_collection_for_select一起使用.. 來看一個範例吧
<%= select_tag('sid[]', options_from_collection_for_select(@students, 'id', 'name'), :multiple => true)%>
因為加上了:multiple,所以可以接受多值選擇,這時在Controller接收到的sid將會是一個陣列,這也是我所卡住的地方.. (( 真丟臉

collection_select:
  collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
  在ActionView::Helpers::FormOptionsHelper中定義

如果資料來源是從資料庫來的話,可以使用這個來做下拉式選單。
這個Object不用我說,就是你的model
method呢?當然就是欄位啦
其實嚴格說起來,這只是select+options_from_collection_for_select的組合啦!
範例:
<%= collection_select(:payment, :id, @payments, :id, :name, options ={:prompt => "-Select a continent"}, :class =>"payment") %>

再次謝謝原作者carpet_the_walls:)

2007年6月16日

Ruby library -- SMS

這個Library搭配http://www.twsms.com才可以使用喔!
有任何問題可以直接回這篇文章,或者寫信問我,我信箱是Gmail的,帳號跟我的這個部落格帳號一樣

我先說用法好了:

require 'twsms'
sms = TWSMS.new(username, password) # 帳號密碼
sms.sendSMS(mobile, message) # mobile: 目標手機號碼  message: 要傳的訊息
原始碼:
=begin
  == Information ==
  === Copyright: Apache 2.0
  === Author: CFC < zusocfc@gmail.com >
  === Prog. Name: TWSMS lib
  === Version: 0.1
  == Introduction ==
    TWSMS(Taiwan SMS)
    TWSMS is a SMS sender, it must use with http://www.twsms.com.
    There has no any library for the SMS system in Taiwan. So, I just coded this and release this version.
    This version just support for sending SMS.
  == Featured ==
   
  == Using TWSMS ==
    It just support for standalone class now.
    require it before you use.
  === Using TWSMS by standalone class
    require 'twsms'
    sms = TWSMS.new('username', 'password')
    sms.sendSMS('09xxxxxxxx', 'Hi, there! TWSMS library is so easy to use!')
    sms.sendSMS('09xxxxxxxx', 'Send SMS with options',
        :popup => 1,
        :type => "now",
        :mo => "Y")
=end

%w|uri cgi net/http|.each{|r| require r}

class TWSMS
  def initialize(username, password)
    @uname, @upwd = username, password
    @options = {
      :type => "now", # Sending type: now, vld
      :popup => "",
      :mo => "Y".upcase,
      :vldtime => "86400",
      :modate => "",
      :dlvtime => "",
      :wapurl => "",
      :encoding => "big5"
    }
   
    @errors = {
      -1.to_s.to_sym => "Send failed",
      -2.to_s.to_sym => "Username or password is invalid",
      -3.to_s.to_sym => "Popup tag error",
      -4.to_s.to_sym => "Mo tag error",
      -5.to_s.to_sym => "Encoding tag error",
      -6.to_s.to_sym => "Mobile tag error",
      -7.to_s.to_sym => "Message tag error",
      -8.to_s.to_sym => "vldtime tag error",
      -9.to_s.to_sym => "dlvtime tag error",
      -10.to_s.to_sym => "You have no point",
      -11.to_s.to_sym => "Your account has been blocked",
      -12.to_s.to_sym => "Type tag error",
      -13.to_s.to_sym => "You can't send SMS message by dlvtime tag if you use wap push",
      -14.to_s.to_sym => "Source IP has no permission",
      -99.to_s.to_sym => "System error!! Please contact the administrator, thanks!!"
    }
    @args = []
    @url ||= "http://api.twsms.com/send_sms.php?"
    @url += "username=" + @uname
    @url += "&password=" + @upwd
  end
 
  def sendSMS(mobile, message, opt={})
    @options[:mobile], @options[:message] = mobile, message
    @options.merge!(opt).each{|k, v| @args << k.to_s + "=" + CGI::escape(v.to_s)}
    @url += "&" + @args.join("&")
    self.chk_val
    chk_errors(Net::HTTP.get(URI.parse(@url)))
  end
 
  def chk_val
    @options[:dlvtime] = "" unless @options[:type] == "dlv"
    @options[:wapurl] = "" if @options[:type] != ("push" && "upush")
  end
 
  def chk_errors(resp)
    resp = resp.split("=")[1]
    if @errors.has_key?(resp.to_s.to_sym)
      puts "==========", "Error!! Message: ", @errors[resp.to_s.to_sym]
    else
      puts "==========", "Message has been send! Your message id is: " + resp.to_s
    end
  end
 
  protected :chk_val
end
晚點丟到Google Code Hosting上去...

Updated:
TWSMS on Google Code Hosting: http://code.google.com/p/twsms/
SMSender on RubyForge: http://rubyforge.org/projects/smsender/

2007年6月12日

find_by_randomize -- 讓ActiveRecord可以亂數取資料

請在model內加入:

def self.find_by_randomize
  ids = self.find(:all, :select => [id])
  self.find(ids[rand(ids.size)]["id"].to_i)
end
這樣一來,就可以取亂數選取資料了!

請參考這篇:為你的 Active Record 做出多采多姿的 find

當然囉.. thegiive那個就是我修改的範本:P

2007年5月15日

具有破壞版面功用的HTML標籤:plaintext

剛剛寫程式寫到一半忽然想到這個破壞力極大的標籤
雖然這個標籤不會造成多大的危害,但是在某些網站上,還是可以造成一定程度的破壞
所以請各位Web Developers注意,過濾掉這個標籤:<plaintext>
另外,HTML的註解標籤也請過濾,也就是:<!--
這兩個都可以破壞版面!
結果請看這邊:
http://willh.org/cfc/cfc_priv/plaintext.htm

解決方式:
如果是使用黑名單來擋HTML標籤,請把plaintext給加入
如果沒有使用檔標籤的套件,請盡快使用
如果沒有辦法使用檔標籤的套件,請透過Regular Expression幹掉它!

2007年5月13日

php+ruby(with ActiveRecord)又一新範例 -- RSS聯撥器

上個例子,我們用PHP + Ruby 搭配ActiveRecord的方式來寫資料新增的程式
今天我們就來延伸應用一下,要做什麼呢? RSS聯撥器!
有鑒於GoogleReader的RSS聯撥器產生出來的東西太醜(只能修改一兩個小地方.. 我總覺得那好胖=  =),乾脆自己寫個來用
Demo網址改天再PO上來,我們先來寫程式比較重要:P
主機請記得先裝好Ruby、PHP、Apache跟MySQL;OS要啥都沒差,我比較建議LAMP的配置XD
我們來建立一個叫做feeds的目錄包含一個子目錄,叫做lib:

  mkdir -p feeds/lib
 
先跳到feeds/lib新增幾個會被require的檔案:

  cd feeds/lib
  touch connect.rb model.rb require.rb

以下是各個檔案的用處:
- connect.rb
  資料庫連線初始化
- model.rb
  資料表模型宣告
- rqeuire.rb
  會用到的額外library引入

原始碼:

  - connect.rb
    #!/usr/bin/env ruby;require 'lib/require';ActiveRecord::Base.establish_connection({:adapter => "mysql",:host => "localhost",:username => "username",:password => "password",:database => "others"})
  - model.rb
    #!/usr/bin/env ruby;require 'lib/connect';class Feed < ActiveRecord::Base;end
  - require.rb
    #!/usr/bin/env ruby;%w|rubygems active_record hpricot open-uri|.each{|lib| require lib}

一切搞定後,我們可以開始來建立資料庫了!

  mysql> create database others;
  mysql> use others;
  mysql> create table feeds(id int, uri varchar(255));
  mysql> describe feeds;
 
看看資料表結構是否正確!
接著回到上一層目錄,新增底下的幾個檔案:

  touch index.php list.rb new.htm new_record.rb save.php

- index.php
  網站首頁,會列出目前的RSS feed
- save.php
  儲存RSS feed網址
- list.rb
  處理RSS feed
- new_record.rb
  將RSS feed網址存入資料庫(也可以直接用php寫.. 我是沒有意見)
- new.htm
  新增RSS feed網址的表單

原始碼我就直接貼了

  - index.php
    <html>
      <head>
        <title></title>
      </head>
      <body>
        <a href="new.htm">Create</a>
        <ul>
    <?php
      exec("ruby list.rb", $args);
      for($i=0;$i<count($args);$i+=3)
        echo "<li><a href=\"" . $args[$i+1] . "\" title=\"作者:" . $args[$i+2] . "\">" . $args[$i] . "</a> -- " . $args[$i+2] . "</li>";
    ?>
        </ul>
      </body>
    </html>

  - save.php
    <?php
      exec("ruby new_record.rb " . $_POST["feed_uri"], $arg);
      if ($arg) echo "<script>location.href=\"index.php\";</script>";
    ?>
 
  - list.rb
    #!/usr/bin/env ruby
    =begin
        Filename: list.rb
    =end
    require 'lib/model'

    Feed.find(:all).each{|feed|
        doc = Hpricot(open(feed.uri))
        rss = doc.search("entry")
        max = rss.size > 3 ? 3 : rss.size
        max.times {|i|
          break if rss.nil?
          puts rss[i].search("title").text.gsub(/\n/, " ") # Return the title of the article to the PHP file.
          puts rss[i].search("link[@rel='alternate']")[0]["href"].gsub(/\n/, " ") # Return the link of the article to the PHP file.
          puts rss[i].search("author/name").text.gsub(/\n/, " ") # Return the author of the article to the PHP file.
        }
    }

  - new_record.rb
    #!/usr/bin/env ruby
    =begin
      Filename: new_record.rb
    =end
    require 'lib/model';puts Feed.new({:uri => ARGV[0]}).save
 
  - new.htm
    <html>
      <head>
        <title></title>
      </head>
      <body>
        <form action="save.php" method="post">
          <p>Please input the feed url:<input type="text" name="feed_uri" /></p>
          <p><input type="submit" value="Save!" /></p>
        </form>
     </body>
    </html>
 
OK,這樣就可以啦XD

2007年5月9日

PHP + Ruby with ActiveRecord 範例

如果老闆要求使用php,可是您卻是Ruby狂熱者,這.. 怎辦呢?
沒關係! 一樣用Ruby寫,php只要做一點點的處理就好!
How to? php中有這個函式:exec
( 本範例實作於Windows XP Professional搭配InstantRails;在其他作業系統上沒有測試過,不過各位還是可以嘗試看看 )
我們來試試看吧!
先寫個test.rb:

  #!/usr/bin/env ruby
  #
  # Filename: test.rb
  #
  puts "Hello"
  puts "world"
 
再寫個test.php:

  <?php
    exec("test.rb", $args);
    foreach($arg as $args)
      echo $arg . "<br />";
  ?>

將兩個檔案放在同一個目錄下後,打開瀏覽器瀏覽test.php;看!是不是顯示結果出來了?
OK,我們直接來用ActiveRecord幫我們新增資料吧!
我們需要一張普通頁面、一張php網頁跟一個ruby檔案:

  #!/usr/bin/env ruby
  #
  # Filename: ar.rb
  #
  require 'rubygems'
  gem 'activerecord'
  ActiveRecord::Base.establish_connection(
    :adapter => 'mysql',
    :host => 'localhost',
    :username => 'root',
    :password => '',
    :database => 'cal'
  )
 
  class Event < ActiveRecord::Base;end
 
  name, descr = ARGV[0], ARGV[1]
  puts Event.new({:name => name, :descr => descr, :date => Date.today, :time => Time.now}).save

好了,接下來是普通頁面,這是送出表單:
 
  <!-- Filename: ar_form.html -->
  <html>
    <head>
      <title>PHP with Ruby and ActiveRecord</title>
    </head>
    <body>
      <form action="ar_save.php" method="POST">
        Username: <input type="text" name="usrname" /><br />
        Description: <textarea name="descr"></textarea><br />
        <input type="submit" value="Save it!" />
      </form>
    </body>
  </html>
 
這是php網頁:

  <?php
    // Filename: ar_save.php
    exec("2.rb " . $_POST["usrname"] . " " . $_POST["descr"], $arg);
    if($arg[0]) echo "Success!";
  ?>

OK,讓我們來試試看吧!
Look!! It works!!
現在,我們來寫個ar_read.rb跟ar_read.php來讀取資料吧:

  # Filename: ar_read.rb
  require 'rubygems'
  gem 'activerecord'
  ActiveRecord::Base.establish_connection(
    :adapter  => "mysql",
    :host     => "localhost",
    :username => "root",
    :password => "",
    :database => "cal"
  )
  class Event < ActiveRecord::Base;end
  events = Event.find(:all, :conditions => "name = '#{ARGV[0]}'")
  events.each{ |event|
    puts event.name
    puts event.descr
    puts event.date.to_s(:db)
    puts event.time.strftime("%H:%M:%S")
  } 

  <?php
    // Filename: ar_read.php
    exec("ar_read.rb " . $_GET["name"], $args);
    $info = array();
    for($i=0, $j=0;$i<count($args);$i+=4, $j++){
      $info[$j]["name"] = $args[$i];
      $info[$j]["descr"] = $args[$i+1];
      $info[$j]["date"] = $args[$i+2];
      $info[$j]["time"] = $args[$i+3];
    }
    for($j=0;$j<count($info);$j++)
      echo "Name => " . $info[$j]["name"] . "<br />Description => " . $info[$j]["descr"] . "<br />Date => " . $info[$j]["date"] . "<br />Time => " . $info[$j]["time"] . "<br />";
  ?>
 
看看結果,hmmm.. 看起來真棒!
嗯?如何?Ruby + ActiveRecord的威力很強大吧?
為什麼不要直接用PHP寫就好? 因為光寫SQL你就想跳樓,何必呢?
記住,在Ruby的檔案中,不可以用:

  puts 1, 2, 3

這種方法,會造成php收不到回傳,因此必須用這種寫法:

  puts 1
  puts 2
  puts 3

或者就是:

  puts 1; puts 2; puts 3

端看個人喜好囉!

2007年4月30日

Array.longest ( Array.which_long?修改版 )

感謝在Ruby-talk上的:

Chris Carter
David A. Black
Harry
Robert Dober
James Edward
:)
原本的程式碼太長,而且使用內建的功能組合起來就好
再者,原本的程式會把陣列的元素強制轉型為String

新的程式碼為:
class Array
  def longest
    # Harry <http://www.kakueki.com/ruby/list.html>
    self.select{|r| r.to_s.size == self.max{|x, y| x.to_s.size <=> y.to_s.size}.to_s.size}
  end
end
這個程式是由Harry所寫出的,底下轉貼原文:

On 4/29/07, Billy Hsu <ruby.maillist@gmail.com> wrote:
> Thanks for your reply, I learned more on this thread :P
> But I have a question:
> If I have an array contain:
>   ary = [1, 12, 234, "456"]
> there has two elements which size is 3, but the longest method just returned
> one of them.
> I can't solve it :(
>

Is this what you are looking for?
Do you want all longest elements?

big = [1, 12, 234,45,978, "456"].max {|x,y| x.to_s.size <=> y.to_s.size}
p [1, 12, 234,45,978, "456"].select {|r| r.to_s.size == big.to_s.size}
由於Harry不喜歡被張貼信箱,因此我將他的網站給貼上來:
http://www.kakueki.com/ruby/list.html
A Look into Japanese Ruby List in English

再一次謝謝Harry的幫助:)
也謝謝其他人,讓我學到許多東西:D
Thanks again and again!!

CFC --


2007年4月28日

Array.which_long? -- 剛出爐的函式

class Array
def which_long?
# Version 1.0
# Coded by CFC <>
# PLEASE DO NOT REMOVE THE COMMENT OF THIS FUNCTION, THANKS A LOT.
# Usage:
# ['a', 'ab', 'abc' 1234].which_long?
# => 1234
self.size.times{|i| self[i]=self[i].to_s}
max, long = 0, String.new
self.each{|item| item.size > max ? (max = item.size; long = item) : next}
long
end
end


以上是原始碼,使用方式如下:

puts ['a', 'ab', 'abc', 1234].which_long?
=> 1234

授權還沒定,不過大家還是可以拿去使用:P
請不要拿掉註解.. 謝謝

2007年4月24日

rubygems 0.9.2的問題

本文同步發佈至:http://blog.pixnet.net/zusocfc/post/4160285


升級Rubygems到0.9.2時,不論是安裝gem包還是升級gem包
都會產生一個Error:

ERROR:  While executing gem ... (NoMethodError)
    undefined method `refresh' for #<Hash:0xb799a478>

這個時候該怎麼辦呢?
根據這篇文章所寫:http://www.cnzxh.net/blog/Index.php?do=readArticle&articleId=145
我們可以做這個動作:

rm -f /usr/local/lib/ruby/gems/1.8/source_cache

經過測試後.. 真的就正常了..
所以如果你有出同樣問題 請照做吧:P
( 我想這問題只會發生在*nix系統上 )

2007年4月20日

大量帳號建置器 版本1跟版本2

先說好,跟往常一樣.. 到我Pixnet的網誌看會比較不頭痛:P
版本1可以不用寫群組名稱,但是程式碼好醜ˊˋ
版本2必須要有群組名稱,適用於學校(?)

版本1下載
版本2下載

版本1:

#!/usr/bin/env ruby
File.open(ARGV[0]) do |file|
  while a = file.gets
    a = a.chomp.split(/ /)
    print "username => #{a[0]} ", "password => #{a[1]} ", "group => #{a[2]}", "\n"
    a[2].nil? ? `useradd -m #{a[0]}` : `useradd -m -G #{a[2]} #{a[0]}`
    `echo #{a[0]}:#{a[1]} | chpasswd`
  end
end
exec "pwconv"

使用者清單寫法:

  帳號 密碼 群組

版本2:

#!/usr/bin/env ruby
require 'yaml'
YAML.load_file(ARGV[0]).each{ |grp|
  grp.each{ |usr|
    usr.each{ |i|
      info = i.chomp.split(/ /)
      `useradd -m -G #{grp[0]} #{info[0]}`
      `echo #{info[0]}:#{info[1]} | chpasswd`
    }
  }
}
`pwconv`

使用者清單寫法:

grp1:
  - usr1 pwd1
  - usr2 pwd2
grp2:
  - usr3 pwd3
  - usr4 pwd4
grp3:
  - usr5 pwd5
  - usr6 pwd6
使用方式都是:
./account list

程式授權.. 隨便啦

2007年3月26日

HAML

最近開始接觸HAML
在Rails中,預設使用ERb來當作模板描述語言,可是這樣寫個人認為非常醜也非常累...
而之前看到HAML時感覺到那東西似乎沒有太大的可用性,難道要Designer也學Ruby嗎?
不過後來我想通了..

架構這部分可以給Coder作,Designer乖乖設計CSS就夠了..
來看看底下這個Sample吧:

這是rhtml

原始碼請看這地方:http://blog.pixnet.net/zusocfc/post/3520168

這是HAML

#content
.left.column
%h2 Welcome to our site!
%p= print_information
.right.column= render :partial => "sidebar"

看!少了多少行?
可以讓開發速度變快耶= v =...
最主要的是,看起來也比較美觀了!

參考:
http://haml.hamptoncatlin.com/tutorial/
http://haml.hamptoncatlin.com/docs/




2007年3月11日

Rails 安全性漏洞一則 -- attr_protected 與 attr_accessible

我沒辦法在這邊正常的發布有表單HTML tag的文章,請連結至:
http://blog.pixnet.net/zusocfc/post/3220943
觀看完整文章!

Rails中有個安全性漏洞,請參考

* http://manuals.rubyonrails.com/read/chapter/47
* http://www.javaeye.com/topic/58686

假設我們有個users table,表格欄位如下:

* username # 很明顯就是帳號
* password # 這就是密碼
* role # 權限名稱

而我們提供給使用者註冊的頁面只會有username跟password欄位
然後你的後端如果是這樣:

User.create(params[:user])

哦.. 這就真的好玩了..
使用者在註冊時直接提權..
那這要怎樣處理呢?

我們可以在
app/model/user.rb
內新增這行:

attr_protected :role

這樣一來,該欄位就會確定被忽略掉而不會被新增..
不過你得做一下這道手續:

user = User.new(params[:user])
user.role = sanitize_properly(params[:user][:role])

===== 分 - 隔 - 線 =====

另外,我們可以使用

attr_accessible :username, :password

這有點類似白名單的方式,可以過濾掉沒出現的欄位...


2007年3月4日

Rails -- InPlaceEdit

用過Flickr嗎?
如果你有Flickr相簿,應該對於修改照片標題、說明的方式記憶猶新吧?
那種就叫做 In Place Editing
在Rails中,要實做這種技術並不難,因為本身就內建這個功能
不過到了Rails 2.0將會把這個從內建移除變成Plugins形勢存在
可以參考這篇:In-plcae-editing by Rails
不過我在這裡重新說明一次使用方式吧
如果有<%= javascript_include_tag :defaults %>的話,那只剩下兩個步驟:
Controller:

class ObjectController < ApplicationController
in_place_edit_for :object, :method
end


View:

<%= in_place_editor_field :object, :method %>

這樣就可以建立起最基本的InPlaceEditing欄位
可是最基本的都是英文,因此Rails也提供了修改參數,可以參考這篇
in_place_editor_field欄位有四個參數:
in_place_editor_field(object, method, tag_options = {}, in_place_editor_options = {})
而修改的部分則是放在第四個參數;假設我要修改:saving_text:
<%= in_place_editor_field(:object, :method, {}, {:saving_text => "儲存中..."} %>
改好後記得重新整理頁面!

另外,如果要建立多個欄位的話,必須用這種方法:
class ObjectController < ApplicationController
in_place_edit_for :object, :method1
in_place_edit_for :object, :method2
in_place_edit_for :object, :method3
end


這樣寫超麻煩的!因此可以這樣:

class ObjectController < ApplicationController
%w"method1 method2 method3".each do |m|
in_place_edit_for :object, m.to_sym
end
end

這樣未來在新增刪除上都會很方便!

Ruby/GTK 中文教學

這是http://www.ruby-lang.org/zh_TW/ 站長所寫的一篇教學
網址是:http://info.sayya.org/~sjh/sjh_rubygtk.pdf
寫得很詳細、簡單明瞭!
如果有需要可以看看

2007年3月1日

Balloon -- Ruby百寶箱

http://balloon.hobix.com/

Here, Try a Balloon

Balloon is a site for Rubyists to create demos of their code. Have Balloon download Gems, fetch code from Subversion, run scripts and then close up without leaving a trace!

簡單的說,Balloon提供給Ruby Coders一個可以建立demo的平台,如果有玩過DOB首頁製作百寶箱作者群的人應該可以很快上手,因為跟發布文章的介面有點類似
它定義了幾個Actions:
  • Run some Ruby code
  • Fetch a gem
  • Fetch a Ruby library(non-Gem)
  • Download code from Subversion
  • Use a Gem Server
可以看看底下範例:
http://balloon.hobix.com/serve.rb
http://balloon.hobix.com/Win32_MessageBox

寫好的Code還可以嵌入到部落格中喔

快速處理HTML/XML文件

XML文件我是用ReXML啦.. 不過我這邊不是要介紹ReXML,是要來介紹hpricot這個Library的
安裝方式:
gem install hpricot
or
gem install hpricot --source http://code.whytheluckystiff.net

第一個會連線到gem server去抓來裝,不會有最新的更新;第二個會連到指定的gem server,那邊更新速度較快,我還看到jruby版本的gem..

OK,廢話不多說,趕緊來看看
官方網站是:http://code.whytheluckystiff.net/hpricot/

如果會jQuery的人,這個是用jQuery當底層的喔!
我來個例子吧


require 'rubygems'
require 'hpricot'
require 'open-uri'
doc = Hpricot(open("http://article.zuso.org.tw/show.php?id=1453"))
tb = doc.search("//table")
puts "Tables: #{tb.size}"
puts tb[0]

2007年2月27日

Wikibooks上的中文版Programming Ruby

網址是:http://zh.wikibooks.org/w/index.php?title=Programming:Ruby&variant=zh
現在是我跟石頭閒語的Rock一起翻譯撰寫,如果有人有興趣的話歡迎加入翻譯的工作
請將原文的文章引用後張貼,然後修改翻譯即可
感謝您的付出!謝謝!

File讀取方式:readlines好還是while迴圈好?

在Ruby中,File可以用readlines跟跑while迴圈來讀
在這個例子中,程式p1用的是while迴圈,p2用的是readlines
執行後,秒數分別是
P1:
121.468秒
P2:
122.172秒
範例文字檔大小是:
4.07 MB (4,272,336 位元組)

範例程式碼是:

puts "P1 start"
p1_start = Time.now
open("C:/words.txt"){ |f|
while a = f.gets
print a
end
}
p1_end = Time.now
puts "P1 end"
puts "P2 start"
p2_start = Time.now
File.open("C:/words.txt") do |f|
puts f.readlines
end
p2_end = Time.now
puts "P2 end"
puts
puts "P1: ", p1_end - p1_start
puts "P2: ", p2_end - p2_start

由此可見,while快上不到一秒,但是如果在讀取大檔案的時候,用while反而會比較快
相對的,如果不考慮效率,我還是建議使用readlines

不過這只是個人看法,希望其他前輩不吝指教,謝謝!

2007年2月25日

小水滴測試用文章

有看到右邊多了什麼嗎?
沒錯!就是部落格寵物!
還蠻可愛的說A_A

HEMiDEMi文章產生器 -- Ver. 0.2

此版本尚未支援 影片代碼 功能

原始碼如下:
require 'rubygems'
require 'mechanize'

class HEMiDEMi
def initialize(username="", password="")
agent = WWW::Mechanize.new{}
f = agent.get("http://www.hemidemi.com/member/signin_form").forms[1]
f["member[username]"], f["member[password]"] = username, password
f.submit
@agent = agent
@base_url = "http://www.hemidemi.com"
@new_path = "/user_bookmark/new"
end

def run(file)
File.open(file) do |f|
f.readlines.each do |frl|
next if frl[0].chr == "#"
title, url, quotes, description, t_s, g_s = frl.split(/\t/)
self.add({
"title" => title,
"url" => url,
"quotes" => quotes,
"description" => description,
"tag_string" => t_s,
"group_string" => g_s
})
end
end
end

def add(qs)
f = @agent.get(@base_url+@new_path).forms[1]
qs.each do |k, v|
puts "Add: #{k} as #{v}"
f["user_bookmark[#{k}]"] = v
end
f.fields.each do |x| puts x.name + " => " + x.value end
f.submit
end

end
puts "請輸入HEMiDEMi使用者帳號跟密碼(用空格分開):"
ud = gets.chomp.split(/ /)
hemidemi = HEMiDEMi.new(ud[0], ud[1])
puts "請輸入檔案位置,不輸入則預設值為當前目錄下的bms.txt:"
path = gets.chomp
path == "" ? hemidemi.run("bms.txt") : hemidemi.run(path)

另外,bms.txt檔案內容是:
# 欄位說明:
# title\turl\tquotes\tdescription\ttag_string\tgroup_string
# 標題網址引述說明標籤群組
# :按一次Tab鍵
# 底下是範例:
HEMiDEMi http://www.hemidemi.com HEMiDEMi共享書籤 hemidemi test ruby_and_ror

說明:

請先建立好bms.txt或者其他檔案名稱的純文字檔
欄位寫的很清楚,就是:標題網址引述說明標籤群組
請記得一定要用tab來分隔,建議用Windows內建的記事本來編寫
如果想要空掉某些欄位,則該欄位不填直接按下tab鍵即可,看範例就可以知道 (範例沒有寫上引述)


程式授權:MIT
程式所需套件:rubygems、mechanize跟mechanize之所需套件
mechanize安裝方式:
請先確定有rubygems,如果沒有請到RubyForge下載安裝
打開命令提示字元或者終端機,輸入:
gem i mechanize -y
如果有要你選版本的話,Windows使用者請選擇(mswin32)版本,而其他作業系統請選(ruby)版本
程式原始碼下載:
Windows (Big5)
Linux (UTF-8)

HEMiDEMi文章產生器 -- Ver. 0.1

原始碼在這邊:

require 'rubygems'
require 'mechanize'

class HEMiDEMi
def initialize(username="", password="")
agent = WWW::Mechanize.new
f = agent.get("http://www.hemidemi.com/member/signin_form").forms[1]
f["member[username]"], f["member[password]"] = username, password
f.submit
@agent = agent
@base_url = "http://www.hemidemi.com"
@new_path = "/user_bookmark/new"
end

def add(qs)
f = @agent.get(@base_url+@new_path).forms[1]
qs.each do |k, v|
f["user_bookmark[#{k}]"] = v
end
f.submit
end

end
=begin
qs = {
"title" => title,
"url" => url,
"quotes" => quotes,
"description" => desc,
"tag_string" => t_s,
"group_string" => g_s,
"embed" => embed
}
=end

qs = {
"title" => "G00g13",
"url" => "google.com"
}

hemidemi = HEMiDEMi.new("", "").add(qs)

目前這個版本只是雛型.. 還不能夠用來大量新增!
簡單介紹一下...

qs = {
"title" => title,
"url" => url,
"quotes" => quotes,
"description" => desc,
"tag_string" => t_s,
"group_string" => g_s,
"embed" => embed
}

qs是一個Hash,我只講其中幾個
quotes:代表的是"引述"
description:代表的是"說明"
embed:代表的是影片代碼

HEMiDEMi文章產生器.. Memo

原始碼在這邊:

require 'rubygems'
require 'mechanize'

class HEMiDEMi
def initialize(username="", password="")
agent = WWW::Mechanize.new
f = agent.get("http://www.hemidemi.com/member/signin_form").forms[1]
f["member[username]"], f["member[password]"] = username, password
f.submit
@agent = agent
@base_url = "http://www.hemidemi.com"
@new_path = "/user_bookmark/new"
end

def add(qs)
f = @agent.get(@base_url+@new_path).forms[1]
qs.each do |k, v|
f["user_bookmark[#{k}]"] = v
end
f.submit
end

end
=begin
qs = {
"title" => title,
"url" => url,
"quotes" => quotes,
"description" => desc,
"tag_string" => t_s,
"group_string" => g_s,
"embed" => embed
}
=end

qs = {
"title" => "G00g13",
"url" => "google.com"
}

hemidemi = HEMiDEMi.new("", "").add(qs)

目前這個版本只是雛型.. 還不能夠用來大量新增!
簡單介紹一下...

qs = {
"title" => title,
"url" => url,
"quotes" => quotes,
"description" => desc,
"tag_string" => t_s,
"group_string" => g_s,
"embed" => embed
}

qs是一個Hash,我只講其中幾個
quotes:代表的是"引述"
description:代表的是"說明"
embed:代表的是影片代碼

2007年2月24日

三場關於Ruby在Google的演講

錄影放在Google Video
議題分別是:
How to Design A Domain Specific Language -- David Pollak
Code Generation With Ruby -- Jack Herrington
Ruby and Google Maps -- Andre Lewis

正在看Ruby and Google Maps:P

51個Rails影片跟展示

網址是:http://www.bestechvideos.com/category/development/ruby/

這邊有51個不同的展示影片,也有介紹影片,非常值得去看看

社群網站建置中

現在改用Joomla,不用Xoops了
不過還在建置.. Joomla裝起來感覺還蠻好的
版面也很漂亮,用起來很舒服
主機由 Zuso Security 提供,感謝負責人 ik

目前網址是:http://willh.org/cfc/
而原本的:http://www.ruby.oss.tw則會自動轉至新網址
感謝http://twpug.net的站長Kiang提供ruby.oss.tw網域名稱及空間

等到網站建置結束,將會在Group上公告

現在.. 凌晨四點多= =
會不會被老婆罵死阿~"~a

2007年2月21日

台灣Ruby官方網站出來了!

這真是令人振奮的消息阿
雖然已經超過兩三個月了...
由SJH於2006年10月4號成立
擷圖:http://farm1.static.flickr.com/175/396720833_599f58f8e6_o_d.jpg

真是太開心了>///<

2007年2月20日

Gyre -- 優秀又強大的網頁版Rails編輯器

Gyre是一個網頁版的Rails Editor,雖然是網頁版的可是別小看它喔!
它的執行環境不過就只是從Desktop換到Web而已,一般IDE該有的功能都有喔!
Ruby Inside上有介紹:http://www.rubyinside.com/gyre-web-based-ide-and-debugger-for-rails-383.html
官方網站:http://gyre.bitscribe.net/
ScreenCast:http://gyre.bitscribe.net/screencast
我很推薦各位去看他的ScreenCast,前面介紹蠻多的.. 可以跳過不聽XD
它可以Debug,可以同步變更檔案內容(也就是說當我使用這個網頁版編輯器時,我在一般文字編輯器上的修改,這個編輯器也可以即時更新)!

Win32API Sample: MessageBox

require 'Win32API'

=begin
Message Box:
Coded by CFC Zuso Security
CFC
2007/2/16
=end

class Msgbox
def initialize(lpText="", lpCaption="", wType = 0)
Win32API.new('user32', 'MessageBox', %w(p p p i), 'i').call(0,lpText,lpCaption,wType)
end
end

def Msgbox(lpText="", lpCaption="", wType = 0)
Win32API.new('user32', 'MessageBox', %w(p p p i), 'i').call(0,lpText,lpCaption,wType)
end

採用MIT授權條款
Usage:
Msgbox.new("Hi", "Hello, world")
Msgbox.new("XD", "Hello!", 1)
Msgbox("Hi", "Hello!")

如何透過Ruby呼叫Win32API

研究了一下.. 寫出來當Memo..
我先以一個簡單的例子來解說,就用大家最愛的MessageBox吧!

require 'win32api'
msgbox = Win32API.new('user32', 'MessageBox', %w(p p p i), 'i')
msgbox.call(0, "Message body", "Messagebox title", 1) # hwnd, lpText, lpCaption, wType => Come from API Viewer (API檢視員)

OK.. 開始來講解
1. require 'win32api'
這是將win32api.rb給引入的意思,跟C的#include用意相同

2. msgbox = Win32API.new('user32', 'MessageBox', %w(p p p i), 'i')
實體化一個Win32API物件,第一個是dllname,第二個是要呼叫的東西,第三個是API參數傳遞時的資料型態,第四個是要回傳的資料型態
如果保持nil(也就是null)的話,就表示不會有傳入或回傳

3. msgbox.call(0, "Message body", "Messagebox title", 1)
透過這個物件呼叫,hwnd傳入0,lpText傳入"Message body"接著以此類推

我來張貼一下常數表

# type flag
MB_OK = 0
MB_OKCANCEL = 1
MB_ABORTRETRYIGNORE = 2
MB_YESNOCANCEL = 3
MB_YESNO = 4
MB_RETRYCANCEL = 5

# return values
IDOK = 1
IDCANCEL = 2
IDABORT = 3
IDRETRY = 4
IDIGNORE = 5
IDYES = 6
IDNO = 7