Category Archives: Ruby

I was coding ruby for the past few days, RubyMine 1.1 released means my free evaluation period finished. Because I just code ruby for fun,  $400+ doesn’t make sense to me. Had to switch back to the free NetBeans 5.7.1.

(I still use SciTe on my slow laptop as Ruby IDE, and it’s a very handy lightweight editor, the only thing drove me crazy is switch between editing file can also change the current path of shell, I’m tired of adding and removing ‘test/’  before my rb file. I could use absolute path, but is there any better solution?)

Fortunately, NetBeans also supports subversion. At first I wasn’t happy with the way it forced me to create a default project structure, e.g., all source code supposed be in /lib/ folder, which obviously is an industry standard, but I missed that part.

Another good thing is that NetBeans created a standard Rakefile at the root folder. Simplely throw all my test rb files into /test/ folder, running “rake test”, I got my local build script!

Why didn’t RubyMine create this?

Mock in Ruby, I end up with using Mocha as my mock framework because I still on test:unitest mode. But gem install won’t bring the mocha rb into my ruby search path, had to manually copy mocha into my site_ruby folder, woala, it works.

Recently I found the book The Ruby Way 2nd edition is very good book, but I badly need a book can cover some ruby project management p&p.

Currently I’m the only developer to my ruby project, CI might be overkill, but someday I will need it. I’m supprised that CruiseControl.rb isn’t that popular in ruby community, so many choices, Hudson, cerberus, etc, including CruiseControl.net. I know this is an open/free teamcity ci server somewhere, can it support ruby project?

Wcf Test Client tool shipped with SDK (C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\WcfTestClient.exe) is very useful, looks like the WCF request and response is soap-like message passed around. But I have to publish to a real soap web service to enable other language consume Wcf Service, adding an extra endpoint using basicHttpBinding:

<endpoint address=”soap” binding=”basicHttpBinding” contract=”WcfServices.Contracts.ILookupServiceContract” />

My PowerBuilder client can consume this WCF/Soap webservice now:

  1. Add pbwsclientXXX.pbd to lib list.
  2. Use Web Service proxy wizard, generate local proxy for powerbuilder. (My VMWare environment caused lots of trouble, watch out your firewall/router/http proxy) By adding host into ignore list of IE6, I fixed the wsdl not access problem, but still can’t fix out the same problem on VMWare and IE7.
  3. Code like this:
    soapconnection gnv_con
    gnv_con = create soapconnection
    
    wcflookupservice lnv_lookup
    gnv_con.createinstance( lnv_lookup, 'wcflookupservice' )
    any list[]
    string email_roles[]
    list = lnv_lookup.FetchAllEmailRoles( )
    
    email_roles = list
    
    int i
    for i = 1 to UpperBound(email_roles)
    lb_1.additem( email_roles[i] )
    Next
    

Ruby client can use SOAP::WSDLDriverFactory, example can be found at RESTful Web Services, or this post.  I kept getting “400 Bad Request” error, looked into the request envelope, it turns out I need to force Ruby running in Unicode mode, to change the KCode for XSD::Charset, run Ruby in ‘-Ku’ switch.

For Ruby, the return type from web service is always SOAP::Mapping::Object type.

To parse it, look into the output, for my case:

#<SOAP::Mapping::Object:0×423a8b2 {http://tempuri.org/}FetchAllEmailRolesResult=#<SOAP::Mapping::Object:0×423a7ae {http://schemas.microsoft.com/2003/10/Serialization/Arrays}string=["test 1736582024", "test 1734736950",  "Business Alternate", "Contact Alternate", "test 1658442384", "test 1576477246", "test 518224939", "Contact"]>>

The the parse statement is:


require "soap/wsdlDriver"

def test3
wsdl_url = "http://myhost/RequestManagement/RequestService.svc?wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver

result_set = driver.FetchAllEmailRolesResult("")

result_set
end

p test3['FetchAllEmailRolesResult']['string']

Unfortunately, Google already discontinued their SOAP search API, it’s hard to run the google search example from RESTful Web Services? Can somebody send me an valid Google SOAP search api key?

Another issue with this SOAP::WSDLDriverFactory, how to control name space in request? Because we added the name space into our service contract.


[ServiceContract(Namespace = "Stakeholder")]
public interface IOrganizationServiceContract
{
[OperationContract]
OrganizationDto FetchOrganizationById(long id);
}
Ruby (method not found) Wcf Test Client (Test Passed)
ruby/lib/ruby/1.8/wsdl/operationBinding.rb:40:in `find_operation':
{http://tempuri.org/}FetchOrganizationById not found (RuntimeError)

&amp;amp;lt;s:Header&amp;amp;gt;
&amp;amp;lt;a:Action s:mustUnderstand="1"&amp;amp;gt;Stakeholder/IOrganizationServiceContract/FetchOrganizationById&amp;amp;lt;/a:Action&amp;amp;gt;
&amp;amp;lt;a:MessageID&amp;amp;gt;urn:uuid:60e56fd8-7d46-44db-8b79-61c5e4784a85&amp;amp;lt;/a:MessageID&amp;amp;gt;
&amp;amp;lt;a:ReplyTo&amp;amp;gt;
&amp;amp;lt;a:Address&amp;amp;gt;http://www.w3.org/2005/08/addressing/anonymous&amp;amp;lt;/a:Address&amp;amp;gt;
&amp;amp;lt;/a:ReplyTo&amp;amp;gt;
&amp;amp;lt;/s:Header&amp;amp;gt;
&amp;amp;lt;s:Body&amp;amp;gt;
&amp;amp;lt;FetchOrganizationById xmlns="Stakeholder"&amp;amp;gt;
&amp;amp;lt;id&amp;amp;gt;8172&amp;amp;lt;/id&amp;amp;gt;
&amp;amp;lt;/FetchOrganizationById&amp;amp;gt;
&amp;amp;lt;/s:Body&amp;amp;gt;
&amp;amp;lt;/s:Envelope&amp;amp;gt;

RESTful service is the way to go, here is a simple demo I learned from how to setup WCF in RESTful service.

I wish I had used Aptana studio (Radrails) 2 years ago, so my ruby coding experience could be more fun. This IDE is very close to Visual studio + Resharper for CSharp coding. The intelligence looks a little bit werid, might because there are too many method in ruby’s object type.

What else I like very much includes:

  1. Unite-test view, exactly same as Junit in eclipse. Once I run one of the test case, it seems no way back to the full list. Unless I re-run the class level test or select the latest test I had run.
  2. Outline view, can even launch unit-test directly. But for the method level unit-test I had to hard type in class name and method name, why no smart drop down list available?
  3. Ruby core api help window, not that help than MS one, but better than nothing.
  4. Code compete, for method, if block, etc. Same as Resharper does for CSharp.
  5. Open declaration, very useful, F3, just like Ctrl+B in R#. But it seems not very stable, I kept getting error “select text not in a ruby …”, switch to eclipse, work for a while, then got the same problem again. For some reason, my home pc just work fine. Need to figure this out someday.
  6. Looks like this aptana studio can also do php and python coding, even ajax javascript, WOW!

The annoying part for Ruby coding is environment config. For some reason my libxml didn’t work on my windows env, figured out almost whole day, then it magiclly starts to word. Still don’t know why. Probably I should copy those lib2xml.dll into windows system folder, and then copy the xml folder under $ruby\lib\ruby\site_ruby\1.8. But I was too tired of copying those folders, don’t know what one did the work. Anyway, it works now, PFM.

Those files are needed for libxml running on windows.

  1. ruby\lib\ruby\site_ruby\1.8\xml\libxml.rb
  2. ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\libxml_so.so
  3. ruby\lib\ruby\site_ruby\1.8\libxml.rb

I also got a problem on installing log4r, tried gem install, update_rubygems, didn’t work, always got a loaderror. I tried “ruby -e ‘require “log4r”‘, the log4r already shonw in the list, but why still loaderror?

I ended up with download the tgz file, and run the ruby install.rb, it seems this process is doing lots of file links afterwards. So, it works. A new folder log4r was created under “ruby\lib\ruby\site_ruby\1.8\”, different than gem install.

Look into log4r, 5 methods in it, debug, info, warn, error and fatal, extact same as log4net. I remeber somewhere in my app I use a trace, it seems not a standard one.

Just tried this IDE for Ruby, I was having problem to install the plugin into Eclipse 3.2, then switched to new 3.4, everything works OK.

I have no experience on NetBeans, but some people said RaDRails is quicker, intelligent and easy to use. This the intelligence I got. But I tried to use it as an online help, it seems not all the methods can pop-up after the dot.

Later I realize I can use the build-in  “Ruby Interactive (RI)” or “Ruby Core API” view.

Comparison between RadRails and Netbeans.

Here is a poll showing RadRails is 3 times popular than NetBeans.

  1. rfc822   ‘Tue, 1 Jul 2003 10:52:37 +0200′
  2. rfc2616 (httpdate)  Tue, 05 Sep 2006 16:05:51 GMT
    podcast use this.
    d.strftime(“%a, %d %b %Y %H:%M:%S %z”)
  3. iso8601 2001-04-17T19:23:17.201Z

code demo:

t = Time.at(1000000000) # => Sat Sep 08 21:46:40 EDT 2001
t.rfc822 # => “Sat, 08 Sep 2001 21:46:40 -0400″
t.httpdate # => “Sun, 09 Sep 2001 01:46:40 GMT”
t.iso8601 # => “2001-09-08T21:46:40-04:00″

Parse string to date

Say you have a string ‘080430′, you can not simply use

Date::strptime(s, ‘%y/%m/%d’)

to convert it to a Date type. (ArgumentError: 3 elements of civil date are necessary)

Had to split to to 3 parts, then do the convert.

s = ‘080204′
s.sub!(/^(\d{2})(\d{2})(\d{2})$/, ‘\1/\2/\3′)
d = Date::strptime(s, ‘%y/%m/%d’)
How to convert a Date to Time?

Most of time, I use Notepad++ as primary texeditor, seldom I had to switch to TextPad when I need compare file difference.

SciTE is the one I only use when I need to do some Ruby coding. I like it’s embed output feature, very handy, so I don’t need to switch between windows that often. I checked NotePad++ has a ‘Run …’ function, but what I need is to provide ‘-n’ parameter to ruby command to run my unit-test.

ruby_unit_test_in_scite.jpg

Maybe someday I will figure out how to hook up Ruby Unit Test with NotePad++. For now, I have nothing to complain to SciTE yet.

I was using Kouhei Sutou’s rss lib to parse and generate a rss feed, it was running very well until I stuck with setting the CDATA value to description field. On Kouhei’s webpage it was said this lib started support content:encoded syntax since version 2.11. But my test found that it can read CDATA, not setting.

Emailed to Kouhei directly, got response pretty fast: I can’t do that.

OK, Ruby is too new to those stuff. I had to turn to php then.

Found 2 nice libs, lastRSS and feed generator, both are from Europe, fantastic tools, even neither of them has been updated since 2005.

The only glitch in feed generator is the default value of encoding, I had to hatch into its class module to change channel.encoding, the outside operation doesn’t work.

To set the CDATA using feed generator, syntax look like this:

$item->description = “asdfasfasf<br />asdfasdfa<br />”;
$item->descriptionHtmlSyndicated = true;

The generated rss xml will be:

<description><![CDATA[asdfasfasf<br />asdfasdfa<br />]]></description>

I have another problem using lastRSS, the fopen(rss_url) method only works locally, not on my DH shared host, maybe the allow_url_open is off by default on DH? I didn’t spend too much time on it because I switched to curl to work around immediately. I will look into this setting later.

LastRSS does not support ATOM, so I use famous MagpieRSS instead for an ATOM feed. There is only one thing I don’t like MagpieRSS is, it only reads feed from url, while lastRss can read both from url and file.

5DollarWhiteBox has a cool lib for ruby to utilize Unix style config file, like:

serverID = web01
serverIPAddress = 192.168.1.102

I tried, it works OK. The only problem is one of my settings has a equal sign in it. This parser then screwed up.

myUrl = http://someghing.com?myId=123

So, xml config is the only option for me, and it’s more popular and cross-platform. By using ruby standard lib ‘rexml/document’, the following configuration can be easily parsed out.

conf_file:
<justing>
<rss_feed_url>http://podcast.overseakids.com/justing_history.xml</rss_feed_url>
</justing>

require ‘rexml/document’
doc = REXML::Document.new(File.new(conf_file))
rss_feed_url = doc.elements['justing/rss_feed_url'].text

Found a good article about ruby access J_security_check, which gave me a clear view about j_security_check. My revised ruby code looks like this:

     def form_auth_demo
res = Net::HTTP.new(host, port).start do |http|
#make the initial get to get the JSESSION cookie
get = Net::HTTP::Get.new(path_to_jsp)
response = http.request(get)
# get original cookie contains jsessionid=blahblahblah
cookie = response.response['set-cookie']

#authorize
post = Net::HTTP::Post.new(‘/MyApp/j_security_check’)
post.set_form_data({‘j_username’=>’XX’, ‘j_password’=>’XX’})
post['Cookie'] = cookie
response = http.request(post)

# one way to check result
# puts ‘Code = ‘ + response.code
# puts ‘Message = ‘ + response.message

# another way to check result
# case response
# when Net::HTTPSuccess
# puts ‘Login OK’
# when Net::HTTPRedirection
# puts    ’redirect to ‘ + response['location']
# else
# res.error!
# end

# grab the new cookie generated from server contains jadid=XXX
# This is extra line I added, I think the reason is because we are using EAServer.
cookie2 = response.response['set-cookie']

# replace the old one with this authenticated new cookie.
get['Cookie'] = cookie2

response = http.request(get)

puts ‘Code = ‘ + response.code
puts ‘Message = ‘ + response.message
# puts response.body

end
end

Now I know a little bit more about what happens in  j_security_check.

  1. Client send request, sever check if client has been authenticated. If not, send a JSessionID back to client, then redirect to login page.
  2. Client input credentials, submit form. After validate, server generate a JadID (I think this might be a EAServer unique feature.
  3. Client has to use this updated cookie to continue work.

Every Moday, a radio station in Sigapore will upload a new epsiode of their Movie Review program, one of my favorate podcasts. Unfortunately, they only update the html page part, the podcast feed updating usually happens days later.

I can’t wait that long, so I wrote my Ruby program to rip their html page, get mp3 url, and then, to generate a latest podcast feed used by my itunes.

mc = MovieCafe.new
mc.get_mp3_list

newitem = mc.mp3_list.first

if newitem.mp3_url != mc.rss.items.first.enclosure.url
#item = RSS::Rss::Channel::Item.new
item = mc.rss.items.first
item.title = newitem.title
item.enclosure.url = newitem.mp3_url

item.description = newitem.description
item.pubDate = Time.now

mc.rss.items.push(item)

mc.rss.channel.lastBuildDate = Time.now
endputs mc.generate_feed

The problem I got was, the charset from html is gb2312, while the podcast feed is utf-8. I had to covert charset. Eventually, I made it:

require ‘iconv’

title = Iconv.new(“UTF-8″,”gbk”).iconv(title)

Here is my podcast feed of Movie Review channel, at least 2 days newer then its offical one.