Saturday, September 30, 2006

To collapse and hide a section of code in Visual Studio 2005

The #Region directive enables you to collapse and hide sections of code in Visual Basic files. The #Region directive lets you specify a block of code that you can expand or collapse when using the Visual Studio code editor. The ability to hide code selectively makes your files more manageable and easier to read. For more information, see How to: Outline and Hide Code.

#Region directives support code block semantics such as #If...#End If. This means they cannot begin in one block and end in another; the start and end must be in the same block. #Region directives are not supported within functions.

To collapse and hide a section of code
Place the section of code between the #Region and #End Region statements, as in the following example:

#Region "This is the code to be collapsed"
Private components As System.ComponentModel.Container
Dim WithEvents Form1 As System.Windows.Forms.Form

Private Sub InitializeComponent()
components = New System.ComponentModel.Container
Me.Text = "Form1"
End Sub
#End Region


The #Region block can be used multiple times in a code file; thus, users can define their own blocks of procedures and classes that can, in turn, be collapsed. #Region blocks can also be nested within other #Region blocks.

Note
Hiding code does not prevent it from being compiled and does not affect #If...#End If statements.

^ 在一个method范围内是不能使用Region的,如果要实现“收起放开”,需要使用CTRL+M and then CTRL+H以及CTRL+M and then CTRL+U.

@ Hide Selection
Collapses the currently selected text. Text must be selected to use this command. Shortcut keys are CTRL+M and then CTRL+H.

@ Stop Hiding Current
Removes the outlining information for the currently selected user-defined region. Shortcut keys are CTRL+M and then CTRL+U.
Note This command becomes available in Visual C# and Visual J# when Automatic Outlining is turned off or Stop Outlining is selected. Not available in Visual Basic.

Friday, September 29, 2006

Determining the Number of Days in a Month with Javascript

ATTENTION: The following words are quoted from great work of Mr. Charlie published at www.bigbold.com on Thu May 25 08:02:48 GMT 2006

Essentially, writing some code to determine the number of days in a given month of a given year with javascript is not the worlds most difficult task. It is the type of exercise that one would expect to be given as a newbie developer during a lab or lecture. The solution normally involves determining if the month is February, an month with 30 days or a month with 31 days, then (if February) checking if the year is a leap year. All these tests add up, however, and add several lines of code to your .js file. They are also unnecessary!

Apparently, the javascript Date function allows you to overflow the day number parameter that you pass, creating a date in the next month. Deliberately overflowing the day parameter and checking how far the resulting date overlaps into the next month is a quick way to tell how many days there were in the queried month. Here is a function that does this:

function daysInMonth(iYear, iMonth) {
return (32 - new Date(iYear, iMonth, 32).getDate());
}


N.B.: iMonth is zero based, so 0 represents January, 1 represents February, 2 represents March and 11 represents December. iYear is not zero based, this is the actual calendar year number. (2006 is actually 2006)

Pray that the browser developers know the correct way to determine whether a year is a leap year! (It's more complicated than a simple mod 4 == 0) Here is a quote from Wikipedia's page on leap years: " The Gregorian calendar, the current standard calendar in most of the world, adds a 29th day to February in all years evenly divisible by 4, except for centennial years (those ending in '00'), which receive the extra day only if they are evenly divisible by 400. Thus 1600, 2000 and 2400 are leap years but 1700, 1800, 1900 and 2100 are not. "

How does this function work? It is quite simple. When the Date() function is given a day number that is greater than the number of days in the given month of the given year, it wraps the date into the next month. The getDate() function returns the day of the month, starting from the beginning of the month that the date is in. So, day 32 of March is considered to be day 1 of April. Subtracting 1 from 32 gives the correct number of days in March!


API : Internet Business from where?

I think I might should start my Internet Business from and on the great ones' APIs, actually, mighty services and resources.

Google API
Flickr API
Live API
ebay API
amazon API
Yahoo API

不是曾经就告诉过自己一定要站在巨人的肩膀上发展吗?为什么不通过API呢?

Thursday, September 28, 2006

ASP.NET Server Control File Upload

Reference:
http://www.codeguru.com/csharp/sample_chapter/print.php/c12593__1/

Internet Application Architecture : Tiers ? Layers?

这两天考虑最多的一个问题是Tiers/Layers问题。这是一个争论广泛似乎没有答案的问题。下午试用Google Pages做网站时受了启发。任何一种架构,存在了就是合理的,就应是满足了某种需求解决了某类问题。所以,为什么一定要为所有的问题找一个统一的解决放案呢?互联网网站有大有小、有简单的有复杂的、有专一的有综合的、有长久发展的有临时实验的,千姿百态,共性的东西其实并不多。这样的话,寻找一种能够包容所有问题域的解决方案似乎就挺不务实的。一个方案解决所有问题,听上去似乎很好:统一了开发过程。可是执行起来就有问题了:无论网站大小,都用同样的架构,写同样多的基础代码。如果做十个网站有八个是短平快且不相似的,那开发成本是提高了而不是降低了。

大型的网站,像Amazon,ebay,Taobao,Yahoo,My Space,其架构、技术、开发都是工业级的,自有Enterprise的方法和技术。
专一的网站:Flickr,Delicious,BaseCamp等所谓Web2.0网站,有Getting Real思想指导下的过程。
普通的网站,比如那些企业门户,又可以用简单快速的技术实现。
个人的网站:比如Blog,比如个人portal,更可以根本不需要编程就实现,比如使用Windows Live Space,Google Pages。

不同类型的网站,可以使用不同的架构、不同的语言、不同的过程来实现。所以,对于Tiers/Layers问题,如果说Case by Case不是一个好的答案,那么Type by Type应该算是一个还好的答案。





Recommended Blogs on Architecture

Web Applications: N-Tier vs. N-Layer - Benefits and Trade-Offs

Should all apps be n-tier?

Avoid Chatty Interfaces Between the Tiers in Your ASP.NET Web Application

What is n-Tier Architecture?

N-Tier Web Applications using ASP.NET 2.0 and SQL Server 2005

http://msdn.microsoft.com/architecture/shareideas/sharebrowseblogs/

Wednesday, September 27, 2006

Transact-SQL

@ Database developers must hava a thorough knowledge of Transact-SQL to read data from and write data to SQL Server database. Using Transact-SQL is the only way to work with the data.

@ Transact-SQL is a fairly simple language; Yet many develpers don't spend the time to understand it, and they end up writing less-than-desirable code.
@ The key to creating well-perfomring Transact-SQL queries is to think in terms of sets instead of row-by-row operations, as you would be in a procedural system.

@ A database developer must ensure that queryies use as few tables as possible to statify the data requirements.

@ Avoid the temptation of creating monolithic, do-everything queries that can be sued to statisfy the requirements of many different parts of the applicaton, or that return data from additional tables just in case it might be necessary in the future.

Tuesday, September 26, 2006

ASP.NET Architecture BLL

How to centralize these business rules into a Business Logic Layer (BLL) that serves as an intermediary for data exchange between the presentation layer and the DAL.
In a real-world application, the BLL should be implemented as a separate Class Library project; however, for these tutorials we'll implement the BLL as a series of classes in our App_Code folder in order to simplify the project structure.

ASP.NET Atlas Tutorial Video

http://www.asp.net/learn/videos/default.aspx?tabid=63

http://weblogs.asp.net/scottgu/archive/2006/08/25/Great-New-Atlas-Videos-Published-_2800_All-Free_2900_.aspx

Monday, September 25, 2006

ASP.NET Application DAL

When working with data one option is to embed the data-specific logic directly into the presentation layer (in a web application, the ASP.NET pages make up the presentation layer). This may take the form of writing ADO.NET code in the ASP.NET page's code portion or using the SqlDataSource control from the markup portion. In either case, this approach tightly couples the data access logic with the presentation layer.

The recommended approach, however, is to separate the data access logic from the presentation layer. This separate layer is referred to as the Data Access Layer, DAL for short, and is typically implemented as a separate Class Library project.

DataSets vs. Business Objects

ATTENTION: The following words are picked out with my respect from Mr. Brian Noyes's essay Build a Data Access Layer with Visual Studio 2005 DataSet Designer publish at theserverside.net http://www.theserverside.net/tt/articles/showarticle.tss?id=DataSetDesigner

Almost as common as the debate over which .NET language to choose is the argument about whether to use DataSets or not. As described above, typed data sets are easy to generate through the designer, provide a type safe API for containing business entity data, and already support advanced features such as change tracking, sorting, filtering, and searching. Some of the resistance to DataSets resulted from several performance shortcomings in the .NET 1.1 implementations. These problems included poor performance when working with large DataSets and the fact that DataSets always serialized themselves as XML, which had bandwidth and performance implications when passing DataSets across remoting boundaries. These problems have been fixed in .NET 2.0 and there have been a large number of other improvements. If you dismissed DataSets in .NET 1.1, they deserve another look.

The alternative to using DataSets is to create custom object types that represent your business entities, and custom collection types to contain them. When you go this route, you end up needing to write a lot more code yourself. This has gotten a lot better in Visual Studio 2005 and .NET 2.0 with the additions of code snippets and generic collection classes. But to support the full range of features that a DataSet provides, there is still a fair amount of custom code that you will need to write by hand.

Custom objects have the advantage of giving you explicit and complete control over the way the type is designed, what its internal capabilities are, and what the API is that is exposed from the object. If you prefer a pure object-oriented design approach, then custom business entities will feel a little more comfortable to you. You can accomplish almost anything with a typed data set that you can with a custom business entity, but some things may be a little less clean with a typed data set if the things you are trying to do don’t map well to the relational nature of a typed data set. But if you are primarily getting business data for the purposes of presenting the data, allowing the user to work with the data, and then will persist the data back to the database, you will be able to get things done quicker with typed data sets if you harness the features of the DataSet designer.

When you work with data in an application, the data is usually partitioned into different types of logical business entities, such as Customers, Products, Employees, and so on. To work with that data, you need to encapsulate those logical entities into objects that you can deal with in your code. You could write a custom class for each entity type. Those entity types would expose properties for each of the data values that the entity includes. You would then also want to create a custom collection type for each entity type so that you could have strongly typed collections to contain those entities.

Typed data sets represent an easy alternative to creating and maintaining all those custom types yourself. Essentially what you are doing when you create a typed data set is that you are creating a set of custom type definitions to contain logical business entities and collections of those entities, similar to writing those types by hand. The difference is that you are doing it in a declarative way through the designer that is easy to visualize, edit, and keep synchronized with the database schema that populates those business entities. The code generation of Visual Studio takes care of writing all the underlying properties and methods that give you a strongly typed API for dealing with those business entities in your consuming code. Additionally, because these types are inheriting from the ADO.NET types, you inherit the rich relational data manipulation functionality from those types. These types are also aligned well with the data binding capabilities in Windows Forms and ASP.NET, so if you will be setting up data binding using the objects, then you have less work to do on that front as well.

Finally, and perhaps most importantly, when you create typed data sets in Visual Studio 2005 from a database, you also get a table adapter type created for each table that you add to the data set. A table adapter is a full fledged data access component that lets you retrieve and update data from the database. It encapsulates a connection, a data adapter, and a set of command objects that allow you to execute queries to the database. I’ll get into more detail on table adapters in a little bit.

When you go with typed data sets in Visual Studio 2005, you can actually support most of the same design styles that you could with custom business entity types. The data access code will always be separated into the table adapter types generated by the designer, or into data access components that you write. But you can add custom validation and other logic into your business entity types (the typed data row or data table classes) through partial class extensions. Each of the types created as part of a typed data set definition (data set, data table, data row, and table adapter) are defined in the generated code as partial classes. This feature in .NET 2.0 allows you to supplement the designer generated code with custom code that becomes part of the compiled type, but you do so through a separate code file. This prevents your code from being destroyed if you choose to regenerate the designer generated code.

Another argument that comes up a lot against using DataSets is the assertion that if you are using DataSets in your presentation or business layer, then you are tightly coupling your application to the data tier. This does not have to be the case. First off, you should consider using stored procedures as a layer of decoupling between your actual data tier schema and your application. Your stored procedures can then return and work with result sets that map well to the business entities that you will be manipulating in your application. Additionally, if you need to provide additional decoupling beyond what the stored procedures provide, you can transform data that has been placed into a DataSet into either a different (decoupled) typed data set definition or a custom business entity type in your business or data access layer.

The designer allows you to very quickly create customized query methods in the table adapter that makes it so you will rarely have to write any ADO.NET code yourself if you are working with typed data sets.

Building and using a 3-tiered data architecture with ASP.NET 2.0 & VB.NET Tutorials

All Tutorials:
http://www.asp.net/learn/dataaccess/default.aspx?tabid=63

Tutorial 1: Creating a Data Access Layer
http://msdn.microsoft.com/asp.net/reference/data/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial01_dataaccesslayer_vb.asp

Tutorial 2: Creating a Business Logic Layer
http://msdn.microsoft.com/asp.net/reference/data/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial02_businesslogiclayer_vb.asp

Tutorial 3: Master Pages and Site Navigation
http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial03_masterpagesandsitenav_vb.asp

Tutorial 4: Displaying Data With the ObjectDataSource
http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial04_datawithobjectdatasource_vb.asp

Tutorial 5: Declarative Parameters
http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial05_declarativeparameters_vb.asp

Tutorial 6: Programmatically Setting the ObjectDataSource's Parameter Values
http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnettut/html/aspnet_tutorial06_programmaticallysetparamvalues_vb.asp

Sunday, September 24, 2006

Ruby on Rails VS ASP.NET

@ Rails可以把database中的所有表通过Scaffold的方式迅速地呈现和管理起来。ASP.NET 可以使用GridView和DataSource两个Control同样迅速地实现这个功能。

@ ASP.NET提供了完整的一套用户相关的组件,包括注册、登录、密码、记住、个性化等等,只要把几个Control往上拖拖就行了。而且对于数据管理也已经做完了大部分工作。
Rails提供了很多plugin,其中Act_as_authenticated就实现了login等功能。没有很仔细地去研究这个功能的实现程度,但是感觉还是要写很多代码。

@ Rails提供了tag cloud的功能,通过一个taggable plugin。ASP.NET好像没有提供类似的control。

Rails : Tips

@ Rails is a database-centric development environment, so your development will usually begin with the model.
@ A good starting point is to underline the important nouns in a list of user stories.

.NET : Threading

Why and when to use multithreading?

@ For most developers, the primary motivation for multithreading is the ability to perform long-running tasks in the background, while still providing the user with an interactive interface.
Another common scenario is when building server-side code that can perform multiple long-running tasks at the same time, thus, each task can be run on a separate thread, allowing all the tasks to run in parallel.

@ If we regard computer programs as being either application software or service software:
Application software uses multithreads primarily to deliver a better user experience.
Service software uses multithreads to keep CPU busy servicing and deliver scalability.

@ For interactive applications, multithreading is not a way to improve performance, but rather is a way to improve then end user experience by providing the illusion that the computer is executing more code simultaneously.
In the case of server-side code, multihtreading enables higher scalability by allowing Windows to better utilize the CPU along with other subsystems such as IO.

What the fuck is thread?

@ The term thread is short for thread of execution.
When your program is running, the CPU is actually running a sequence of processsor instructions, one after another. You can think of these instructions, one after another, as forming a thread that is being executed by the CPU.

What is process?

@ Each of the programs your computer keeps in memory runs in a single process. A process is an isolated region of memory that contains a program's code and data. The process is started when the program starts and exists for as long as the program is running.

@ When a process is started, Windows sets up an isolated memory area for the program and loads the program's code into that area of memory. It then starts up the main thread for the process. The mean thread might execute instructions taht create more threads within the same process.

.NET : Genric Collection

^ 对于Generic Dictionary的程序写法:

Dim OneGenericDictionary As New Dictionary(Of Integer, String)
OneGenericDictionary.Add(1, "One")
OneGenericDictionary.Add(2, "Two")
OneGenericDictionary.Add(3, "Three")

For Each OnePare As KeyValuePair(Of Integer, String) In OneGenericDictionary
Console.WriteLine("The pare is {0} : {1}", OnePare.Key.ToString, OnePare.Value.ToString)
Next

Dim OneEnumerator As Dictionary(Of Integer, String).Enumerator = OneGenericDictionary.GetEnumerator()
While OneEnumerator.MoveNext
Console.WriteLine(OneEnumerator.Current.Key & " : " & OneEnumerator.Current.Value)
End While

Saturday, September 23, 2006

VB.NET

^ 之所以喜欢VB这种语言(从前是嗤之以鼻的),是因为没有那么多的数理符号,比如{} && ;。讨厌这些符号,虽然写了那么多年Java也习惯了,但是自从知道了Ruby,就不再喜欢C#和Java风格的语言了。偶然的机会,因为项目要求,不得不开始学习VB语言,发现它和Ruby在语法风格上很有相似之处,用自然的英语词汇和语法来代替那些符号。我喜欢自然语言,讨厌数理符号。况且,VB.NET在功能上一点不比C#.NET差。
^ 当然,可能最合适自己的语言应该是自己创造的,哈哈,比如把Ruby和VB语言再稍加改变糅合,产生自己的语言。这不是不可能的。我甚至可以只做一个语法解析器就行了——用我自己的语言写程序,然后通过一个解析器把代码再转换成Ruby解析器或者VB.NET编译器可以读的代码就行了。

^ 对于实现某种语段总是会有好几种写法,但是我要给自己规定一套Convention,必须遵循:

写For循环:
C# : for(int x = 0; x < Someone.Count; X++
VB : For x = 0 someone.Count - 1 Step + 1

创建一个object的时候:(尽量使用Generic)
Dim OneObject As New SomeClass(Of String)

.NET Collection

ArrayList

@ ArrayList, like most collections, supports several ways to iterate over its contents.
Dim OneArrayList As ArrayList = New ArrayList()
OneArrayList.Add("First")
OneArrayList.Add("Second")
OneArrayList.Add("Three")
OneArrayList.Add("Four")
'Way #1

For Each OneArrayListItem As Object In OneArrayList
Console.WriteLine(OneArrayListItem.ToString)
Next
'Way #2

Dim OneEnumerator As IEnumerator = OneArrayList.GetEnumerator()
While OneEnumerator.MoveNext()
Console.WriteLine(OneEnumerator.Current)
End While
'Way #3

For Indexer As Integer = 0 To OneArrayList.Count - 1
Console.WriteLine(OneArrayList(Indexer))
Next

Dictionary

^ 有两种Standard Dictionary:HashtableSortedList,三种Specialized Dictionary:ListDictionaryHybridDictionaryOrderedDictionary

@ In general, the Hashtable class is a very efficient collection. The only problem with Hashtable is for small collections (fewer than 10 elements) it impede performance. This is where ListDictionary comes in.
@ When you know our collection is small, use a ListDictionary; when your collection is large, use a Hashtable. But what if you just do not know how large your collection is? Use HybridDictionary!
^ 干吗非得整得这么复杂?TNND,让事情简洁明了不行?我就不信性能会差十万八千里。硬件的强大处理能力不知有多少被浪费掉了!何不只用一种Dictionary来满足所有类似需求?HybridDictionary解决了所谓的HashtableListDictionary的efficiency问题。有什么意义?对于efficiency这一点我不太考虑,只当是存在Hashtable一种Dictionary就行了。

@ To accomodate you when you need a fast Dictionary but also need to keep the items in an ordered fashion, the .NET Framework supports the OrderedDictionary.
^ OrderedDictionary除了具备Hashtable的功能之外,还具备了control the order of the elements in the collection的功能。OrderedDirctionry is as if a mix of an ArrayList and a Hashtable. 所以,为了简单起见,作为一种通用解决方案,对于需要Dictionary功能的地方,我就只使用OrderedDictionary,只有有明确需求的时候在研究使用其他的Dictionary.
^ 可是,MD!我发现HashtableContainsKey()ContainsValue()两个method,可是OrderDictionary没有。虽然OrderDictionry.Contains(Key)可以实现Hashtable.ContainsKey()的功能,却实现不了 Hashtable.ContainsValue()

^ 也许应该考虑尽量使用Generic Collection吧。还没有研究透。

Friday, September 22, 2006

.NET : Serialization

What is serialization?

@ Serialization is the process of converting an object into a stream of bytes in order to persist it to memory, a database, or a file.

Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.
The object is serialized to a stream, which carries not just the data, but information about the object's type, such as its version, culture, and assembly name.

@ Hah hah, teleportation in science fiction is a good example of serialization, although which is not currently supported by .NET Framework. ;-)

Why use serialization?

@ The two most important reasons are:
to persist the state of an object to a storage medium so an exact copy can be re-created at a later stage,
to send the object by value from one application domain to another.

Scenarioes of using serialization

@ Through serialization, a developer can perform actions like
1. send the object to a remote application by means of a Web Service,
2. pass an object through a firewall as an XML string,
3. maintain security or user-specific information across applications.
4. save session state in ASP.NET
5. copy objects to the Clipboard in Windows Forms
6. pass objects by value from one application domain to another, used by Remoting.

How to serialize and unserialize?

@ How to serialize an object?
At a high level, the steps are:
1. Create a Stream object, to hold the serialized output.
2. Create a BinaryFormatter object, to do serialize work.
3. Call the BinaryFormatter.Serialize method to serialize the object and output the result to the stream.
Dim DataToBeSerialized As String = "This is the content to store in a file."
Dim FileStreamForHolding As FileStream = New FileStream("SeriaziedString.Data", FileMode.Create)
Dim OneBinaryFormatter As BinaryFormatter = New BinaryFormatter
OneBinaryFormatter.Serialize(FileStreamForHolding , DataToBeSerialized)
FileStreamForHolding .Close

@ How to deserialize an object?
At a high level, the steps are:
1. Create a Stream object, to read the serializd output.
2. Create a new object to store the deserialized data.
3. Create a BinaryFormatter object.
4. Call the BinaryFormatter.Deserialize method to deserialized the object, and cast it to the correct type.
Dim FileStreamForReading As FileStream = New FileStream("SerializedString.Data", FileMode.Open)
Dim ObjectToStore As String = ""
Dim BinaryFormatterWorking As BinaryFormatter = New BinaryFormatter
ObjectToStore = CType(BinaryFormatterWorking.Deserialized(FileStreamForReading), String)
FileStreamForReading.Close

@ It is a good practice to make ALL calsses serializable enven if you do not immediately require serialization.

@ To create a class that can be serialized, add the Serializable attribute.

Thursday, September 21, 2006

ASP.NET MasterPage

@ You can put anything you want to share in the .master file.

@ Starting the .master file with <%@ Master Language="VB" %>, you code the rest of the master page just as you would any other .aspx page.

@ You can use server controls, raw HTML, text, images, events or anything else you normally would use for any .aspx page. This means that your master page can have a Page_Load event as well or any other event that you deem appropriate.

Wednesday, September 20, 2006

Encoding

@ While ASCII was Sufficient for most English-language communications, ASCII did not include characters used in non-English alphabets.

@ More and more, ASCII and ISO 8859 encoding types are being replaced by Unicode.

@ Unicode is a massive code page supports most languages and scripts.

@ The .NET Framework uses Unicode UTF-16 (Unicode Transformaiton Format, 16-bit encoding form) to represent characters.

@ If you are not sure which encoding type to use when creating a file, simply accept the default by not specifying an encoding type. The .NET Framework will choose UTF-16.

.NET : Regular Expression

@ For decades, UNIX and Perl developers have used a complex but efficient technique for processing text: regular expressions.

@ A regular expression is a set of characters.

@ The "^" represents the start of the string, The "$" represents the end of the string. When validating input, MUST always begin regular expressions with a "^" character and end them with "$".

Enumeration是个好东西

@ Enumerations are related symbols that have fixed values.
@ The purpose of enumerations is to simplify coding and improve code readability by enabing you to use meaningful symbols instead of simple numeric values.
@ How to creat Enumerations? For instance:
Enum Titles As String
Mr
Ms
Mrs
Dr
Jr
End Enum

关于Double的四舍五入

I. 在VB.NET 2005中,根本就没有四舍五入这个概念。round()不应该被翻译成四舍五入。

II.如何实现四舍五入?
一个同事告诉我一个方法:比如要将一个Double保留到小数点后两位并且四舍五入,那么就把这个Double加上0.005,然后截断到小数点后两位。他说这个方法曾经在很多项目里面用过,没问题。我没仔细测试过,但是想想看,道理上是讲的过去的。

.NET System.IO

d The file system classes are separated into two types of classes: informational and utility.
d The informational classes include: FileInfo, DirectoryInfo, DriveInfo. These classes expose all the system information about file system objects - files, directories, and drives.
d The utility classes include: File, Directory, and Path. These classes provide static/shared methods to perform certain operations on file system objects - files, directories, and paths.

d The Path class deals only with the string of a path. It makes no changes to the file sytem. For instance:
Dim OnePath As String = "C:\boot.int"
Path.ChangeExtention(OnePath, "bak")
^ 以上代码改变了一个Path,但是并没有改变文件名本身,就是说,OnePath改变成"C:\boot.bak",但是boot.ini本身的文件名并没有被改变。

How to read from a file:

1. One way of reading a file is using StreamReader classes, which makes reading easier than calling the Read or ReadByte methods of the Stream class.
Dim OneFile As FileStream = File.Open("C:\boot.ini", FileMode.Open, FileAccess.Read)
Dim OneReader As StreamReader = New StreamReader(OneFile)
Console.Write(OneReader.ReadToEnd())
OneReader.Close()
OneFile.Close()

@ The StreamReader class is intented to read a stream as a string, not as a series of bytes. Thus, the StreamReader's methods for returning data all return either strings or arrays of strings.

2.The File class has a simpler way to open a file for reading. It supports creating a StreamReader directly with the OpenText method:
Dim OneReader As StreamReader = File.OpenText("C:\boot.int")
Console.Write(OneReader.ReadToEnd())
OneReader.Close()

3. If all you need to do is read out the entire file, the File class supports reading the file in a single method call, hiding all the details of the stream and reader implementation by calling its ReadAllText method:
Console.Write(File.ReadAllText("C:\boot.ini"))

How to create a file for writing:

1. We can use the StreamWriter to write text directly into a new file
Dim OneFile As FileStream = File.Create("C:\SomeFile.txt")
Dim OneWriter As StreamWriter = New StreamWriter(OneFile)
OneWriter.WriteLine("Hello")
OneWriter.Close()
OneFile.Close()

2. File class supports creating a StreamWriter object directly with the CreateText method:
Dim OneWriter As StreamWriter = File.CreateText("C:\SomeFile.txt")
OneWriter.WriteLine("Hello")
OneWriter.Close()

3. File class aslo supports the WriteAllText method that write a string to a new file:
File.WriteAllText("C:\SomeFile.txt", "Hello")

How to open an existing file for writing:

1. File class
Dim OneFile As FileStream = File.Open("C:\SomeFile.txt", FileMode.Open, FileAccess.Write)

2. The File class has the OpenWrite method, which is a shortcut for opening existing files for writing:
Dim OneFile = File.OpenWrite("C:\SomeFile.txt")

How to exither open an existing file or create a new file for writing:

1. Using the Open method of the File class to specify that you want open or create. The FileMode.OpenOrCreate enumeration value allows you to avoid writing procedural code to deal with the issue of whether you are dealing with a new or existing file:
Dim OneFile As FileStream = FileOpen("C:\SomeFile.txt", FileMode.OpenOrCreate, FileAccess.Write)

Tuesday, September 19, 2006

编程高手是怎样变成的呀?

虽然写了五年程序了,Java,C#,Ruby on Rails,VB.NET,用过好几种语言,也参加过不少大项目的开发,可总是对自己的编程能力不够有信心。虽然,有的程序也写得很好,却好像从没真正全面地掌握一种语言,没能对所有的特性都了然于心。从开始编程,所有的东西都是自学的,也从来没请过高手指导自己,总感觉不是那么“正”。不像在武术领域有大师言传身教,不像在音乐方面有专业演奏家指导。为啥我靠着吃饭的东东却没有请人指导过呢?吼吼!

现在在准备MCPD的认证考试,第一门又是关于语言的,我选择VB.NET作为考试语言,因为我发现VB.NET的语法和Ruby语言很像,都接近英语,少了很多像C#那样的乱七八糟的符号,更符合我这个“人文大脑”的程序员。嘿嘿。毕竟,我在运用人类语言的方面是有灵性的,可一旦到了数理方面,我就成了某人说的呆瓜了。上次考SCJP,考的Java语言,其实这两门考试的内容差不多,涵盖的都是Object-Oriented Programming的东西,只不过用了两套不同的语言语法而已,思想上没有啥大区别。上次以83%通过的,这次也不会是问题。

复习考试,不求一遍能够完全明白,多看几遍,多做些题,量变成质变。有些语言特性可能自己不理解,但是目前做到知道怎么答题就行了。有用的东西都记录下来,发布在这个Blog上,方便自己以后回来查阅。不懂的地方,就多请教人家,即便是有嘲笑,有脸色,忍了,反正不是我没素养。哈。有机会的话,请一位公司里的编程高手指导一番,咱也提升提升水准。希望在我离开这个行业之前成为一个编程高手,否则总有些逃兵的感觉。

王者之程(程序的程,嘿嘿)

.NET Class

@ Fields are variables delcared in the class so that they are available to all code within the class, and are available to each individual object.

@ Fields are also called instance variables or member variables.

@ Fields are used by objects to store data.

@ Typically, fields are Private in scope, available only to the code in the class itself.
Never declare a field as Public, beacuse such a choice directly breaks the concept of encapsulation, since code outside the object can directly change data values without following any rules set in the object.

@ If you want to make the value of a field available to code outside of the object, you should use a property:
Public Class OneClass
Private FieldName As String
Private FieldAge As Integer
Public ReadOnly Property Name() As String
Get
Return FieldName
End Get
End Property
End Class

^ 要实现Java中的Field + Getter & Setter Method的关系,在VB中恐怕就要用Field + Property Method的方法了。

@ You shouldn't confuse fields with properties. In Visual Basic, a Property is a type of method that is geared to retrieving and setting values, while a field is a variable within the class that may hold the value exposed by a Property.

.NET Delegate & Event

@ A delegate is a class that can hold a reference to a method.
Unlike other classes, a delegate class has a signature, it can hold references only to methods that match its signature.

@ A delegate declaration is sufficient to define a delegate class. the declaration supplies the signature of the delegate, and the CLR provides the implementation.

@ EventHandler is predefined delegate class that specifically represents an event handler method for an event that does not return a value, whose 1st parameter is of type Object and refers to the instance that raises the event, and whose 2nd parameter is derived from type EventArgs and holds the event data.

@ An event is a message sent by an object to signal the occurence of an action.

@ In event communication, the event sender calss does not know which object or method will receive/handle the events it raises. What is needed is an intermediary(or pointer-like mechanism) between the sender and receiver. To associate an event with an event handler, add an instance of the delegate to the event.

@ How to wire up a Event Handler for an Event?
AddHandler OneObject.OneEvent, AddressOf OneEventHandler

.NET : Generics

@ Why use Generics?
Develpers used the Object class for parameters and members, and would cast other classes to and from the Object class.
1. Using generics allows the comipler to catch type errors before your program runs, namely, its' type-safe.
2. Using generics doesn't require casting or boxing, which improves run-time performance.

@ .NET built-in generic types inludes:
1. Nullable
2. EventHandler
3. System.Collection.Generic, including Dictionary, Queue, SortedDictionary, and SortedList.

^ Generic应该就是被看成是一个语言特性。它诞生了,成为了一种语言的feature,目的是用来解决从前的写法的问题。所以,就应该完全抛弃掉从前的写法,使用Generic这个语言特性。无论是Collection还是自己写的东西。对我个人来说,以后所有的程序都将全盘使用Generic这种思想和特性,消除type-safe问题,也让程序更简洁漂亮一些。

Monday, September 18, 2006

.NET : Value Types

@ Built-In types are base types provided with the .NET Framework, with which other types are built.

@ Value types directly contain their data, offering excellent performance. However, value types are limited to types that store very small pieces of data. In the .NET Framework, all value types are 16 bytes or shorter.

@ All build-in numeric types are value types.

@ For integral variables, use Int32 and UInt32, because the runtime optimizes the performance of 32-bit integer types (System.Int32 and System.UInt32).
@ For floating-point operations, System.Double is the most efficient type, because those operations are optimized by hardware.

@ User-Defined types are also called structures. Structures are a composite of other types that make it easier to work with related ata.

@ Instances of User-Defined types are stored on the stack and they contain their data directly.

@ In most ways, structures behave nearly identical to classes. While the functionality is similar, structures are usually more efficient than classes.

@ Enumerations are related symbols that have fixed values. Use enumerations to provide a limited set of of choices for a value. For example:

Enum Titles As Integer
Mr
Ms
Mrs
Dr
End Enum

@ The purpose of enumerations is to simplify coding and improve code readability by enabling you to use meaningful symbols instead of simple numeric values.

Sunday, September 17, 2006

.NET XmlReader & XmlWriter

@ XmlReader provides fast, forwar-only, read-only access to XML documents.

@ The primary way for you to create an instance of an XmlReader is by using the Static/Shared Create method. Rather than creating concrete implementattions of the XmlReader calss, you create an instance of the XmlReaderSettings class and pass it to the Create method. You specify the features you want for your XmlReader object with the XmlReaderSettings class.

@ If you’re going to run through the document only once, you don’t want to hold it in memory; youwant the access to be as fast as possible. XmlReader is the right decision in this case.

^ 我倾向于在一个Application中,对于数据操作,XML操作,都分别只使用在一种模式:数据操作使用DataSet;XML操作使用XmlDocument。虽然Reader和Writer的模式有优势,但是并不提供一个完整的解决模型和统一的操作方式。只使用一种“全能”的模式,可以让编程更易于实现和维护。至于内存和性能问题,我想应该通过硬件来解决。

Saturday, September 16, 2006

New thinking of roles in Internet Application Ecosystem

When using the server controls provided by ASP.NET, you are not specifying the HTML to be output from your server-side code. Rather, you are specifying the functionality you want to see in the browser, and letting the ASP.NET decide for you on the output to be sent to the browser.

在一个Application的scenerio中,只有两种角色,Consummer和Provider。Consummer通过Browser来使用某个function,完成他想做的事情;Provider通过Server提供某个function。在整个故事里面,Provider提供的function,关注的、思考的也应该是function,至于这个function是通过什么element实现的,并不应该在乎。所以,我认为ASP.NET的Web Server Control的思想非常的好,我不关心最终生成的HTML代码是什么样子的,只要可以能够在Browser中得到他想要的function就行了。
1. 当我做一个Application的时候,我关心的是要实现的功能,关心的是我能够在浏览器中完成一件事情,而不关心这个功能到底使用什么HTML elements实现的。
2. 用户用什么浏览器来访问我的Application谁也不知道,而且这不是我该关心的,我只关心要实现的功能,至于怎么能够在不同的Browser中实现相同的function,我就不管了,让ASP.NET去料理吧。
所以,我想在Internet Application的制造过程中,Provider考虑的应该是function,而不是element。因为Provider和Consummer都只关心function而不关心element。

Friday, September 15, 2006

Adding Client-Side Message Boxes in your ASP.NET Web Pages

Introduction One of the useful features in a Windows desktop application that many programmers and end-users take for granted is message boxes. Two of the most common types of message boxes are alerts and confirms. A confirm message box prompts the user if they want to continue, and provides two choices: "OK" and "Cancel". Clicking "OK" confirms the action, while "Cancel" cancels it.
An alert message box, on the other hand, simply presents a message to the user. There is no choice, here, just an "OK" button that the user must click to dispose of the message box.
Using client-side message boxes on a Web site offers a number of benefits. Message boxes, if used intelligently, can help ensure that the reader sees important information - by placing important messages or warnings in message boxes you can rest assured that your visitors are more apt to see and read the message than if you placed the same message in some label on the page. For example an alert box can provide a practical way to inform the user that some of the data they entered was invalid. A confirm box could provide a safety check to ensure that the user was certain that they wanted to delete something. (For an article on discussing how to add client-side confirmation to Delete buttons in a DataGrid be sure to read An Extensive Examination of the DataGrid Web Control: Part 8.) Message boxes can be a clean way to present information to your users, as opposed to weaving in labels throughout the page. Perhaps most importantly, end users are familiar with message boxes, having used them repeatedly before in desktop applications.
In addition to the pros of message boxes, there are also two major cons: first, message boxes require an extra click from the end user as opposed to just browsing a label message without clicking anything. Second, message boxes reside on the client and are displayed using client-side script, but an end user can always disable client side scripting. Users who have disabled client-side scripting in their browser will not see the message boxes. This latter disadvantage, however, should not be too great a concern since virtually all Web surfers have client-side scripting enabled.
The Challenges in Using Message Boxes with ASP.NET The problem with message boxes is that they are created on the client, and therefore cannot be directly created from server-side code. Since ASP.NET Web pages' code-behind classes are running on the Web server, it is impossible for this server-side code to be able to directly invoke some client-side functionality. Rather, the server-side code needs to emit the proper client-side JavaScript code along with the rendered HTML so that when this is sent back to the client, the client can display the message box. (If you are not familiar with the difference between client-side and server-side behavior, consider reading ASP Basics: What's Happening Back There? before continuing...)
In this article we'll see how to create a utility class that can be used in our ASP.NET Web pages' code-behind classes. This utility class will contain methods for displaying client-side message boxes. These methods will emit the proper HTML and client-side JavaScript necessary to display the message box.
Displaying a Confirm Message Box Let's begin by examining how to add a confirm message box that is displayed when the user clicks a button. Before ASP.NET, one way to do this would be make a regular HTML <input> button and add a JavaScript onclick event to the button which calls the JavaScript method confirm(), thereby displaying a client-side confirm message box upon the button being clicked.
With ASP.NET, however, we don't directly create the HTML markup for a button. That is, we don't type in the HTML for an <input> HTML element. Rather, we use a Button Web control, which is rendered into the appropriate HTML. With the Web control model rather than manually interweaving JavaScript into the HTML portion of an ASP.NET Web page, we instead programmatically set a property of the Button Web control class.
To accomplish this, start by adding a Button Web control to an ASP.NET Web page and give it an ID of BtnDelete. If we stopped here, the Button Web control would generate the following HTML:
<input type="submit" name="BtnDelete" value="Delete" id="BtnDelete" />
This HTML, however, is missing the client-side JavaScript onclick event handler. What we really want to generated is something that includes the JavaScript, like:
<input type="submit" name="BtnDelete" value="Delete" id="BtnDelete" onclick="return confirm('Are you sure you want to delete?');" />
In other words, we want to add another attribute to the rendered <input> element and assign it a value. (Specifically, we want to add the onclick attribute with the value return confirm('Are you sure you want to delete?');.) Fortunately, all ASP.NET Web controls provide an Attributes property that provides a collection of attributes for the rendered HTML element along with the attributes' values. The Attributes property has an Add(key, value) method that can be used to add a new attribute and value to an existing Web control. Therefore, to add the appropriate JavaScript to the BtnDelete Button Web control, we could add the following code:
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
If (Not Page.IsPostBack) Then
Me.BtnDelete.Attributes.Add("onclick", _
"return confirm('Are you sure you want to delete?');")
End If
End Sub

Because we only need to add this attribute once (and not on every page load), we place the code in the Not Page.IsPostBack block.
If you visit the page through a Web browser and click the button, you should see something like the screenshot below.
If you plan on needing to add a confirm message box for numerous ASP.NET Web pages, it might make sense to create a Utilities class with a static method that accepts a Button Web control and a string message and sets the Button's Attributes property accordingly.
Public Class Utilities
Public Shared Sub CreateConfirmBox(ByRef btn As WebControls.Button, _
ByVal strMessage As String)
btn.Attributes.Add("onclick", "return confirm('" & strMessage &amp;amp;amp;amp; "');")
End Sub
End Class

We could then call this helper method from within the Page_Load event of the Web Form, passing both a reference to the button as well as the message:
Utilities.CreateConfirmBox(Me.BtnDeleteUtil, _ "Are you sure you want to delete (this uses the Utilities Class)?")
By placing the functionality in the Utilities class, we are able to easily reuse the code in other ASP.NET Web pages. This is similar to the technique of using include files in classic ASP. For more information on using classes as a repository for reusable code fragments, check out: Accessing Common Code, Constants, and Functions in an ASP.NET Project.
Now that we have examined how to display a confirm message box, let's turn our attention to displaying alert message boxes. We'll tackle this in Part 2 of this article.
Displaying Alert Message Boxes Besides having prompting the user to confirm that they want to perform an action, we might also want to notify the user of some server-side behavior. For example, if there was some server-side error and the data entered wasn't correctly saved, we might want to use an alert message box to inform the user. Or perhaps when attempting to add the data provided into the database, we deduced that the provided data was duplicate data. The question becomes, coming back from the server to the client, how would we alert the user with a message box?
Traditionally we would do this with JavaScript in the html of the page by creating an onload event that generated a message box. However like the previous case, ASP.NET provides us additional methods to handle all this from the code-behind without having to hard code HTML ourselves.
· What we want to do is register a client script block with the ASP.NET Web page. More specifically, we want this to run when the page starts up on the client. Again it's our lucky day, as the ASP.NET Page class provides a RegisterStartupScript() method for that very purpose.
Typically what will happen is the user will submit his data, we'll do some processing, and then realize that we need to alert the user of some unexpected behavior. Therefore, we'll probably need to add this RegisterStartupScript() method call in the Button Web control's server-side Click event handler. The code for this might look something like:
Private Sub BtnSave_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles BtnSave.Click
'Generates the message:
Dim strMessage As String
If (Me.CheckBox1.Checked()) Then
strMessage = "The data was saved."
Else
strMessage = "The data was NOT saved."
End If
'finishes server processing, returns to client.
Dim strScript As String = "<script language=JavaScript>"
strScript += "alert(""" & strMessage &amp;amp;amp;amp;amp; """);"
strScript += "</script>"
If (Not Page.IsStartupScriptRegistered("clientScript")) Then
Page.RegisterStartupScript("clientScript", strScript)
End If
End Sub

This code first generates the message by checking field values (in this case if a CheckBox1 CheckBox Web control was checked or not) and building the message appropriately. However note that the message could be generated from any server-side process, such as the return value of a business object, or based upon the results of a stored procedure or database query.
Once we have the message, we can build the client-side JavaScript script block. The RegisterStartupScript() method takes two string inputs: a key, identifying the script block being registered, and the actual script itself. Notice that the second input parameter, the client-side script, includes both the <script> tag, and the JavaScript code to run (alert('...');). Before calling RegisterStartupScript() it is prudent to first check to make sure that the script block hasn't already been registered. (In our simple example above, it clearly couldn't have already been registered, but if you are registering a script block based on, say, values in a DataGrid, there might be multiple records that would cause the script block to be rendered. A check to IsStartupScriptRegistered() quickly determines if a startup script has already been registered or not.)
In the screen below, the user has selected the checkbox and then clicked the save button. The server then generates the necessary JavaScript block, registers it, and displays it upon returning the page to the client.
Like the previous sample, we can also abstract this functionality to a Utilities class. For this method, we need to pass in a Page class instance (since the RegisterStartupScript() and IsStartupScriptRegistered() methods are methods of the Page class), along with the string to display in the alert message box and the key name by which to register the script.
Public Class Utilities
Public Shared Sub CreateMessageAlert(ByRef aspxPage As System.Web.UI.Page, _
ByVal strMessage As String, ByVal strKey As String)
Dim strScript As String = "<script language=JavaScript>alert('" _
& strMessage & "')</script>"
If (Not aspxPage.IsStartupScriptRegistered(strKey)) Then
aspxPage.RegisterStartupScript(strKey, strScript)
End If
End Sub
End Class

The original page could then call the CreateMessageAlert() method like so:
Private Sub BtnSaveUtil_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles BtnSaveUtil.Click

'Generates the message:
Dim strMessage As String
If (Me.CheckBox1.Checked()) Then
strMessage = "The data was saved."
Else
strMessage = "The data was NOT saved."
End If
'Call separate class, passing page reference, to register Client Script:
Utilities.CreateMessageAlert(Me, strMessage, "strKey1")
End Sub
Notice that when calling the CreateMessageAlert() method we pass in Me for the Page class instance. This is because the code-behind class is inherited from the Page class, so we can just pass in the code-behind class reference. The second parameter is the message to display in the alert message box and the third input parameter provides the key name for the script block.
Conclusion In this article we looked at how to add client-side message boxes to your ASP.NET application. Adding confirm message boxes is as simple as adding an onclick attribute to the Button Web control's Attributes collection. Displaying an alert message box on page load involves calling the Page.RegisterStartupScript() method, passing in the complete JavaScript block that should be performed on page load.
Happy Programming!
Attachments Download a Demonstration of these Examples

不去比较哪种技术好不好

不去比较那种技术比另一种好不好。ASP.NET,Ruby on Rails都是非常好的技术,各有各的优势。之所以要掌握ASP.NET是工作的需要;之所以要学会Ruby on Rails是为了改善经济状况。一种技术本身并没有多少意义,只有当这种技术可以被运用了改变一些现状,实现一些梦想的时候,它才存在了价值。
为什么要把自己郁于选择某种技术,选择某个阵营这个问题中呢?无所谓。
为了我想要的生活,为了实现我的梦想,把时间精力比例分配好,尽量找出共通的东西,形成自己的一套方法论,做事!

Ruby Language Features


Iteration

Two Ruby features that are a bit unlike what you may have seen before, and which take some getting used to, are “blocks” and iterators. Instead of looping over an index (like with C, C++, or pre-1.5 Java), or looping over a list (like Perl’s for (@a) {...}, or Python’s for i in aList: ...), with
Ruby you’ll very often instead see

some_list.each do this_item
# We're inside the block.
# deal with this_item.
end

For more info on each (and it’s friends collect, find, inject, sort, etc.), see ri Enumerable (and then ri Enumerable#func_name).


Everything has a value

There’s no difference between an expression and a statement. Everything has a value, even if that value is nil. This is possible:

x = 10
y = 11
z = if x < y
true
else
false
end
z # => true

Symbols are not lightweight Strings

Many Ruby newbies struggle with understanding what Symbols are, and what they can be used for. Symbols can best be described as identities. A symbol is all about who it is, not what it is. Fire up
irb and see the difference:

irb(main):001:0> :george.object_id == :george.object_id
=> true
irb(main):002:0> "george".object_id == "george".object_id
=> false
irb(main):003:0>

The object_id methods returns the identity of an Object. If two objects have the same object_id, they are the same (point to thesame Object in memory).

As you can see, once you have used a Symbol once, any Symbol with the same characters references the same Object in memory. For any given two Symbols that represent the same characters, the object_ids match.

Now take a look at the String (“george”). The object_ids don’t match. That means they’re referencing two different objects in memory. Whenever you use a new String, Ruby allocates memory for it.

If you’re in doubt whether to use a Symbol or a String, consider what’s more important: the identity of an object (i.e. a Hash key), or the contents (in the example above, “george”).


Everything is an Object

“Everything is an object” isn’t just hyperbole. Even classes and integers are objects, and you can do the same things with them as with any other object:

# This is the same as
# class MyClass
# attr_accessor :instance_var
# end
MyClass = Class.new do
attr_accessor :instance_var
end

Variable Constants

Constants are not really constant. If you modify an already initialized constant, it will trigger a warning, but not halt your program. That isn’t to say you should redefine constants, though.

Naming conventions

Ruby enforces some naming conventions. If an identifier starts with a capital letter, it is a constant. If it starts with a dollar sign ($), it is a global variable. If it starts with @, it is an instance variable. If it
starts with @@, it is a class variable.

Method names, however, are allowed to start with capital letters. This can
lead to confusion, as the example below shows:

Constant = 10
def Constant
11
end

Now Constant is 10, but Constant() is 11.


Fake keyword parameters


Ruby doesn’t have keyword parameters, like Python has. However, it can be
faked by using symbols and hashes. Ruby on Rails, among others, uses this
heavily. Example:

def some_keyword_params( params )
params
end
some_keyword_params( :param_one => 10, :param_two => 42 )
# => {:param_one=>10, :param_two=>42}

The universal truth


In Ruby, everything except nil and false is
considered true. In C, Python and many other languages, 0 and possibly other
values, such as empty lists, are consided false. Take a look at the following
Python code (the example applies to other languages, too):

# in Python
if 0:
print "0 is true"
else:
print "0 is false"

This will print “0 is false”. The equivalent Ruby:

# in Ruby
if 0
puts "0 is true"
else
puts "0 is false"
end

Prints “0 is true”.


Access modifiers apply until the end of scope


In the following Ruby code,

class MyClass
private
def a_method; true; end
def another_method; false; end
end

You might expect another_method to be public. Not so. The
‘private’ access modifier continues until the end of the scope, or until another
access modifier pops up, whichever comes first. By default, methods are
public:

class MyClass
# Now a_method is public
def a_method; true; end

private

# another_method is private
def another_method; false; end
end
public,
private and protected are really methods, so they can
take parameters. If you pass a Symbol to one of them, that method’s visibility
is altered.

Method access


In Java, public means a method is accessible by anyone.
protected means the class’s instances and their ancestors can
access it, but not anyone else, and private means nobody besides
the classes instances can access the method.


Ruby differs slightly. public is, naturally, public.
private means the method(s) are accessible only when they can be
called without an explicit receiver. Only self is allowed to be
the receiver of a private method call.

protected is the one to
be on the lookout for. A protected method can be called from a class or its
ancestors’ instances, but also with another instance as its receiver. Example,
adapted from the
Ruby
FAQ
:
$ irb
irb(main):001:0> class Test
irb(main):002:1> def func
irb(main):003:2> 99
irb(main):004:2> end
irb(main):005:1>
irb(main):006:1* def ==(other)
irb(main):007:2> func == other.func
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):010:0>
irb(main):011:0* t1 = Test.new
=> #<Test:0xb7db7bbc>
irb(main):012:0> t2 = Test.new
=> #<Test:0xb7daf688>
irb(main):013:0> t1 == t2
=> true
irb(main):014:0> # Now make 'func' private
irb(main):015:0* class Test
irb(main):016:1> private :func
irb(main):017:1> end
=> Test
irb(main):018:0>
irb(main):019:0* t1 == t2
NoMethodError: private method 'func' called for
#<Test:0xb7db7bbc>
from (irb):7:in '=='
from (irb):19
from :0
irb(main):020:0>

Classes are open

Ruby classes are open. You can open them up, add to
them, and change them at any time. Even core classes, like Fixnum
or even Object, the parent of all objects. Ruby on Rails defines a
bunch of methods for dealing with time on Fixnum. Watch:
class Fixnum
def hours
self * 3600 # number of seconds in an hour
end
alias hour hours
end

# 14 hours from 00:00 January 1st
# (aka when you finally wake up ;)
Time.mktime(2006, 01, 01) + 14.hours # => Sun Jan 01 14:00:00

Funny method names

In Ruby, methods are allowed to end with question
marks or exlamation marks. By convention, methods that answer questions (i.e.
Array#empty? returns true if the receiver is empty)
end in question marks. Potentially “dangerous” methods (ie methods that modify
self or the arguments, exit! etc.) by convention
end with exclamation marks.

All methods that change their arguments don’t end with exclamation marks,
though. Array#replace replaces the contents of an array with the
contents of another array. It doesn’t make much sense to have a method like that
that doesn’t modify self.


Singleton methods


Singleton methods are per-object methods. They are only available on the
Object you defined it on.

class Car
def inspect
"Cheap car"
end
end

porsche = Car.new
porsche.inspect # => Cheap car
def porsche.inspect
"Expensive car"
end

porsche.inspect # => Expensive car

# Other objects are not affected
other_car = Car.new
other_car.inspect # => Cheap car

Missing methods


Ruby doesn’t give up if it can’t find a method that responds to a particular
message. It calls the method_missing method with the name of the
method it couldn’t find and the arguments. By default, method_missing raises a
NameError exception, but you can redefine it to better fit your application, and
many libraries do. Here is an example:

# id is the name of the method called, the * syntax collects
# all the arguments in an array named 'arguments'
def method_missing( id, *arguments )
puts "Method #{id} was called, but not found. It has " +
"these arguments: #{arguments.join(", ")}"
end

__ :a, :b, 10
# => Method __ was called, but not found. It has these
# arguments: a, b, 10

The code above just prints the details of the call, but you are free to
handle the message in any way that is appropriate.


Message passing, not function calls


A method call is really a message to another object:

# This
1 + 2
# Is the same as this ...
1.+(2)
# Which is the same as this:
1.send "+", 2

Blocks are Objects, they just don’t know it yet


Blocks (closures, really) are heavily used by the standard library. To call a
block, you can either use yield, or make it a Proc by
appending a special argument to the argument list, like so:

def block( &the_block )
# Inside here, the_block is the block passed to the method
the_block # return the block
end
adder = block { a, b a + b }
# adder is now a Proc object
adder.class # => Proc

You can create blocks outside of method calls, too, by calling Proc.new with
a block or calling the lambda method.


Similarly, methods are also Objects in the making:

method(:puts).call "puts is an object!"
# => puts is an object!

Operators are syntactic sugar


Most operators in Ruby are just syntactic sugar (with some precedence rules)
for method calls. You can, for example, override Fixnums + method:

class Fixnum
# You can, but please don't do this
def +( other )
self - other
end
end

You don’t need C++’s operator+, etc.

You can even have
array-style access if you define the [] and []=
methods. To define the unary + and – (think +1 and -2), you must define the
+@ and -@ methods, respectively.

The operators below are not syntactic sugar, though. They
are not methods, and cannot be redefined:

=, .., ..., !, not, &&, and, , or, !=, !~, ::
In
addition, +=, *= etc. are just abbrevations for
var = var +
other_var
, var = var * other_var, etc. and therefore cannot
be redefined.