Showing posts with label Ruby. Show all posts
Showing posts with label Ruby. Show all posts

Tuesday, July 06, 2010

mongodb tutorial and references

Introduction


MongoDB is a collection-oriented, schema-free document database.

By collection-oriented, we mean that data is grouped into sets that are called 'collections'. Each collection has a unique name in the database, and can contain an unlimited number of documents. Collections are analogous to tables in a RDBMS, except that they don't have any defined schema.

By schema-free, we mean that the database doesn't need to know anything about the structure of the documents that you store in a collection. In fact, you can store documents with different structure in the same collection if you so choose.

By document, we mean that we store data that is a structured collection of key-value pairs, where keys are strings, and values are any of a rich set of data types, including arrays and documents. We call this data format "BSON" for "Binary Serialized dOcument Notation."

MongoDB is a server process that runs on Linux, Windows and OS X. It can be run both as a 32 or 64-bit application. We recommend running in 64-bit mode, since Mongo is limited to a total data size of about 2GB for all databases in 32-bit mode.

The MongoDB process listens on port 27017 by default (note that this can be set at start time - please see Command Line Parameters for more information).

MongoDB stores its data in files (default location is /data/db/), and uses memory mapped files for data management for efficiency.

Example data of mongodb


$> bin/mongo --shell slides.js


/*
* Slides for presentation on Mastering the MongoDB Shell.
* Copyright 2010 Mike Dirolf (http://dirolf.com)
* This work is licensed under the Creative Commons
* Attribution-Noncommercial-Share Alike 3.0 United States License. To
* view a copy of this license, visit
* http://creativecommons.org/licenses/by-nc-sa/3.0/us/ or send a
* letter to Creative Commons, 171 Second Street, Suite 300, San
* Francisco, California, 94105, USA.
* Originally given at MongoSF on 4/30/2010.
* Modified and given at MongoNYC on 5/21/2010.
* To use: run `mongo --shell slides.js`
*/
db = db.getSisterDB("shell");
db.dropDatabase();
// some sample data
for (var i = 0; i < 1000; i += 1) {
db.data.save({
x: i
});
} // "slides"
db.deck.save({
slide: 0,
welcome: "to MongoNYC!",
hashtag: "#mongonyc",
mirror: "http://confmirror.10gen.com/"
});
db.deck.save({
slide: 1,
title: "Mastering the MongoDB Shell",
who: "Mike Dirolf, 10gen",
handle: "@mdirolf"
});
db.deck.save({
slide: 2,
question: "what is the shell?",
answer: "a better Powerpoint?"
});
db.deck.save({
slide: 3,
question: "what is the shell?",
answer: "a full JavaScript environment"
});
db.deck.save({
slide: 4,
question: "what is the shell?",
answer: "a reference MongoDB client"
});
db.deck.save({
slide: 5,
"use cases": ["administrative scripting", "exploring and debugging", "learning (and teaching!)"]
});
db.deck.save({
slide: 6,
repl: ["arrows for history", "^L"]
});
db.deck.save({
slide: 7,
"getting help": ["help", "db.help", "db.foo.help"]
});
db.deck.save({
slide: 8,
"show": ["dbs", "collections", "users", "profile"]
});
db.deck.save({
slide: 9,
navigating: "databases",
how: "'use' or 'db.getSisterDB'"
});
db.deck.save({
slide: 10,
navigating: "collections",
how: "dots, brackets, or 'db.getCollection'",
note: "careful with names like foo-bar"
});
db.deck.save({
slide: 11,
"basic operations": ["insert", "findOne", "find", "remove"]
});
db.deck.save({
slide: 12,
"fun with cursors": ["auto-iteration", "it"]
});
db.deck.save({
slide: 13,
"error checking": "auto 'db.getLastError'"
});
db.deck.save({
slide: 14,
"commands": ["count", "stats", "repairDatabase"],
"meta": "listCommands"
});
db.deck.save({
slide: 15,
"pro tip!": "viewing JS source"
});
db.deck.save({
slide: 16,
"getting help": "--help"
});
db.deck.save({
slide: 17,
scripting: "run .js files",
tools: ["--eval", "--shell", "runProgram"]
});
db.deck.save({
slide: 18,
warning: "dates in JS suck"
});
db.deck.save({
slide: 19,
warning: "array iteration in JS sucks"
});
db.deck.save({
slide: 20,
warning: "numeric types in JS suck"
});
db.deck.save({
slide: 21,
so: "why JS?"
});
db.deck.save({
slide: 22,
homework: ["convince 2 friends to try MongoDB", "send feedback @mdirolf"]
});
db.deck.save({
slide: 23,
url: "github.com/mdirolf/shell_presentation",
questions: "?"
}); // current slide
var current = 0; // print current slide and advance
var next = function() {
var slide = db.deck.findOne({
slide: current
});
if (slide) {
current++;
delete slide._id;
delete slide.slide;
print(tojson(slide, null, false));
} else {
print("The End!");
}
}; // go to slide and print
var go = function(n) {
current = n;
next();
}; // repeat the previous slide
var again = function() {
current--;
next();
};


Basic Commands of mongodb



http://www.mongodb.org/display/DOCS/List+of+Database+Commands
http://rezmuh.sixceedinc.com/2010/02/basic-commands-to-get-you-started-with-mongodb.html

Privileged Commands

Certain operations are for the database administrator only. These privileged operations may only be performed on the special database named admin.

Start the server like this:
$> bin/mongod --dbpath /path/to/data

Stop it with Ctrl-C or with kill (but don’t use kill -9, which doesn’t give the server a chance to shut down cleanly and flush data to disk).

Viewing stats without the mongo console:
Visit http://localhost:28017 (28017 is the port the server is running on, plus 1000) to get an overview of what’s going on.
You can also query http://localhost:28017/_status to see the same data that db.serverStatus() returns, but in JSON format.

Use client command console:

$> bin/mongo

> use admin;
> db.addUser('dummy, 'dummy') // create new user with password "dummy"
> db.runCommand("shutdown"); // shut down the database

$> bin/mongo -u dummy -p dummy admin

Create a new Database:

> use new_database
> db.addUser('dummy', 'differentpassword')

$ bin/mongo -u dummy -p differentpassword new_database


Deleting a database:

> use [db name]
> db.dropDatabase()

Working with Collections (Tables):
> show collections

Lists all the available databases:
> show dbs

To get a list of data in a specific collection, use:
> db.[collection name].find()

Directory Global functions and properties:

> for(var o in this) {
print(o);
}
__quiet
chatty
friendlyEqual
doassert
assert
argumentsToArray
isString
isNumber
isObject
tojson
tojsonObject
shellPrint
printjson
shellPrintHelper
shellHelper
help
Random
killWithUris
Geo
connect
MR
MapReduceResult
__lastres__
sleep_
sleep
quit_
quit
getMemInfo_
getMemInfo
_srand_
_srand
_rand_
_rand
_isWindows_
_isWindows
_startMongoProgram_
_startMongoProgram
runProgram_
runProgram
runMongoProgram_
runMongoProgram
stopMongod_
stopMongod
stopMongoProgram_
stopMongoProgram
stopMongoProgramByPid_
stopMongoProgramByPid
rawMongoProgramOutput_
rawMongoProgramOutput
clearRawMongoProgramOutput_
clearRawMongoProgramOutput
removeFile_
removeFile
listFiles_
listFiles
resetDbpath_
resetDbpath
copyDbpath_
copyDbpath
_parsePath
_parsePort
createMongoArgs
startMongodTest
startMongod
startMongodNoReset
startMongos
startMongoProgram
startMongoProgramNoConnect
myPort
ShardingTest
printShardingStatus
MongodRunner
ReplPair
ToolTest
ReplTest
allocatePorts
SyncCCTest
db
hex_md5_
hex_md5
version_
version
i
current
next
__iscmd__
___it___
it

Directory properties of db:

> for(var o in db){
print(o);
}
_mongo
_name
shellPrint
getMongo
getSisterDB
getName
stats
getCollection
commandHelp
runCommand
_dbCommand
_adminCommand
addUser
removeUser
__pwHash
auth
createCollection
getProfilingLevel
dropDatabase
shutdownServer
cloneDatabase
cloneCollection
copyDatabase
repairDatabase
help
printCollectionStats
setProfilingLevel
eval
dbEval
groupeval
groupcmd
group
_groupFixParms
resetError
forceError
getLastError
getLastErrorObj
getLastErrorCmd
getPrevError
getCollectionNames
tojson
toString
currentOp
currentOP
killOp
killOP
getReplicationInfo
printReplicationInfo
printSlaveReplicationInfo
serverBuildInfo
serverStatus
version
printShardingStatus

> db.shell.help()
DBCollection help
db.foo.count()
db.foo.dataSize()
db.foo.distinct( key ) - eg. db.foo.distinct( 'x' )
db.foo.drop() drop the collection
db.foo.dropIndex(name)
db.foo.dropIndexes()
db.foo.ensureIndex(keypattern,options) - options should be an object with these possible fields: name, unique, dropDups
db.foo.reIndex()
db.foo.find( [query] , [fields]) - first parameter is an optional query filter. second parameter is optional set of fields to return.
e.g. db.foo.find( { x : 77 } , { name : 1 , x : 1 } )
db.foo.find(...).count()
db.foo.find(...).limit(n)
db.foo.find(...).skip(n)
db.foo.find(...).sort(...)
db.foo.findOne([query])
db.foo.findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )
db.foo.getDB() get DB object associated with collection
db.foo.getIndexes()
db.foo.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )
db.foo.mapReduce( mapFunction , reduceFunction , <optional params> )
db.foo.remove(query)
db.foo.renameCollection( newName , <droptarget> ) renames the collection.
db.foo.runCommand( name , <options> ) runs a db command with the given name where the 1st param is the colleciton name
db.foo.save(obj)
db.foo.stats()
db.foo.storageSize() - includes free space allocated to this collection
db.foo.totalIndexSize() - size in bytes of all the indexes
db.foo.totalSize() - storage allocated for all data and indexes
db.foo.update(query, object[, upsert_bool, multi_bool])
db.foo.validate() - SLOW
db.foo.getShardVersion() - only for use with sharding

> db.help()
DB methods:
db.addUser(username, password[, readOnly=false])
db.auth(username, password)
db.cloneDatabase(fromhost)
db.commandHelp(name) returns the help for the command
db.copyDatabase(fromdb, todb, fromhost)
db.createCollection(name, { size : ..., capped : ..., max : ... } )
db.currentOp() displays the current operation in the db
db.dropDatabase()
db.eval(func, args) run code server-side
db.getCollection(cname) same as db['cname'] or db.cname
db.getCollectionNames()
db.getLastError() - just returns the err msg string
db.getLastErrorObj() - return full status object
db.getMongo() get the server connection object
db.getMongo().setSlaveOk() allow this connection to read from the nonmaster member of a replica pair
db.getName()
db.getPrevError()
db.getProfilingLevel()
db.getReplicationInfo()
db.getSisterDB(name) get the db at the same server as this onew
db.killOp(opid) kills the current operation in the db
db.printCollectionStats()
db.printReplicationInfo()
db.printSlaveReplicationInfo()
db.printShardingStatus()
db.removeUser(username)
db.repairDatabase()
db.resetError()
db.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into { cmdObj : 1 }
db.serverStatus()
db.setProfilingLevel(level,) 0=off 1=slow 2=all
db.shutdownServer()
db.stats()
db.version() current version of the server

> help()
HELP
show dbs show database names
show collections show collections in current database
show users show users in current database
show profile show most recent system.profile entries with time >= 1ms
use <db name> set curent database to <db name>
db.help() help on DB methods
db.foo.help() help on collection methods
db.foo.find() list objects in collection foo
db.foo.find( { a : 1 } ) list objects in foo where a == 1
it result of the last line evaluated; use to further iterate

If I insert the same Document twice, it does not raise an Error?



Using PyMongo for example, why does inserting the same document (read same _id) more than once not raise an error? When we need to detect if a document already exists in the database, we could try catching DuplicateKeyError on insert. Below we explicitly insert the document with the same _id twice but the exception is never raised. Why?

try:
doc = { _id: '123123' }
db.foo.insert(doc)
db.foo.insert(doc)
except pymongo.errors.DuplicateKeyError, error:
print("Same _id inserted twice:", error)

The answer is that DuplicateKeyError will only be raised if we do the insert in safe mode i.e. db.foo.insert(doc, safe=True). The reason why we do not see an error raised with most drivers but with MongoDB's interactive shell is because the shell does a safe insert by default whereas, with most drivers, it is the developers choice whether or not to use a safe insert.

MongoDB's interactive shell:
> doc = {_id: 123421, name: 'test'};
{ "_id" : 123421, "name" : "test" }
> db.deck.insert(doc)
> db.deck.insert(doc)
E11000 duplicate key error index: shell.deck.$_id_ dup key: { : 123421.0 }

Backup



http://effectif.com/mongodb/mongo-administration

There are basically two approaches to backing up a Mongo database:

1. mongodump and mongorestore are the classic approach. Dumps the contents of the database to files. The backup is stored in the same format as Mongo uses internally, so is very efficient. But it’s not a point-in-time snapshot.
2. To get a point-in-time snapshot, shut the database down, copy the disk files (e.g. with cp) and then start mongod up again.

Alternatively, rather than shutting mongod down before making your point-in-time snapshot, you could just stop it from accepting writes:

> db._adminCommand({fsync: 1, lock: 1})
{
"info" : "now locked against writes, use db.$cmd.sys.unlock.findOne() to unlock",
"ok" : 1
}

To unlock the database again, you need to switch to the admin database and then unlock it:

> use admin
switched to db admin
> db.$cmd.sys.unlock.findOne()
{ "ok" : 1, "info" : "unlock requested" }


If you don’t switch to the admin database first you’ll get an unauthorized error:

> db._adminCommand({fsync: 1, lock: 1})
{
"info" : "now locked against writes, use db.$cmd.sys.unlock.findOne() to unlock",
"ok" : 1
}

> db.$cmd.sys.unlock.findOne()
{ "err" : "unauthorized" }


You can take a point in time snapshot from a slave just as easily as your master database, which avoids downtime. This is one of the reasons that running a slave is so strongly recommended…

What RAID should I use?



http://www.mongodb.org/display/DOCS/Developer+FAQ

We recommend not using RAID-5, but rather, RAID-10 or the like. Both will work of course.

Replication



Do it (did you read the previous section?). Seriously.

Start your master and slave up like this:

$ mongod --master --oplogSize 500
$ mongod --slave --source localhost:27017 --port 3000 --dbpath /data/slave

When seeding a new slave server from master use the --fastsync option.

You can see what’s going on with these two commands:

> db.printReplicationInfo() # tells you how long your oplog will last
> db.printSlaveReplicationInfo() # tells you how far behind the slave is

If the slave isn’t keeping up, how do you find out what’s going on? Check the mongo log for any recent errors. Try connecting with the mongo console. Try running queries from the console to see if everything is working. Run the status commands above to try and find out which database is taking up resources. If you can’t work it out hop on the IRC channel; Mathias says they’ll be very responsive.

What is the difference between MongoDB and RDBMSs



http://sunoano.name/ws/mongodb.html#faqs

MySQL, PostgreSQL, ...
----------------------
Server:Port
- Database
- Table
- Row

MongoDB
--------
Server:Port
- Database
- Collection
- Document

The concept of server and database are very similar. But the concept of table and collection are quite different. In RDBMSs a table is a rectangle. It is all columns and rows. Each row has a fixed number of columns, if we add a new column, we add that column to each and every row.

In MongoDB a collection is more like a really big box and each document is like a little bag of stuff in that box. Each bag contains whatever it needs in a totally flexible manner (read schema-less). However, schema-less does not equal type-less i.e. it is just that any document has its own schema, which it may or may not share with any other document. In practice it is normal to have the same schema for all the documents in collection.

Clone Database



http://www.mongodb.org/display/DOCS/Clone+Database

MongoDB includes commands for copying a database from one server to another.

// copy an entire database from one name on one server to another
// name on another server. omit <from_hostname> to copy from one
// name to another on the same server.
db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>);
// if you must authenticate with the source database
db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>, <username>, <password>);
// in "command" syntax (runnable from any driver):
db.runCommand( { copydb : 1, fromdb : ..., todb : ..., fromhost : ... } );
// command syntax for authenticating with the source:
n = db.runCommand( { copydbgetnonce : 1, fromhost: ... } );
db.runCommand( { copydb : 1, fromhost: ..., fromdb: ..., todb: ..., username: ..., nonce: n.nonce, key: <hash of username, nonce, password > } );

// clone the current database (implied by 'db') from another host
var fromhost = ...;
print("about to get a copy of database " + db + " from " + fromhost);
db.cloneDatabase(fromhost);
// in "command" syntax (runnable from any driver):
db.runCommand( { clone : fromhost } );

What might be a use case for --fork?



The --fork switch forks a mongod process of another exiting process. One use case where this is pretty handy for example is if we SSH into a remote machine and start a MongoDB and leave right away after a new mongod got started.

The fastest way to do so would simply be to append /path/to/mongod --fork to the SSH command line since this will skip creating an intermediate shell and bring up a remote mongod right away.

Are there any Reasons not to use MongoDB?



http://sunoano.name/ws/mongodb.html#faqs

1. We need transactions (read ACID).
2. Our data is very relational.
3. Related to 2, we want to be able to do joins on the server (but can not do embedded objects / arrays).
4. We need triggers on our tables. There might be triggers available soon however.
5. Related to 4, we rely on triggers (or similar functionality) to do cascading updates. or deletes. As for #4, this issue probably goes away once triggers are available.
6. We need the database to enforce referential integrity (MongoDB has no notion of this at all).
7. If we need 100% per node durability.

Use Cases



http://www.mongodb.org/display/DOCS/Comparing+Mongo+DB+and+Couch+DB

It may be helpful to look at some particular problems and consider how we could solve them.

* if we were building Lotus Notes, we would use Couch as its programmer versioning reconciliation/MVCC model fits perfectly. Any problem where data is offline for hours then back online would fit this. In general, if we need several eventually consistent master-master replica databases, geographically distributed, often offline, we would use Couch.
* if we had very high performance requirements we would use Mongo. For example, web site user profile object storage and caching of data from other sources.
* if we were building a system with very critical transactions, such as bond trading, we would not use MongoDB for those transactions -- although we might in hybrid for other data elements of the system. For something like this we would likely choose a traditional RDBMS.
* for a problem with very high update rates, we would use Mongo as it is good at that. For example, updating real time analytics counters for a web sites (pages views, visits, etc.)

Generally, we find MongoDB to be a very good fit for building web infrastructure.

ruby driver of mongodb tutorial



http://api.mongodb.org/ruby/1.0.3/index.html
http://www.mongodb.org/display/DOCS/Ruby+Tutorial
http://github.com/mongodb/mongo-ruby-driver

$> gem update --system
$> gem install mongo
$> gem install bson
$> gem install bson_ext

Making a Connection:
# db = Mongo::Connection.new.db("shell")
# db = Mongo::Connection.new("localhost").db("shell")
db = Mongo::Connection.new("localhost", 27017).db("shell")


Listing All Databases:
m = Mongo::Connection.new # (optional host/port args)
m.database_names.each { |name| puts name }
m.database_info.each { |info| puts info.inspect}


Dropping a Database:
m.drop_database('database_name')


Authentication (Optional):
auth = db.authenticate(my_user_name, my_password)


Getting a Collection:
deck = db.collection("deck")


Inserting a Document:
deck = db['deck']

doc = {"name" => "MongoDB", "type" => "database", "count" => 1,
"info" => {"x" => 203, "y" => '102'}}
deck.insert(doc)
100.times { |i| deck.insert("i" => i) }


Finding the First Document In a Collection using find_one():
my_doc = deck.find_one()
puts my_doc.inspect


Note the _id element has been added automatically by MongoDB to your document. Remember, MongoDB reserves element names that start with _ for internal use.

Counting Documents in a Collection:
puts deck.count()


Using a Cursor to get all of the Documents:
deck.find.each { |row| puts row.inspect }


Getting a Single Document with a Query:
deck.find("i" => 71).each { |row| puts row.inspect }


Getting a Set of Documents With a Query:
deck.find("i" => {"$gt" => 50}).each { |row| puts row }


Querying with Regular Expressions:
deck.find("question" => /w/i).each { |row| puts row }


Creating An Index:
To create an index, you specify an index name and an array of field names to be indexed, or a single field name.
deck.create_index("i")
# deck.create_index([["i", Mongo::ASCENDING]])


Getting a List of Indexes on a Collection:
deck.index_information


Ruby driver example


require 'rubygems' not necessary for Ruby 1.9
require 'mongo'
# 需要先导入slides.js之后,再进行下面的ruby代码测试
db = Mongo::Connection.new.db("mydb")
db = Mongo::Connection.new("localhost").db("mydb")
m = Mongo::Connection.new("localhost", 27017)
db = m.db("shell")
puts db.inspect
m.database_names.each { |name| puts name }
m.database_info.each { |info| puts info.inspect}
db.collection_names.each { |name| puts name }
deck = db['deck']
doc = {"name" => "MongoDB", "type" => "database", "count" => 1,
"info" => {"x" => 203, "y" => '102'}}
deck.insert(doc)
100.times { |i| deck.insert("i" => i) }
my_doc = deck.find_one()
puts my_doc.inspect
puts deck.count()
deck.find.each { |row| puts row.inspect }
deck.find("i" => 71).each { |row| puts row.inspect }
deck.find("i" => {"$gt" => 90}).each { |row| puts row }
deck.find("i" => {"$gt" => 20, "$lte" => 30}).each { |row| puts row }
deck.find("question" => /w/i).each { |row| puts row }
deck.create_index([["i", Mongo::ASCENDING]])
p deck.index_information
db.validate_collection('deck')


References: http://www.mongodb.org/display/DOCS/Developer+Zone

Monday, March 01, 2010

Debugging rails with ruby-debug

1. setup
$> sudo gem install ruby-debug

2. start rails webrick/mongrel web server
$> script/server --debugger

3. using debugger in controller

class PeopleController < ApplicationController def new debugger # 当应用程序访问到此行时,在console中会出现debugger控制台 @person = Person.new end end

4. debugger shell 命令帮助
(rdb:40) help
ruby-debug help v0.10.3
Type 'help ' for help on a specific command

Available commands:
backtrace delete enable help next quit show
break disable eval info p reload source
catch display exit irb pp restart step
condition down finish list ps save thread
continue edit frame method putl set trace

其中比较常用的是next/list/continue/method/backtrace命令。

更多关于ruby-debug,查看以下链接:
http://articles.sitepoint.com/article/debug-rails-app-ruby-debug
http://guides.rubyonrails.org/debugging_rails_applications.html

Wednesday, May 13, 2009

Write excel tool for ruby

require 'rubygems'
require 'writeexcel'

# Create a new Excel Workbook
workbook = Spreadsheet::WriteExcel.new('ruby.xls')

# Add worksheet(s)
worksheet = workbook.add_worksheet
worksheet2 = workbook.add_worksheet

# Add and define a format
format = workbook.add_format
format.set_bold
format.set_color('red')
format.set_align('right')

# write a formatted and unformatted string.
worksheet.write(1, 1, 'Hi Excel.', format) # cell B2
worksheet.write(2, 1, 'Hi Ruby.') # cell B3

# write a number and formula using A1 notation
worksheet.write('B4', 3.14159)
worksheet.write('B5', '=SIN(B4/4)')

# write to file
workbook.close

Tuesday, December 23, 2008

install ruby-mysql gem in mac osx 10.5

首先用dmg包安装的mysql(/usr/local/mysql),来安装mysql-ruby gem包:
$> sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib --with-mysql-include=/usr/local/mysql/include --with-mysql-config=/usr/local/mysql/bin/mysql_config
Building native extensions. This could take a while...
Successfully installed mysql-2.7
1 gem installed

$> sudo gem install dbd-mysql -- --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib --with-mysql-include=/usr/local/mysql/include --with-mysql-config=/usr/local/mysql/bin/mysql_config
Successfully installed dbd-mysql-0.4.2
1 gem installed
Installing ri documentation for dbd-mysql-0.4.2...
Installing RDoc documentation for dbd-mysql-0.4.2...
看上去是装成功了,但实际使用时却抛出了以下错误:
dyld: lazy symbol binding failed: Symbol not found: _mysql_init
Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
Expected in: dynamic lookup

这个主要是因为平台原因造成的,分别查看dmg包和二进制包的mysql_config可看到-arch的差异:
$> /usr/local/mysql/bin/mysql_config
Usage: /usr/local/mysql/bin/mysql_config [OPTIONS]
Options:
--cflags [-I/usr/local/mysql/include -Os -arch ppc -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -DDONT_DECLARE_CXA_PURE_VIRTUAL]
--include [-I/usr/local/mysql/include]
--libs [-L/usr/local/mysql/lib -lmysqlclient -lz -lm]
--libs_r [-L/usr/local/mysql/lib -lmysqlclient_r -lz -lm]
--socket [/tmp/mysql.sock]
--port [0]
--version [5.1.23-rc]
--libmysqld-libs [-L/usr/local/mysql/lib -lmysqld -lz -lm]
$> /usr/local/mysql5/bin/mysql_config
Usage: /usr/local/mysql5/bin/mysql_config [OPTIONS]
Options:
--cflags [-I/usr/local/mysql5/include -g -Os -arch i386 -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT]
--include [-I/usr/local/mysql5/include]
--libs [-L/usr/local/mysql5/lib -lmysqlclient -lz -lm -lmygcc]
--libs_r [-L/usr/local/mysql5/lib -lmysqlclient_r -lz -lm -lmygcc]
--socket [/tmp/mysql.sock]
--port [0]
--version [5.0.67]
--libmysqld-libs [-L/usr/local/mysql5/lib -lmysqld -lz -lm -lmygcc]

而mac osx 10.5的macbook则是i386的:
$> uname -a
Darwin Macintosh.local 9.5.0 Darwin Kernel Version 9.5.0: Wed Sep 3 11:29:43 PDT 2008; root:xnu-1228.7.58~1/RELEASE_I386 i386

所以用i386平台编译的mysql5来编译安装mysql-ruby包:


$> sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql5/bin/mysql_config
Building native extensions. This could take a while...
Successfully installed mysql-2.7
1 gem installed

$> sudo env ARCHFLAGS="-arch i386" gem install dbd-mysql -- --with-mysql-config=/usr/local/mysql5/bin/mysql_config
Successfully installed dbd-mysql-0.4.2
1 gem installed
Installing ri documentation for dbd-mysql-0.4.2...
Installing RDoc documentation for dbd-mysql-0.4.2...

这样才能正确安装上ruby-mysql和dbd-mysql。

Friday, December 05, 2008

Hack ruby String#length

en = 'test'
cn = '一'
p en # >> "test"
p cn # >> "\344\270\200"
puts cn.inspect # >> "\344\270\200"
p "344".oct.to_s(16)
# >> "e4"
p "270".oct.to_s(16)
# >> "b8"
p "200".oct.to_s(16)
# >> "80"
p "344".oct
# >> 228
p "270".oct
# >> 184
p "200".oct
# >> 128
cn.scan(/./).each do |ch|
p ch, ch[0]
end

# hack ruby String#length
puts en.length # >> 4
puts cn.length # >> 3
puts en.scan(/./).length # >> 4
puts cn.scan(/./).length # >> 3
puts en.scan(/./u).length # >> 4
puts cn.scan(/./u).length # >> 1

Thursday, December 04, 2008

在Ruby中将unicode直接量转化成为utf8字符

require 'cgi'
def unicode_utf8(unicode_string)
unicode_string.gsub(/\\u\w{4}/) do |s|
str = s.sub(/\\u/, "").hex.to_s(2)
if str.length < 8
CGI.unescape(str.to_i(2).to_s(16).insert(0, "%"))
else
arr = str.reverse.scan(/\w{0,6}/).reverse.select{|a| a != ""}.map{|b| b.reverse}
# ["100", "111000", "000000"]
hex = lambda do |s|
(arr.first == s ? "1" * arr.length + "0" * (8 - arr.length - s.length) + s : "10" + s).to_i(2).to_s(16).insert(0, "%")
end
CGI.unescape(arr.map(&hex).join)
end
end
end

puts unicode_utf8('test\u4E2Dtest\u6587test\u6D4Btest\u8BD5test')

Sunday, October 12, 2008

MD5 值相同的二个字符串

d131dd02c5e6eec4693d9a0698aff95c 2fcab58712467eab4004583eb8fb7f89 
55ad340609f4b30283e488832571415a 085125e8f7cdc99fd91dbdf280373c5b
d8823e3156348f5bae6dacd436c919c6 dd53e2b487da03fd02396306d248cda0
e99f33420f577ee8ce54b67080a80d1e c69821bcb6a8839396f9652b6ff72a70
d131dd02c5e6eec4693d9a0698aff95c 2fcab50712467eab4004583eb8fb7f89 
55ad340609f4b30283e4888325f1415a 085125e8f7cdc99fd91dbd7280373c5b
d8823e3156348f5bae6dacd436c919c6 dd53e23487da03fd02396306d248cda0
e99f33420f577ee8ce54b67080280d1e c69821bcb6a8839396f965ab6ff72a70
这二个字符串的MD5值会冲突,值为:79054025255fb1a26e4bc422aef54eb4. 求值程序perl版及ruby版本如下:
#!/usr/bin/perl -w

use strict;

my $v1=<<END_V1;
d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c
2f ca b5 87 12 46 7e ab 40 04 58 3e b8 fb 7f 89
55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 71 41 5a
08 51 25 e8 f7 cd c9 9f d9 1d bd f2 80 37 3c 5b
d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6
dd 53 e2 b4 87 da 03 fd 02 39 63 06 d2 48 cd a0
e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 a8 0d 1e
c6 98 21 bc b6 a8 83 93 96 f9 65 2b 6f f7 2a 70
END_V1

my $v2=<<END_V2;
d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c
2f ca b5 07 12 46 7e ab 40 04 58 3e b8 fb 7f 89
55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 f1 41 5a
08 51 25 e8 f7 cd c9 9f d9 1d bd 72 80 37 3c 5b
d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6
dd 53 e2 34 87 da 03 fd 02 39 63 06 d2 48 cd a0
e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 28 0d 1e
c6 98 21 bc b6 a8 83 93 96 f9 65 ab 6f f7 2a 70
END_V2

my $p=join("",map {chr(hex($_))} split /\s+/, $v1);
my $q=join("",map {chr(hex($_))} split /\s+/, $v2);

# print $p, $q;
print `echo -n \'$p\'|md5`; # linux md5sum, mac md5
print `echo -n \'$q\'|md5`; # linux md5sum, mac md5

Ruby版:
#!/usr/bin/ruby -w
require 'digest/md5'

v1=<<END_V1;
d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c
2f ca b5 87 12 46 7e ab 40 04 58 3e b8 fb 7f 89
55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 71 41 5a
08 51 25 e8 f7 cd c9 9f d9 1d bd f2 80 37 3c 5b
d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6
dd 53 e2 b4 87 da 03 fd 02 39 63 06 d2 48 cd a0
e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 a8 0d 1e
c6 98 21 bc b6 a8 83 93 96 f9 65 2b 6f f7 2a 70
END_V1

v2=<<END_V2;
d1 31 dd 02 c5 e6 ee c4 69 3d 9a 06 98 af f9 5c
2f ca b5 07 12 46 7e ab 40 04 58 3e b8 fb 7f 89
55 ad 34 06 09 f4 b3 02 83 e4 88 83 25 f1 41 5a
08 51 25 e8 f7 cd c9 9f d9 1d bd 72 80 37 3c 5b
d8 82 3e 31 56 34 8f 5b ae 6d ac d4 36 c9 19 c6
dd 53 e2 34 87 da 03 fd 02 39 63 06 d2 48 cd a0
e9 9f 33 42 0f 57 7e e8 ce 54 b6 70 80 28 0d 1e
c6 98 21 bc b6 a8 83 93 96 f9 65 ab 6f f7 2a 70
END_V2

nv1 = v1.split(/\s+/).collect{|char| char.hex.chr}.join("")
nv2 = v2.split(/\s+/).collect{|char| char.hex.chr}.join("")

puts Digest::MD5.hexdigest(nv1)
puts Digest::MD5.hexdigest(nv2)


Reference: http://www.mathstat.dal.ca/~selinger/md5collision/

Monday, September 08, 2008

Ruby 正则转义单引号

a = "it's = 'test'"
puts a.gsub(/(')/, '\\\\\\1')

需要将单引号'转义为\',然后存入数据库,本来是用a.gsub(/(')/, "\\'")来处理,发现不正确,查了一下ruby正则,发现:
\' The part of the string after the match
\' 代表是正则匹配位置后面的部分字符串

Thursday, July 31, 2008

Juggernaut for Rails 启动报错

07/31/08 18:00:18 INFO Starting up on 0.0.0.0:443...
/Library/Ruby/Gems/1.8/gems/eventmachine-0.12.0/lib/eventmachine.rb:500:in `start_tcp_server': no acceptor (RuntimeError)
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.0/lib/eventmachine.rb:500:in `start_server'
from script/push_server:216
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.0/lib/eventmachine.rb:224:in `call'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.0/lib/eventmachine.rb:224:in `run_machine'
from /Library/Ruby/Gems/1.8/gems/eventmachine-0.12.0/lib/eventmachine.rb:224:in `run'

google后,才发现在mac上用普通用户去使用443这个1024以下的系统使用端口号,因为权限问题才导致服务无法成功启动。

在mac上安装RMagick的一个问题及其解决方法

从http://www.imagemagick.org/script/binary-releases.php上下载imagemagick,安装到了/Users/yu/Programs/ImageMagick下,并在~/.profile里设置好以下二个环境变量,在安装过程中extconf.rb会用到,及以后ruby中require "RMagick"会用到。
$> export MAGICK_HOME="/Users/yu/Programs/ImageMagick"
$> export DYLD_LIBRARY_PATH="/Users/yu/Programs/ImageMagick/lib"

然后直接在shell中运行命令:
$> sudo gem install rmagick
碰到以下错误:
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install rmagick --local
checking for Ruby version >= 1.8.2... yes
checking for gcc... yes
checking for Magick-config... yes
checking for ImageMagick version >= 6.3.0... yes
checking for HDRI disabled version of ImageMagick... yes
checking for stdint.h... yes
checking for sys/types.h... yes
checking for magick/MagickCore.h... no
Can't install RMagick 2.5.2. Can't find MagickCore.h.

*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

Provided configuration options:
--with-opt-dir
--without-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby

在rmagick的安装目录中运行
$> ruby extconf.rb
却是正确的,但sudo则会报错。
只能到Directory Utility中enable root,用root身份来安装。在shell中用root身份进入后再执行最早做的二个export变量的动作,运行:
$> gem install rmagick
Building native extensions. This could take a while...
Successfully installed rmagick-2.5.2
1 gem installed
$> irb -rubygems -r RMagick
>>
成功!
不知道其他用mac的同学安装rmagick2.x版本是否碰到我这个问题,安装RMagick1.x版本跟2.x版本是不一样的。

Monday, June 16, 2008

javascript ruby interpreter -- johnson

require 'johnson'

puts Johnson.evaluate("4 + 4") # => 8
puts Johnson.evaluate("4 + foo", :foo => 4) # => 8

js_function_test = "foo = function (bar) { return parseInt(bar); };"
puts Johnson.parse(js_function_test)
puts Johnson.parse("alert(33)")

ctx = Johnson::Runtime.new
ctx['alert'] = lambda { |x| puts x }
puts ctx.evaluate('alert("Hello world!");')


j = Johnson::Runtime.new

# Introduce a new JavaScript function, named print,
# which calls a Ruby function
# j.print = lambda {|msg| puts msg}; # => undefined method `print=' for #<Johnson::Runtime:0x4e8c70>
j[:print] = lambda {|msg| puts msg};

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
j.evaluate("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
j.evaluate("alert('text');");

class Monkey
def eat
puts "Nom, nom, nom, bananas!"
end
end

j = Johnson::Runtime.new

# toss a monkey into the runtime
m = Monkey.new
j[:m] = m

# add a JSland function to our monkey...
j.evaluate("m.chow = function() { this.eat() }")

# ...and now it's available as an instance method on our native Ruby object!
m.chow

Tuesday, June 10, 2008

如何用ruby验证字符串中是否包括中文字


def include_chinese_char?(str)
# /[\u4e00-\u9fa5]/ unicode 中文字符集范围 即: 一-龥
/[一-龥]/ =~ str
end

puts include_chinese_char?("ruby regexp.")
puts include_chinese_char?("中 ruby regexp.")
puts include_chinese_char?("ruby 中 regexp.")
# >> nil
# >> 0
# >> 5

字符串与unicode编码的相互转换

unicode编码简而言之就是将每一个字符用16位2进制数标识。但是通常都用4位的16进制数标识。
例如:
1)中文字符串"你好"的unicode码为:\u4f60\u597d;
2)英文字符串"ab"的unicode码为:\u0061\u0062;
其中\u是标识unicode码用的,后面的4位16进制数则是对应字符的unicode码。

1、unicode编码规则
unicode码对每一个字符用4位16进制数表示。具体规则是:将一个字符(char)的高8位与低8位分别取出,转化为16进制数,
如果转化的16进制数的长度不足2位,则在其后补0,然后将高、低8位转成的16进制字符串拼接起来并在前面补上"\u" 即可。

2、用java代码说明unicode的编码规则 [java的unicode解码编码的代码详见javaeye的帖子]

public class Unicode {

public static void main(String[] args) {
char c = '一'; // 一(4e00)是unicode中文字符集首字,龥(9fa5)是unicode中文字符集尾字
int i, j;
i = c & 0xFF;
j = c >>> 8;
System.out.println("Original character is: " + c);
System.out.println("low 8 bit is: " + i);
System.out.println("high 8 bit is: " + j);
}

}
$> javac Unicode.java
$> java Unicode
Original character is: 一
low 8 bit is: 0
high 8 bit is: 78
78转为16进制为4e,将高、低8位转成的16进制字符串拼接起来即为\u4e00,这就是中文字"一"的unicode编码。
在ajax请求返回的responseText或者json数据可以先在服务器端编码为unicode格式传给客户端浏览器,这样客户端的页面无论是什么编码,js都可以很好的处理返回的内容。
4e00的十进制值为4 * 16 * 16 * 16 + 14 * 16 * 16 + 0 * 16 + 0 = 19968
网页中则可以用&#19968;来表示中文字"一",这样不论网页以何种编码,页面始终都可以正常显示,而不会出现乱码。这种方法以前在做wap项目常常将页面上所有中文字都用unicode编码后发布,就是为了避免乱码问题。

3、javascript代码,验证字符串中是否包括中文字
/[\u4e00-\u9fa5]/.test(str)

4、ruby中验证字符串中是否包括中文字
/[一-龥]/ =~ str

Reference:
http://haoi77.javaeye.com/blog/198840

Friday, May 30, 2008

json for ruby [jruby] install and usage

$> sudo gem install json
$> sudo jruby -S gem install json_pure

require 'rubygems'
require 'json'

class Range
def to_json(*a)
{
'json_class' => self.class.name,
'data' => [ first, last, exclude_end? ]
}.to_json(*a)
end

def self.json_create(o)
new(*o['data'])
end
end

puts (1..10).to_json
p JSON.parse((1..10).to_json)
puts JSON.parse((1..10).to_json) == (1..10)

json =<<-"JSON"
{
"hasItems": true,
"totalItems": 5,
"orderId": "xxx-xxxxx-xxx",
"hasDetails": true,
"details": [{"item": "2323-2323", "number": 2, "price": 2.00}, {"item": "2323-2324", "number": 3, "price": 3.00}]
}
JSON
p JSON.parse(json)["hasItems"] # => true
p JSON.parse(json)["totalItems"] # => 5

notice: keys and values in json string must be quoted.

Wednesday, May 21, 2008

ruby script/server lighttpd

在一个jruby on rails目录下面运行以下命令时报错:
$> ruby script/server lighttpd
.....
Couldn't find any pid file in '/Users/yu/Sites/RubyOnRails/tmp/pids' matching 'dispatch.[0-9]*.pid'
(also looked for processes matching "/Users/yu/Sites/RubyOnRails/public/dispatch.fcgi")
在lighttpd的log中看到如下信息:
2008-05-21 00:23:33: (log.c.75) server started
2008-05-21 00:23:33: (mod_fastcgi.c.1029) the fastcgi-backend /Users/yu/Sites/RubyOnRails/public/dispatch.fcgi failed to start:
2008-05-21 00:23:33: (mod_fastcgi.c.1033) child exited with status 9 /Users/yu/Sites/RubyOnRails/public/dispatch.fcgi
2008-05-21 00:23:33: (mod_fastcgi.c.1036) If you're trying to run PHP as a FastCGI backend, make sure you're using the FastCGI-enabled version.
You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' in the output, NOT '(cgi)' NOR '(cli)'.
For more information, check http://trac.lighttpd.net/trac/wiki/Docs%3AModFastCGI#preparing-php-as-a-fastcgi-programIf this is PHP on Gentoo, add 'fastcgi' to the USE flags.
2008-05-21 00:23:33: (mod_fastcgi.c.1340) [ERROR]: spawning fcgi failed.
2008-05-21 00:23:33: (server.c.908) Configuration of plugins failed. Going down.

经google后才发觉script/server lighttpd只能用于ruby on rails的项目上,通过以下命令:
$> /usr/local/lighttpd/bin/spawn-fcgi -f /Users/yu/Sites/RubyOnRails/public/dispatch.fcgi -p 12000 -s /tmp/rails-fcgi.socket
会得到成功的结果如下:
spawn-fcgi.c.197: child spawned successfully: PID: 2275
而在jruby的项目下调用spawn-fcgi则会报脚本错误。

另附dispatch.sh[reference: http://www.javaeye.com/topic/168989]


#!/bin/sh

DISPATCH_PATH=/Users/yu/Sites/cv2/public/dispatch.fcgi
SOCKET_PATH=//Users/yu/Sites/cv2/tmp/sockets
RAILS_ENV=developement
export RAILS_ENV

case "$1" in

start)
for num in 0 1 2
do
/Users/yu/Programs/lighttpd/bin/spawn-fcgi -f $DISPATCH_PATH -s $SOCKET_PATH/rails.socket-$num
done
;;

stop)
killall -9 dispatch.fcgi
;;

restart)
$0 stop
$0 start
;;

*)
echo "Usage: dispatch.sh {start|stop|restart}"
;;

esac

exit 0

Thursday, April 24, 2008

rails2.0.2 fastcgi sqlite3 setup

# add below line to /etc/hosts
127.0.0.1 www.test.com

# add below green lines at the end of lighttpd.conf file


$HTTP["host"] == "www.test.com" {
server.document-root = "/Users/test/Sites/RubyOnRails/public"
server.errorlog = "/Users/test/Sites/lighttpd/logs/rails.lighttpd.error.log"
server.indexfiles = ( "dispatch.fcgi", "index.html" )
accesslog.filename = "/Users/test/Sites/lighttpd/logs/rails.access.log"
server.error-handler-404 = "/dispatch.fcgi"
fastcgi.server = ( ".fcgi" =>
( "localhost" =>
(
"socket" => "/tmp/rails-fastcgi.socket",
"bin-path" => "/Users/test/Sites/RubyOnRails/public/dispatch.fcgi",
"bin-environment" => ("RAILS_ENV" => "development"),
"max-procs" => 3,
"min-procs" => 1
)
)
)
}

wget http://www.sqlite.org/sqlite-3.5.8.tar.gz
tar zxvf sqlite-3.5.8.tar.gz
cd sqlite-3.5.8
./configure --prefix=/usr/local/sqlite358
make
sudo make install

# create db files under rails app db folder
cd /Users/test/Sites/RubyOnRails/db
/usr/local/sqlite358/bin/sqlite3 development.sqlite3
/usr/local/sqlite358/bin/sqlite3 test.sqlite3
/usr/local/sqlite358/bin/sqlite3 production.sqlite3

sudo gem install sqlite3-ruby

# restart lighttpd, and request url: http://www.test.com

Monday, April 21, 2008

install fastcgi and ruby-fastcgi

curl -O http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
tar xzvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure --prefix=/usr/local/fcgi240
make
sudo make install
cd ..

# install Ruby-FastCGI gem

curl -O http://rubyforge.iasi.roedu.net/files/fcgi/ruby-fcgi-0.8.7.tar.gz
tar xzvf ruby-fcgi-0.8.7.tar.gz
cd ruby-fcgi-0.8.7
/usr/local/bin/ruby install.rb config -- --with-fcgi-dir=/usr/local/fcgi240
/usr/local/bin/ruby install.rb setup
sudo /usr/local/bin/ruby install.rb install
cd ..

# or install Ruby-FastCGI gem using:
$> sudo gem install fcgi -- --with-fcgi-dir=/usr/local/fcgi240

# Building native extensions. This could take a while...
# Successfully installed fcgi-0.8.7
# 1 gem installed

Monday, April 07, 2008

Ruby http-access2

require 'pp'
require 'http-access2'
client = HTTPAccess2::Client.new()
# head = client.head('http://www.google.com')
# p head.header['Server'][0]

# content = client.get_content('http://www.google.com')
# puts content

# response = client.get('http://www.google.com/')
# pp response.header.get
# puts response.header.request_uri
# puts response.header.response_status_code
# pp response.header
# puts response.dump
# puts response.contenttype
# puts response.version
# puts response.status
# puts response.reason
# puts response.body.content
# puts response.content
# pp response.methods.sort
# puts response.content

=begin

== WebAgent::CookieManager Class

Load, save, parse and send cookies.

=== Usage

## initialize
## load from IE7 cookie file
cm = WebAgent::CookieManager.new("C:\Documents and Settings\user\Local Settings\Temporary Internet Files")

## load cookie data
cm.load_cookies()

## parse cookie from string (maybe "Set-Cookie:" header)
cm.parse(str)

## send cookie data to url
f.write(cm.find(url))

## save cookie to cookiefile
cm.save_cookies()


=== Class Methods

-- CookieManager::new(file=nil)

create new CookieManager. If a file is provided,
use it as cookies' file.

=== Methods

-- CookieManager#save_cookies(force = nil)

save cookies' data into file. if argument is true,
save data although data is not modified.

-- CookieManager#parse(str, url)

parse string and store cookie (to parse HTTP response header).

-- CookieManager#find(url)

get cookies and make into string (to send as HTTP request header).

-- CookieManager#add(cookie)

add new cookie.

-- CookieManager#load_cookies()

load cookies' data from file.


== WebAgent::CookieUtils Module

-- CookieUtils::head_match?(str1, str2)
-- CookieUtils::tail_match?(str1, str2)
-- CookieUtils::domain_match(host, domain)
-- CookieUtils::total_dot_num(str)


== WebAgent::Cookie Class

=== Class Methods

-- Cookie::new()

create new cookie.

=== Methods

-- Cookie#match?(url)

match cookie by url. if match, return true. otherwise,
return false.

-- Cookie#name
-- Cookie#name=(name)
-- Cookie#value
-- Cookie#value=(value)
-- Cookie#domain
-- Cookie#domain=(domain)
-- Cookie#path
-- Cookie#path=(path)
-- Cookie#expires
-- Cookie#expires=(expires)
-- Cookie#url
-- Cookie#url=(url)

accessor methods for cookie's items.

-- Cookie#discard?
-- Cookie#discard=(discard)
-- Cookie#use?
-- Cookie#use=(use)
-- Cookie#secure?
-- Cookie#secure=(secure)
-- Cookie#domain_orig?
-- Cookie#domain_orig=(domain_orig)
-- Cookie#path_orig?
-- Cookie#path_orig=(path_orig)
-- Cookie#override?
-- Cookie#override=(override)
-- Cookie#flag
-- Cookie#set_flag(flag_num)

accessor methods for flags.

=end

ActiveRecord::Base transaction explain


#---
# Excerpted from "Agile Web Development with Rails, 2nd Ed.",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material,
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose.
# Visit http://www.pragmaticprogrammer.com/titles/rails2 for more book information.
#---
# $: << File.dirname(__FILE__)

require "logger"
require "rubygems"
require "active_record"

ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:user => "root",
:password => "",
:database => "test"
)

# InnoDB table: users, accounts
ActiveRecord::Schema.define do

create_table :accounts, :force => true do |t|
t.column :number, :string
t.column :balance, :decimal, :precision => 10, :scale => 2, :default => 0
end

create_table :users, :force => true do |t|
t.column :name, :string
t.column :password, :string
end

end

class User < ActiveRecord::Base
end

class Account < ActiveRecord::Base
end

Account.transaction do
Account.create(:balance => 100, :number => "12345")
User.create(:name => 'test', :password => "123456")
raise 'error!!!'
# 如果transaction内部所有SQL都正确执行并且通过ActiveRecord::Base validates,在block中没有raise的话则正确写入数据库
# 如果有SQL错误或者validates没有通过,或者是transaction中有raise错误,则事务会ROLLBACK
# ROLLBACK 是基于事务表(如InnoDB表)的,非事务表(如MyISAM表)则需要在程序中手工回滚
end

Thursday, March 20, 2008

hostname not match (OpenSSL::SSL::SSLError)

1. install soap4r
$> gem install soap4r
2. run soap request
driver = SOAP::RPC::Driver.new
driver.wiredump_dev = STDERR if $DEBUG
driver.wiredump_file_base = "soap_result"
......
3.get error as below:


C:/ruby/lib/ruby/1.8/openssl/ssl.rb:91:in `post_connection_check': hostname not match (OpenSSL::SSL::SSLError)
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:1052:in `post_connection_check'
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:1467:in `connect'
from C:/ruby/lib/ruby/1.8/timeout.rb:56:in `timeout'
from C:/ruby/lib/ruby/1.8/timeout.rb:76:in `timeout'
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:1454:in `connect'
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:1311:in `query'
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:932:in `query'
from C:/ruby/lib/ruby/gems/1.8/gems/httpclient-2.1.2/lib/httpclient.rb:2131:in `do_get_block'
... 7 levels...
from C:/ruby/lib/ruby/gems/1.8/gems/soap4r-1.5.8/lib/soap/rpc/proxy.rb:143:in `call'
from C:/ruby/lib/ruby/gems/1.8/gems/soap4r-1.5.8/lib/soap/rpc/driver.rb:181:in `call'

4. google this problem and get resolution as below:
driver.options['protocol.http.ssl_config.verify_mode'] = OpenSSL::SSL::VERIFY_NONE
or
driver.options['protocol.http.ssl_config.verify_mode'] = 0
or
driver.options['protocol.http.ssl_config.verify_mode'] = ""
or
driver.options['protocol.http.ssl_config.verify_mode'] = OpenSSL::SSL::VERIFY_PEER
driver.options['protocol.http.ssl_config.ca_file'] = '/etc/ssl/certs/certification_authority.crt'
driver.options['protocol.http.ssl_config.client_cert'] = '/etc/ssl/certs/client.cert'
driver.options['protocol.http.ssl_config.client_key'] = '/etc/ssl/certs/client.key'

Reference: http://www.fngtps.com/2007/03/openssl-ssl-sslerror-with-soap4r-and-the-rubyforge-gem