Ruby WEBrick アクセスログフォーマットの変更
require 'webrick' config = { :DocumentRoot => '.', :AccessLog => [ [ $stderr, WEBrick::AccessLog::COMBINED_LOG_FORMAT ], ], } server = WEBrick::HTTPServer.new(config) trap("INT") { server.shutdown } # Ctrl + C で shutdown server.start
Ruby はてなブックマーク Atom API WSSE認証
はてなブックマークAtomAPI/はてなフォトライフAtomAPI で使用するWSSE認証のHTTP X-WSSEヘッダを作成するRubyスクリプト
$KCODE = 'u' require 'time' require 'digest/sha1' def hatena_wsse_header(hatena_id, password) # Nonce : HTTPリクエスト毎に生成したセキュリティ・トークン # ランダムなバイト列 http://sheepman.parfait.ne.jp/20050104.html nonce = Array.new(10){ rand(0x100000000) }.pack('I*') nonce_base64 = [nonce].pack("m").chomp # Base64エンコード # Created : Nonceが作成された日時をISO-8601表記で記述したもの now = Time.now.utc.iso8601 # PasswordDigest : Nonce, Created, パスワードを文字列連結しSHA1アルゴリズムでダイジェスト化して生成された文字列を、Base64エンコードした文字列 digest = [Digest::SHA1.digest(nonce + now + password)].pack("m").chomp credentials = sprintf(%Q<UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s">, hatena_id, digest, nonce_base64, now) { 'X-WSSE' => credentials } end
Ruby はてなブックマークの全ブックマークを取得するスクリプト
はてなブックマークAtomAPI FeedURIを使用して全ブックマークを取得するRubyスクリプト
require 'hatena_wsse_header' は d:id:toward:20051225:ruby_hatena_wsse
#!/usr/local/bin/ruby -w $KCODE = 'u' require 'net/http' Net::HTTP.version_1_2 require 'rexml/document' require 'pstore' require 'hatena_wsse_header' # はてなブックマーク/はてなフォトライフ AtomAPI WSSE認証 HTTP X-WSSEヘッダを作成 hatena_id = 'hatena_id' # はてなID password = 'password' # パスワード bookmarks = [] # 全ブックマーク # 全ブックマークを取得 Net::HTTP.start('b.hatena.ne.jp') do |http| offset = 0 has_next = true while has_next header = { 'User-Agent' => "Ruby/#{VERSION}" }.update(hatena_wsse_header(hatena_id, password)) response = http.get('/atom/feed?of=' + offset.to_s, header) root = REXML::Document.new(response.body).elements['feed'] total_results = root.elements['openSearch:totalResults'].text.to_i start_index = root.elements['openSearch:startIndex'].text.to_i items_per_page = root.elements['openSearch:itemsPerPage'].text.to_i if total_results >= start_index + items_per_page offset += items_per_page else has_next = false end root.elements.each('entry') do |elem| bookmark = {} bookmark[:title] = elem.elements['title'].text bookmark[:url] = elem.elements['link[@rel="related"]'].attributes['href'] bookmark[:hb_url] = elem.elements['link[@rel="alternate"]'].attributes['href'] bookmark[:atom_edit] = elem.elements['link[@rel="service.edit"]'].attributes['href'] bookmark[:eid] = bookmark[:atom_edit].split('/')[-1] bookmark[:issued] = elem.elements['issued'].text bookmark[:summary] = elem.elements['summary'].text bookmark[:tag] = [] elem.elements.each('dc:subject') do |tag| bookmark[:tag] << tag.text end bookmarks << bookmark end end end # 全ブックマークをPStoreで保存 db = PStore.new("hatena_bookmark-#{hatena_id}.pstore") db.transaction do db['bookmarks'] = bookmarks end # PStoreファイルから全ブックマークを読み込み bookmarks2 = nil db2 = PStore.new("hatena_bookmark-#{hatena_id}.pstore") db2.transaction do bookmarks2 = db2['bookmarks'] end require 'pp' pp bookmarks2.collect { |i| i[:title] }
ブックマークを公開しているはてなIDは、Atomフィードで同様のことが可能(WSSE認証不要)
23・24行目を変更
header = { 'User-Agent' => "Ruby/#{VERSION}" } response = http.get("/#{hatena_id}/atomfeed?of=" + offset.to_s, header)
Ruby XMLRPC はてなブックマーク件数取得API
Ruby XMLRPC4R(標準添付ライブラリ)を使用したはてなブックマーク件数取得APIのサンプル
XMLRPC::Client#call - 例外が発生するバージョン
#!/usr/local/bin/ruby -w require 'xmlrpc/client' end_point = 'http://b.hatena.ne.jp/xmlrpc' urls = [ 'http://www.rubyonrails.org/', 'http://www.rubyonrails.com/', 'http://rubyonrails.org/', 'http://rubyonrails.com/'] client = XMLRPC::Client.new2(end_point) begin result = client.call('bookmark.getCount', *urls) result.each do |url, count| puts "#{url} : #{count}" end rescue XMLRPC::FaultException => e puts "Error: #{e.faultCode}: #{e.faultString}" end
実行結果
http://rubyonrails.org/ : 3 http://www.rubyonrails.org/ : 87 http://rubyonrails.com/ : 1 http://www.rubyonrails.com/ : 45
XMLRPC::Client#call2 - 例外が発生しないバージョン
client = XMLRPC::Client.new2(end_point) ok, result = client.call2('bookmark.getCount', *urls) if ok result.each do |url, count| puts "#{url} : #{count}" end else puts "Error: #{result.faultCode}: #{result.faultString}" end
XMLRPC::Client#proxy - 例外が発生するバージョン
client = XMLRPC::Client.new2(end_point) bookmark = client.proxy('bookmark') begin result = bookmark.getCount(*urls) result.each do |url, count| puts "#{url} : #{count}" end rescue XMLRPC::FaultException => e puts "Error: #{e.faultCode}: #{e.faultString}" end
XMLRPC::Client#proxy2 - 例外が発生しないバージョン
client = XMLRPC::Client.new2(end_point) bookmark = client.proxy2('bookmark') ok, result = bookmark.getCount(*urls) if ok result.each do |url, count| puts "#{url} : #{count}" end else puts "Error: #{result.faultCode}: #{result.faultString}" end
Agile Web Development with Rails - Chapter 7
Source Code depot5〜depot7
Agile Web Development with Rails - Chapter 6
Source Code depot1〜depot4
6.1 Iteration A1: Get Something Running
Create a Rails Application
toward@localmachine ~/rails $ rails depot toward@localmachine ~/rails $ cd depot/
Configure the Application (順番入れ替え)
MySQL Administratorでデータベースdepot_developmentを作成
config/database.ymlを変更
login: &login adapter: mysql username: root password: xxxx host: LOCALHOST development: database: depot_development <<: *login test: database: depot_test <<: *login production: database: depot_production <<: *login
Create the Product Table (順番入れ替え)
Migration
toward@localmachine ~/rails/depot $ ruby script/generate migration InitialScheme create db/migrate create db/migrate/001_initial_scheme.rb
db/migrate/001_initial_scheme.rb 変更
class InitialScheme < ActiveRecord::Migration def self.up create_table :products do |t| t.column :title, :string, :limit => 100, :null => false t.column :description, :text, :null => false t.column :image_url, :string, :limit => 200, :null => false t.column :price, :float, :null => false end end def self.down drop_table :products end end
toward@localmachine ~/rails/depot $ rake --trace migrate (in /home/toward/rails/depot) ** Invoke migrate (first_time) ** Invoke environment (first_time) ** Execute environment ** Execute migrate
Create the Maintenance Application
toward@localmachine ~/rails/depot $ ruby script/generate scaffold Product Admin exists app/controllers/ exists app/helpers/ create app/views/admin exists test/functional/ dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/product.rb create test/unit/product_test.rb create test/fixtures/products.yml create app/views/admin/_form.rhtml create app/views/admin/list.rhtml create app/views/admin/show.rhtml create app/views/admin/new.rhtml create app/views/admin/edit.rhtml create app/controllers/admin_controller.rb create test/functional/admin_controller_test.rb create app/helpers/admin_helper.rb create app/views/layouts/admin.rhtml create public/stylesheets/scaffold.css toward@localmachine ~/rails/depot $ ruby script/server => Booting WEBrick... => Rails application started on http://0.0.0.0:3000 => Ctrl-C to shutdown server; call with --help for options [2005-12-18 00:16:45] INFO WEBrick 1.3.1 [2005-12-18 00:16:45] INFO ruby 1.8.3 (2005-09-21) [i386-cygwin] [2005-12-18 00:16:45] INFO WEBrick::HTTPServer#start: pid=4008 port=3000
6.2 Iteration A2: Add a Missing Column
toward@localmachine ~/rails/depot $ ruby script/generate migration AddProductDateAvailable exists db/migrate create db/migrate/002_add_product_date_available.rb
db/migrate/002_add_product_date_available.rb 変更
class AddProductDateAvailable < ActiveRecord::Migration def self.up add_column :products, :date_available, :datetime, :null => false end def self.down remove_column :products, :date_available end end
toward@localmachine ~/rails/depot $ rake --trace migrate (in /home/toward/rails/depot) ** Invoke migrate (first_time) ** Invoke environment (first_time) ** Execute environment ** Execute migrate
toward@localmachine ~/rails/depot $ ruby script/generate scaffold Product Admin exists app/controllers/ exists app/helpers/ exists app/views/admin exists test/functional/ dependency model exists app/models/ exists test/unit/ exists test/fixtures/ identical app/models/product.rb identical test/unit/product_test.rb identical test/fixtures/products.yml overwrite app/views/admin/_form.rhtml? [Ynaq] a forcing scaffold force app/views/admin/_form.rhtml identical app/views/admin/list.rhtml identical app/views/admin/show.rhtml identical app/views/admin/new.rhtml identical app/views/admin/edit.rhtml identical app/controllers/admin_controller.rb identical test/functional/admin_controller_test.rb identical app/helpers/admin_helper.rb identical app/views/layouts/admin.rhtml identical public/stylesheets/scaffold.css