Thursday, August 28, 2008

Ruby notes(2) - OO

Function

Definition
def method([arg1, ..., argn,..., *arg, &arg])
    statements
end
Singleton Method
def obj.method([arg1, ..., argn,..., *arg, &arg])
    statements [rescue [exception [, exception...]] [=>var] [then] code ]... [else code ] [ensure code] end

undef method    #make the method undefined.yield(expr...)    #execute the block passed in to current method.
super(expr...)    #execute the method in super class.
super                #execute the method in super class with current method's arguments are passed in.
yield
alias newmethodname oldmethodname
Method Invocation
(*) General
method ([param1 ...[, *param [, &param]]])
method [param1 ...[, *param [, &param]]]
obj.method([param1 ...[, *param [, &param]]])
obj.method [param1 ...[, *param [, &param]]])
obj::method([param1 ...[, *param [, &param]]])
obj::method [param1 ...[, *param [, &param]]]
(*) With blocks
methdo { |[var1 [, var2 ...]]|
    code
}
method do |[var1 [, var2 ...]]|
    code goes here
end
A block has its own local scope and code within a block can access local variables of outer scope.

Class

Definition
class classname [ < superclass]
    code
end

classname MUST be a constant instead of a global or local variable. Class definition introduces a new scope. In order for different definitions of the same class to be merged, one of the two conditions must be met:
(1) A class does not include superclass
(2) if a class definition includes superclass, superclass MUST match super class of previous declaration.

class << object
    code
end

Creation
Instances of a class are created by using method new.
str = String.new or str = String::new

Modules

Definition
module modulename
    code
end
modulename MUST be a constant instead of a global or local variable. Module definition introduces a new scope. Different definitions of the same module are merged.

Sunday, August 24, 2008

Locale in linux/unix

(1) Get locale information
Use command locale.

locale    //get current locale environment for each locale category defined by the LC_* environment variables.
locale -a //output names of all available locales
locale -m //Write names of available charmaps.
locale -k LC_CTYPE //Write names and values of selected keywords (In this case, it is "LC_CTYPE").

command: localedef
"The  localedef  program  reads  the  indicated  charmap  and input files, compiles them to a form usable by the locale(7) functions in the C library, and places the six output files in the outputpath directory."

When a program looks up locale dependent values, it does this according to the following environment variables, in priority order:

  1. LANGUAGE
  2. LC_ALL
  3. LC_xxx, according to selected locale category: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES, ...
  4. LANG

Variables whose value is set but is empty are ignored in this lookup.
Set locale environment variable (E.g. LC_ALL, LANG...):
ll_cc.encoding  E.g. de_DE.UTF-8, zh_CN.UTF-8
ll_cc@variant  E.g. de_DE@euro, sr_RS@latin
"There is also a special locale, called ‘C’. When it is used, it disables all localization: in this locale, all programs standardized by POSIX use English messages and an unspecified character encoding (often US-ASCII, but sometimes also ISO-8859-1 or UTF-8, depending on the operating system)."
http://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-POSIX-Locale

C lib:
char *setlocale(int category, const char *locale): set the current locale.

Ruby notes-basic(1)

Semicolons and newline characters are interpreted as ending of a statement. +, = or \ can be use as line continuation characters.
Comments
Single-line comments: Comments extend from # to the end of a line.
Multi-line comments:

=begin
comments go here
=end
Note: '=begin' and '=end' must appear at the beginning of a line.
Integer literals: 123, 0123(octal), 0xf34(hex), 0b1123(binary), ?d(char code for 'd')
Float-point literals: 23.45, 3e4, 4E10, 5e+39
String literals:
double quotations: allow substitution and escape character sequences.
single quotations: don't allow substitution and escape character sequences except \\ and \'.
Adjacent strings are concatenated automatically. "abc""def" => "abcdef"
Command execution: `command`. The syntax is similar to the counterpart of bash. It allows substituion and escape character sequences. The output generated by execution of the command is converted to a string.
here documents:

<<EOF
content goes here
EOF
The string is in double quotations.
<<"EOF"
content goes here
EOF
<<'EOF'
content goes here
EOF
The string is in single quotations.
<<`EOF`
command goes here
EOF
The string is in back quotes.
<<-EOF
command goes here
EOF
The delimiter ('EOF' in this example) needs not be at the beginning of a line.

Symbols:
"A symbol is an object corresponding to an identifier or variable"
:name    #symbol for 'name'
:$name   #symbol for variable 'name'
Array
[], [1,2,3], [1,[2,3]]
%w(str1 str2 str3) => ["str1", "str2", "str3"]
Dictionary(Map, or Hash):
{key => value}
Regular expression:
/pattern/
/pattern/options

Alternatives:
%!string! and %Q!string! are equivalent to "string".
%q!string! is equivalent to 'string'
%x!command! is equivalent to `command`.
%r!pattern!

Variable

Type Description Example Note
global variables can be accessed globally by and program. $var Uninitialized global variables are set to nil.
instance variables that belong to an object. @var
class variables that belong to a class. @@var Class variables must be initialized before they are accessed in methods.
contants Constants as you know in other languages Var must begin with an upper case letter.May not be defined in methods.
local Local variables. var must begin with a lowercase letter or _

Variable substitutions: #{varname}. E.g. #{filename}, #{@conf}, #{$stdin} 
Variable assignments
var = value
var1, var2, ..., *varn = expr1, expr2, ..., *exprn
Operators:

expr?expr1:expr2
    The same as the tertiary operator in C/C++.
defined? varname
    #return a description about the variable/method or nil.

Control statements

Name Syntax Alternatives
if if cond [then]
    code
[elsif cond [then]
    code]
[else
    code]
end
code if cond
unless unless cond [then]
    code
[else
    code]
end
code unless cond
case case expr
[when expr [,expr ...] [then]
    code ]...
[else
    code]
end
 
while while cond [do]
    code
end
(1)code while cond
(2)begin code end while cond.
Note: code is executed once before cond is evaluated.
until until cond [do]
    code
end
(1) code until cond
(2) begin code end until cond
Note: code is executed once before cond is evaluated.
for for var[, var2 ...] in expr [do]
    code
end
expr do |var [,var...]|
    code
end
break Break from look  
next like continue in C++  
redo re-execute the loop body once without evaluation of conditional expression.  
retry re-execute a call to a method  
begin begin
    code
[rescue [exception_class [, excep_cls...]] [=>var] [then]
    code ]...
[else
    code ]
[ensure
    code ]
end
Code in ensure clause is always executed.
Code in else clause is executed only when no exceptions are raised.
Code in rescue clause is executed when exception is caught.
rescue code rescue expr Evaluate the expr only if an exception is caught.
raise raise exception_class, message
raise exception_object
raise message
raise
Raise an exception.
To call raise in a rescue clause will re-raise the exception.
BEGIN BEGIN{
    code
}
Code to be executed before the program is run.
END END{
    code
}
Code to be executed when the interpreter quits.

Monday, August 18, 2008

Linux shared object (.so)

Search path the linker uses to locate shared object files (Following content is from manual of command ld):
"1.  Any directories specified by -rpath-link options.
2.  Any  directories  specified  by -rpath options.  The difference between -rpath and -rpath-link is that directories specified by -rpath  options are included in the executable and used at run-time, whereas the -rpath-link option is only effective at link time. It is for the native linker only.
3.  On  an  ELF system, if the -rpath and "rpath-link" options were not used, search the contents of the environment variable "LD_RUN_PATH". It is for the native linker only.
4.  On  SunOS, if the -rpath option was not used, search any directories specified using -L options.
5.  For a native linker, the contents of the  environment  variable "LD_LIBRARY_PATH".
6.  For  a  native  ELF  linker, the directories in "DT_RUNPATH" or "DT_RPATH"  of  a  shared  library  are  searched  for shared libraries  needed  by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
7.  The default directories, normally /lib and /usr/lib.
8.  For  a  native  linker  on  an  ELF system, if the file /etc/ld.so.conf  exists,  the list of directories found in that file."

Resources
A good tutorial about static, shared dynamic and loadable linux libraries
A Chinese post introducing using and generation of linux shared object libraries
List of GNU tools which manipulate linux libraries

Saturday, August 09, 2008

API design

Many times I struggled with API design dilemma which I didn't know how to solve perfectly. As all know, API design is important. However, it is difficult to get it right. Actually, nothing is absolutely right or wrong. What matters is tradeoff. I googled and found a pretty good article (written by Michi Henning from ZeroC) which give insight about API design. The article is here.

I agree with most of the author's viewpoints. Here I just would like to outline the elaborate article. Most following content is from the article. Gradually, I will add my own viewpoints and guidelines about how to design good API.
The effect of bad-designed API:
"Even minor and quite innocent design flaws have a tendency to get magnified out of all proportion because APIs are provided once, but are called many times. If a design flaw results in awkward or inefficient code, the resulting problems show up at every point the API is called. In addition, separate design flaws that in isolation are minor can interact with each other in surprisingly damaging ways and quickly lead to a huge amount of collateral damage.
The lower in the abstraction hierarchy an API defect occurs, the more serious are the consequences."
How to design good API:
"(1) APIs should be designed from the perspective of the caller.
     APIs should be documented before they are implemented.
(2) An API must provide sufficient functionality for the caller to achieve its task.
(3) An API should be minimal, without imposing undue inconvenience on the caller.
(4) APIs cannot be designed without an understanding of their context.
(5) General-purpose APIs should be "policy-free;" special-purpose APIs should be "policy-rich."
(6) Good APIs don't pass the buck.
(7) Good APIs are ergonomic. "