Class instance variable for ruby modules

Sorry if the title is a bit misleading, but this post talks about the scenario such that I have several classes, all extending the same module, and I need to avoid using shared or class variables (@@) in the module because the classes extending the module may change the shared or class variable at the same time and cause problem.


So basically we have:


class Test


  extend TestModule


end


class TestTwo


  extend TestModule


end


module TestModule


  @@val


  def somemethod


     #do something with @@val


  end 


end 


And the goal is the replace the @@val class variable with a class instance variable so that if the Test.somemethod and TestTwo.somemethod happens at the same time, there won’t be any problem.


The easiest way (I can think of) of doing this is to set the variable within the class, instead of setting it in the module. For example:


class Test


  @val = “abc”


  class << self; attr_accessor :val; end


  extend TestModule


end 


But the problem of doing this is that everybody else using TestModule will need to update their code after this update, which is unacceptable.


Is there a way to move the variable definition and accessor to the module and has exactly the same effect as defining them in the class? Yes. define the self.extended(base) method.


module TestModule


  def self.extended(base)


    class << base; attr_accessor :val; end


    base.val = “abc”


  end


  def somemethod


     #do something with self.val


  end 


end


class Test


  extend TestModule


end


 


Here base refers to the class extending this module. self. extended is called when the module is initialized, and the accessors for the base class is then created (class << base; attr_accessor :val; end), base.val = abc sets the default value.


By doing it this way, the module works exactly the same as before, and multiple classes can extend it and call the same method without affecting each other.


Hope this helps.

Don’t forget the port number when replicating CouchDB

In the afternoon I needed to replicate a database  from my co-worker’s CoudhDB using CouchDBX. In the replicator, I entered my co-worker’s database’s path like the following:


http://10.0.0.3/TestDatabase


And I selected to replicate to one of my existing databases.  Everything seemed to be right (I could ping and telnet my co-worker’s IP and CouchDB port 5984 without problem), but CouchDBX returned error 500, could not connect to remote database.


After a series of diagnostics, we finally realized, we forgot to put the port number in the path of remote database. When we changed the database path to http://10.0.0.3:5984/TestDatabase,  everything just worked very well.


I’m sharing this since I bet many people may encounter the same problem. Hope this is helpful.

Creating a Merb Rack middleware for running in Merb applications

There are a lot of resources on the Internet showing how to write and run a standalone rack application or middleware, but few showing how to write one to run in other Merb applications. This is actually very easy, so I’m going to share how I did it. Hopefully to be helpful to people in such need.


The goal is to have a rack middleware in a merb application, which can be installed as gem, and then can be ued in other merb applications.


First, create the merb application:


$ merb-gen app  application_name 

where application_name is your proposed application name.


Second, create your code folder and ruby file. I created a “lib” folder to be the container of my middlewares.


Third, open the ruby file and write your middleware. (In this example, let’s name  it samplemiddleware.rb within the “lib/test” folder)


The class could inherit Merb::Rack::Middleware if you want. Below is an example.


module Test
  class SampleMiddleware < Merb::Rack::Middleware
   
    def initialize(app)
      @app = app
    end
   
    def deferred?(env)
      @app.deferred?(env) if @app.respond_to?(:deferred?)
    end
   
    def call(env)
      puts “do something here”
      @app.call(env)
    end
   
  end
end


Fourth, write your rake file, so the rack middleware merb application can be installed as a gem.


Fifth, install the gem.


So far we finished the middleware, now we go to the other merb application which we want the middleware to run within. Assuming the merb application has a rack configuration file (rack.rb) under the “config” folder. Open this file.


We need to require our middleware, in this case:


require 'test/samplemiddleware.rb''

And then use the middleware in the same file:


use Test::SampleMiddleware

Finally remember to have a line to run the Merb::Rack application (should already have it):


run Merb::Rack::Application.new

Now when the merb application runs, the rack middleware you wrote and installed will run as well. It’s handy to use the middleware to process requests in your Merb applications before Merb handles the requests.

Modify bind address for couchdb 0.9.0

By default couchdb only binds to 127.0.0.1 so it’s not accepting requests from other IP addresses. The bind address setting can be modified in the configuration file. For 0.9.0, by default, the default configuration file is located at /usr/local/etc/couchdb/default.ini, and the local configuration file is located at /usr/local/etc/couchdb/local.ini. Settings in the local configuration file will override those in the default one. 


Bind address is in the [httpd] section


[httpd]

port = 5984

bind_address = 127.0.0.1

Note that in the local configuration file, this may be commented out with a leading “;”, if you want to set it in the local configuration file, you need to uncomment the bind_address line and modify 127.0.0.1 to some other IP address.

If you modify the bind address to 0.0.0.0, it will bind all interfaces.

 

 

 

Making an executable standalone Merb Slice gem

I have a standalone Merb Slice which can be started by running the “slice” command in its top directory. Today I needed to make a gem file for this Slice so that people can install the gem and start it directly by running the Slice’s name, for example, “foo”.


So I created the Rakefile, in which I specified the executable file in the following way:


— Code: Rakefile —


spec = Gem::Specification.new do |s|
  s.rubyforge_project = ‘merb’
  s.name = GEM_NAME
  s.version = GEM_VERSION
  s.platform = Gem::Platform::RUBY
  s.has_rdoc = false
  s.summary = SUMMARY
  s.description = s.summary
  s.author = AUTHOR
  s.email = EMAIL
  s.homepage = HOMEPAGE
  s.executables = “foo”
  s.require_path = ‘lib’
  s.autorequire = GEM_NAME
  s.files = %w(Rakefile TODO) + Dir.glob(“{config,lib,spec,app,data,public}/**/*”)
end


Then I created a bin folder within the Slice’s top directory, and created a file named “foo” within the bin folder I put Merb.start in the file “foo”, and I tried to make a gem and installed it. But the Slice did not start correctly this way.


Then I spent a while trying different possibilities, and with somebody’s help, I finally got the right way of doing it.


1. look up the location of merb-slices. This can be done by executing gem list – d | grep merb-slices.


2. locate a file named “slice” under the bin folder of merb-slices.


3. copy the contents of this file to the file you have in your Slice’s bin folder, and amend from that (you may want to remove or change the Merb::Config.use block since your own Slice may have that set somewhere else, for example, in init.rb).


 


Depending on how you amend the slice binary file, you may encouter a situation that your executable is only able to run within the source folder. For example, if you run “foo” in your Slice’s source folder, it becomes equivalent as running “slice”, but if you run it anywhere else, it fails with the error “No slice found”. If this happens, what you need to do is change the following things in your “foo” binary file:


1. Change __DIR__ (originally assigned to current directory):


Dir.chdir File.join(File.dirname(__FILE__),”..”)
__DIR__ = Dir.getwd


2. Update slice_name:


slice_name = “foo”


3. Add a line before Merb.start to specify the right init file to load:


ARGV.push *[ “-I”, File.join(File.dirname(__FILE__), “..”, “config”, “init.rb”) ]


Note: This assumes init.rb is under config folder of your Slice project.

Testing exceptions with RSpec

I’m new to ruby and rspec. I wrote a ruby function and wanted to check whether it throws an exception or not in a certain situation with rspec, but I realized should_raise function no longer worked in the rspec version I was using (1.2.2). I tried to find information on the Internet and I found that I should use raise_error.


However, when I wrote something like:


it “description” do
    ObjectName.new(“parameterName”).should raise_error
end


It did not work. Finally I learned the correct way – using lambda:


it “description” do
    lambda{
ObjectName.new(“parameterName”)}.should raise_error
end


Wanted to post this here and hope it can be helpful for people in the similar need.


 

Writing and Project Samples

PROGRAMMING AND WRITING



1. Windows Mobile Starter Kits: Tic Tac Toe and Home Screen Alarm Plugin


Description:


These two projects were completed when I was working at Microsoft Mobile and Embedded Devices Content Publishing Team (Summer 07). Both programs were written in C++ with easy to understand documentations. I was involved in the design, development, testing and documentation processes. The Tic Tac Toe project focused on Windows Mobile Ink APIs and screen resolution awareness; the Home Screen Alarm Plugin project focused on Windows Mobile 6 Standard Home Screen Plug-in programming.


URL (at Microsoft’s web site):


http://msdn.microsoft.com/en-us/windowsmobile/bb264330.aspx


2. EasyCapture User Assistance Documentation


Description:


This was a group project for the University of Washington TC 407 Software User Assistance class (Spring 08). We created high value documentation for the EasyCapture software. We single sourced the main contents and created a user manual in print (PDF) format as well as an online help in HTML format. We used Madcap Flare 3.0 as our primary tool to manage contents and generate output.


URL to PDF user manual:


http://students.washington.edu/nuoyan/proj/TC407/TeamD/FinalPDF_June4th.pdf


URL to HTML online help:


http://students.washington.edu/nuoyan/proj/TC407/TeamD/HTML_version.htm


URL to MadCap Flare Source Files:


http://students.washington.edu/nuoyan/proj/TC407/TeamD/FlareProjectSourceFiles/ 



 


DESIGN AND HUMAN COMPUTER INTERACTION



1. ParkSmart Prototype


Description:


This was a team project for the University of Washington CSE 440 Human Computer Interaction class (Autumn 08). It’s a prototype of a location aware iPhone application that helps drivers find parking spots. 


URL to project web site:


http://www.cs.washington.edu/education/courses/cse440/CurrentQtr/project_files/parking/

Using Eclipse to add/update files to CVS

The command-line based CVS tool is hard to use for first time users; many GUI-based CVS tools are not really well designed to be easy to use either. I’m not against the point that developers and testers should learn how to use a technical tool in no time even though the tool is hard to use, but developers and testers have their schedules and need to be efficient. Having an efficient way to add and update files to CVS is very necessary.


Eclipse is the tool I use to deal with CVS file operations. It works really well not only with source code, but any other file type.


For example, if you want to upload a Microsoft Word document (docx) to a remote CVS repository, simply follow the following steps:


1.       In Eclipse, import the remote CVS repository by using the Import wizard:


a.       Click File->Import


b.      Choose “Projects from CVS” and click Next


c.       Depends on real situation, either select “Create a new repository location” or “Use an existing repository location”. In this example, we use an existing repository location because we want to add the Microsoft Word document to an existing CVS repository. Click Next.


d.       Select “Use an existing module”, and navigate the tree list to find the repository you want to add the file to. Click Next.


Note: If you need to upload different files to different subfolders (repositories) within a folder (repository), it’s often useful to select the parent folder in this step so you don’t need to run this wizard every time for each of the subfolders.


e.      Follow the remaining steps in the wizard to finish the import process. Selecting “Check out as a project in the workspace” is the easiest way to import the repository to a new project. If you want to import it into your existing project, select “Check out into existing project.”  


 



2.       Import the file(s) you want to add/update to the CVS repository to the appropriate folders:


a.       In the Project Explorer, expand the folder you just checked out from CVS, right click the folder you want to add the new file to, and click “Import” from the context menu.


b.      Select “File System” and click Next.


c.       Click “Browse…” to browse the folder containing the file you want to add or update to CVS.


d.      Select the files, and click “Finish”.


 



3.       Now the file(s) you want to add or update to CVS are in the appropriate folders. Right click each file, and click Team-> Commit to commit the file to the corresponding remote CVS repository.


Hope this helps.

How to connect Remote Spy++ to Windows Mobile emulators in Visual Studio 2008

I don’t see any problem doing so, but I got a question from a comment of one of my earlier post.


The question states


Hello! Could you please tell more about how to make Remote Spy++ connect to WM 5.0 emulator, which I got with MSVS2008? I’ve read some articles at microsoft.com, but they say you can’t connect to Windows Mobile, only Windows CE…


So I want to explain the process to connect Remote Spy to Windows Mobile emulator in Visual Studio 2008.


Here are the steps:


1. On the Debug menu of Visual Studio 2008, click Start Debugging.


Note: Make sure you selected the correct emulator, for example, USA Windows Mobile 5.0 Pocket PC R2 emulator, depending on what Windows Mobile SDK you’re using for your project. The step is the same for Windows Mobile 6 and 6.1 emulators.


2.  On the Start menu, click All Programs, expand Microsoft Visual Studio 2008 folder, click Remote Spy in the Visual Studio Remote Tools folder to start Remote Spy.


3. In the Select a Windows CE Device dialog box of Remote Spy, select the emulator (or device) you want Remote Spy to connect to (the same one as you selected in step 1). Then click “OK.” Shortly you will be able to see the Windows List shows up.


Let me know if there’s any problem, and I will figure it out for you.

No way to join the social – Is the lack of global languages support on Zune a problem, or not at all?


It’s been a pretty long time since the first generation of Zune came out. Microsoft wants to attract us as potential users to join the social – they made pretty good media sharing and community features so that to distinct from similar products made by other companies.

However, Zune has a very serious usability problem that even though a huge amount of users have been complaining all the time, it’s never been solved. It is the lack of support for most of the global languages.

It’s true that Zune has not yet been available globally. However, the assumption of people in North America only listen to English, French, and Spanish songs just does not make sense. There’re people originally from almost anywhere in the world reside in North America temporarily or permanently. They speak different languages and they have their entertainment needs as well. They listen to English songs, but they also listen to songs on their own languages.

You will be able to see the demand of global languages support by just doing a simple search on the Internet. You will see a huge number of complains from the date the first generation of Zune came out all the way up to the present time.

The users do not even need Microsoft to have Zune menus displayed in their languages. They just need Zune to have the ability to show their song information correctly on the device. Technically, this is really a simple task for Microsoft to do. So it’s become a do-or-not-do decision for Microsoft. But provided the fact that until the newly released version 2.5, Zune still doesn’t support most global languages, I guess Microsoft made the not-do decision. But I still hope in the upcoming third generation, they can do it.

If you now think that Microsoft has done nothing about this issue, you are wrong. In order for the users to solve this design or usability problem, Microsoft published a Knowledge Base article (http://support.microsoft.com/default.aspx/kb/928210/en-us?sd=zune). It simply asks the user to change all the song information in other languages to their equivalent English representation. Well, does anybody like to find some spare time to translate and change the name, album, and artist information of 10,000 songs in the media library? Or do you, as a user, want to just simply buy an ipod, iriver, or Creative zen?  Microsoft tried to ask the customers to solve their own design issues. This will not work out in this user centric era!

As the result, people have songs in foreign languages are in a frustrating situation. They may like their Zunes; they may like the social; but they don’t want to see the boxes showing in the device instead of the correct characters or languages anymore! Finally, they decide to switch, they either buy a much cheaper music player but supports 20 languages including their own, or go to use an ipod.

Microsoft should really do something to solve this – provided it’s really just a matter of whether or not putting some font files in the system partition with just a little extra work.