« June 2008 | Main | September 2008 »
July 21, 2008
Browse Ruby documentation with improved gem server
I am currently using Netbeans as my Ruby IDE. The autocompletion feature provides some RDoc snippets but does not always work.
The second option is to use some web resources like http://ruby-doc.org/ or directly use google. But this obviously does not work offline and possibly provides the wrong version of the documentation for those living on the bleading edge. For example, I use the "nightly" RSpec version installing it directly from the git hub.
So I stuck to the local gem server. Unfortunately it's start page is not so convenient, so I've patched the rubygems/server.rb. You can append following near the end of file:
# extended by Vladimir Dobriakov, http://www.innoq.com/blog/vd/
rdoc_proc = lambda do |req, resp|
gem_name = req.query['gem']
found_gems = Dir.glob("#{@gemdir}/doc/#{gem_name}*")
if found_gems.length == 1
new_path = File.basename(found_gems[0])
resp.status = 302
resp['Location'] = "/doc_root/#{new_path}/rdoc/index.html"
else
found_gems = Dir.glob("#{@gemdir}/doc/*") if found_gems.empty?
resp.body = '<ul>'
found_gems.each do |gem_name|
path = File.basename(gem_name)
url = "/doc_root/#{path}/rdoc/index.html"
resp.body << "<li style='margin-top: 1em'><a href='#{url}'>#{path}</a></li>"
end
resp.body << '</ul>'
resp['Content-Type'] = 'text/html'
end
end
@server.mount('/rdoc', WEBrick::HTTPServlet::ProcHandler.new(rdoc_proc))
just before
trap("INT") { @server.shutdown; exit! }
trap("TERM") { @server.shutdown; exit! }
@server.start
end
end
Now the new code is tied to urls like http://localhost:3333/rdoc?gem=active providing either a list of the links to the documentation for the gems, which names start with 'active' or directly jumping to the rdoc of the gem in case there is only one search hit.
In my del.icio.us Plugin for the Firefox I connected
http://localhost:3333/rdoc?gem=%s to rdoc keyword. So now I can simply
type in something like rdoc httpauth
UPDATE. One additional trick. Run
# please adjust paths accordingly
# use for example 'locate yaml.rb' and 'gem environment'
# for identifying directories
# install ruby sources
cd /usr/src
sudo apt-get source ruby
rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc /usr/lib/ruby/1.8 ruby1.8-1.8.7.72
to generate the rdoc for the core ruby libraries (not gems). The -o parameter specifies the output directory. Two directory names, that follow, specify the ruby- and the C sources respectively.
And how do you browse the ruby documentation?
Posted by VladimirDobriakov at 7:40 PM | Comments (0)
July 3, 2008
Cutting corners with xmpp4r-simple
xmpp4r-simple aims to provide a wrapper around the powerful and well maintained xmpp4r library, "making it dead-simple to send and receive Jabber messages".
Unfortunately, the abstraction and simplification provided by xmpp4r-simple is leaky, missing the principles of jabber protocol. The result - the naive implementation (from the tutorial) did not work for me:
# Send a message to a friend, asking for authorization if necessary:
im = Jabber::Simple.new("[email protected]", "password")
im.deliver("[email protected]", "Hey there friend!")
Yes, I did replace the example.com
with the name of my server. ;-)
Result - response 406 "Not Acceptable"
The problem
Jabber::ClientAuthenticationFailure: : Not Acceptable
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-0.3.2.99/lib/xmpp4r/client.rb:116:in `auth'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:391:in `connect!'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:322:in `client'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:331:in `send!'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:147:in `status'
from /usr/lib/ruby/gems/1.8/gems/xmpp4r-simple-0.8.7/lib/xmpp4r-simple.rb:90:in `initialize'
from (irb):3:in `new'
from (irb):3
The trace
So I had to go couple of abstraction layers deeper to get it running. At the end I am glad about that. The best opportunity to learn a protocol - to read the documentation in connection with the problem at hand and by observing the actual communication.
Using Gajim's XML Console you can trace the communication between the client and the server:
Client: connecting...
<iq type="get" id="29">
<query xmlns="jabber:iq:auth">
<username>johndoe</username>
</query>
</iq>
Server tells, which information the client should provide:
<iq type='result' id='29'>
<query xmlns='jabber:iq:auth'>
<username>johndoe</username>
<digest/>
<password/>
<resource/>
</query>
</iq>
Client fills in the blanks providing the needed information:
<iq type="set" id="30">
<query xmlns="jabber:iq:auth">
<username>johndoe</username>
<digest>c26789d0exyz4adf8c61e62e8fef27e6d0de</digest>
<resource>Gajim</resource>
</query>
</iq>
Server: connection succeeded:
My server is a jabberd14 (the original reference
implementation of the Jabber protocol), easily installable on Ubuntu
by sudo aptitude install jabber
.
As seen in the log, it requires the resource-clause - some sort of subnamespace. Gajim and Pidgin and probably all other Clients are smart enough to provide it if requested by the server. xmpp4r-simple is not.
The solution
The solution was to provide the required information from the beginning
on, because xmpp4r ignores the Jabber typical handshake. Please
note the /Home
after the jabber id.
im = Jabber::Simple.new("[email protected]/Home", "password")
im.deliver("[email protected]", "Hey there friend!")
Read more about the Jabber communication protocoll.
Posted by VladimirDobriakov at 11:20 PM | Comments (0) | TrackBack