Sep 07
The Rails framework includes a simple “delegate” method, which is mixed in the models, and can be used in order to delegate methods to other classes. However it’s limited at least in the following:
1. It doesn’t prevent “train wrecks” – e.g. if the class that the method is delegated to is nil, then there will be an attempt to call this method on the nil class.
2. It doesn’t allow renaming of the methods, e.g. if you have a method called “name” in your class, and a method called “name” in other class you want to delegate to, you have no means of doing this.
The implementation below remedies these shortcomings.
class Module
def delegate(*methods)
options = methods.pop
unless options.is_a?(Hash) && to = options[:to]
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
end
prefix = options[:prefix] || ''
orig_prefix = prefix
if prefix != true and !prefix.empty?
prefix += '_'
end
methods.each do |method|
prefix = to.to_s + '_' if orig_prefix == true
module_eval(<<-EOS, "(__DELEGATION__)", 1)
def #{prefix}#{method}(*args, &block)
return nil unless #{to}
#{to}.__send__(#{method.inspect}, *args, &block)
end
EOS
end
end
end
You can use it like this:
delegate :name, :to=> :other, :prefix=>true
and it will delegate a method “name” in “other” class as “other_name” in your class.
Or, alternatively
delegate :name, :to=> :other, :prefix=>'some'
will delegate “some_name” to class “other”, method “name”.
Aug 30
While the acts_as_tree rails plugin ( http://dev.rubyonrails.com/svn/rails/plugins/acts_as_tree ) provides some basic methods for accessing tree like data structure, I found that it lacks some basic ones, for example – has_children? and has_siblings?
Other than that, it would have been nice to know the tree width and depth (especially if you need to draw it, and need to calculate the scaling.
module ActiveRecord
module Acts
module Tree
module InstanceMethods
def has_children?
!self.children.size.zero?
end
def has_siblings?
!self.siblings.size.zero?
end
# Return the tree depth
def depth
return 0 unless has_children?
children.inject(0) {|dep,c| dep > c.depth ? dep : c.depth} + 1
end
# Return the tree width
def width
return 1 unless has_children?
children.inject(0) {|sum,c| sum + c.width}
end
end
end
end
end
Maybe if I won’t be lazy, I’ll write some tests and send this for inclusion in the plugin…
Aug 20
When playing with LSI, I noticed that the program runs for too long and uses enormous amounts of memory.
Using a great tool ruby-prof, I found, to my astonishment, that I waste more time in stemming than in SVD.
So I wanted to try to see, if using a compiled C extension will make a difference. So I took the thread-safe porter algorithm from http://tartarus.org/~martin/PorterStemmer/ and wrapped it with swig.
The results were almost in an order of magnitude (10000 rounds for 11 words):
user system total real
stem : 3.480000 0.250000 3.730000 ( 3.719107)
fstem: 0.440000 0.090000 0.530000 ( 0.526526)
This I call “performance boost”
porter.i (for swig):
%module stemmer
%{
char *stem_word(char *word)
{
int length, i;
char *res;
struct stemmer * z = create_stemmer();
length = stem(z, word, strlen(word)-1);
/* length is the index of last char, add one for size and one for '�' */
res = (char *)malloc((length+2) * sizeof(char));
for (i=0; i<=length; i++)
{
res[i] = word[i];
}
res[length+1] = 0;
free_stemmer(z);
return res;
}
%}
%newobject stem_word;
char *stem_word(char *);
Aug 05
The following steps are usually sufficient in order to make “pretty URLs” in mediawiki, e.g.
http://wiki.somehost.com/Article_Name
In Apache configuration:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/(skins|stylesheets|images|config)/
RewriteCond %{REQUEST_URI} !^/(redirect|texvc|index).php
RewriteRule ^(.*)$ /index.php?title=$1 [L,QSA]
In LocalSettings.php
$wgScriptPath = "";
$wgScript = "$wgScriptPath";
$wgRedirectScript = "$wgScriptPath/redirect.php";
$wgArticlePath = "$wgScript/$1";
However, the latest version (1.12.0 at the time of writing) needed the following patch, in order to make all things work. I don’t know whenever this was already reported by someone and/or fixed.
--- includes/Title.php.orig 2008-08-05 22:56:32.000000000 +0300
+++ includes/Title.php 2008-08-05 23:16:22.000000000 +0300
@@ -832,7 +832,12 @@
if ( $query == '-' ) {
$query = '';
}
- $url = "{$wgScript}?title={$dbkey}&{$query}";
+ # Assume "pretty URLs" if wgScript is empty
+ if ( $wgScript == '' ) {
+ $url = "/{$dbkey}?{$query}";
+ } else {
+ $url = "{$wgScript}?title={$dbkey}&{$query}";
+ }
}
}
Aug 05
This upgrade was a real pain.
Though there are many resources on the web, which talk about this kind of upgrade (and the best one in my opinion is this one: http://julien.danjou.info/blog/index.php/post/2008/05/19/Upgrading-mediawiki-from-PostgreSQL-82-to-83), all of them fall short of giving a succinct but precise instruction for this upgrade. I tried to follow the aforementioned article, but it still gave some errors.
So I’ve done something similar, but a little bit different, finally importing the 8.2 database without a single error.
First of all, I dumped the original database in two parts – schema and data.
I took the schema part and divided it in two: schema definition and constraints and indexes. From the former I removed all references to tsearch2 functions, in the latter checked that the “search_path” is correct for every bulk of updates. Then I wanted to import the new tsearch2 functions that come with PostgreSQL 8.3.
So I wrote a simple script which I used in order to import the db several times, fixing bugs and eliminated all the problems which were still present:
#!/bin/sh
export PGUSER=postgres
dropdb wikidb
createdb wikidb
psql -q wikidb < /usr/share/pgsql/contrib/tsearch2.sql
echo "Inserting wiki schema"
psql -q wikidb < wiki_schema.sql
echo "Inserting data"
psql -q wikidb < wiki_data.sql
echo "Inserting constraints"
psql -q wikidb < wiki_schema_constraints.sql
At the end all files were imported without a single error.
Then I discovered, that I’ll have to update mediawiki from 1.11.0 to 1.12.0, since the former doesn’t work with PostgreSQL 8.3
The update had only one problem (missing file – it’s mentioned in the link above), which was easy to remedy.
Upon using the mediawiki I found out, that I’ve to grant access to one of the tables.
It was probably due to the fact, that it was added to schema by user other than wikiuser:
GRANT ALL ON TABLE protected_titles TO wikiuser;
Seems to work fine so far.
Jul 27
When trying to help our engineers to configure Apache 2.2 I found out to my complete astonishment, that Apache doesn’t allow negation of environment, e.g. to perform some action in context of mod_authz_host allow/deny when some environment variable DOESN’T exist, thus the directive below has no effect:
Deny from env=!HAS_SOMEVAR
I opened a bug with a patch, which was accepted, and lately it was backported to 2.2 branch, therefore it will appear in the next version (2.2.10).
Other shortcoming that I’ve found, that it’s impossible to unset a cookie while using mod_rewrite, but checking the code revealed, that the value for the cookie isn’t checked, therefore it’s possible to inject arbitrary string there, and this is exactly what I did:
RewriteRule ^/$ http://myhost.domain/url [CO=JSESSIONID:;comment=Reset:.myhost.domain:0:/,L]
Notice the trick – the value for cookie is “;comment=Reset” and validity period of 0 minutes making the Set-Cookie header look like this:
Set-Cookie: JSESSIONID=;comment=Reset; path=/; domain=.myhost.domain;
expires=Sun, 27-Jul-2008 12:00:08 GMT
Jun 24
The dhtmlxTabbar is a nice tab-bar component from http://www.dhtmlx.com/
In order to use the AJAX loading feature I had to make a small change in the dhtmlxcommon.js so it mimics the behavior of Prototype by adding a X-Requested-With HTTP header. Thus, it’s possible to use request.xhr? in Rails.
dhtmlxcommon.js
Feb 02
Today was a perfect day for hacking wget.
I wanted to mirror some site, and to my astonishment found out, that wget doesn’t support regular expressions for including the paths to mirror. Only a list of directories for including/excluding could be provided.
This was easily remedied using the excellent pcre library.
The patch is quick and dirty, and if one would like to compile wget with it, -lpcre should be added to LIBS in Makefile.
Patch for wget which adds regular expression matching for urls
Update: Well, it seems that there was a similar patch available for years: http://www.mail-archive.com/wget@sunsite.dk/msg07395.html
Oct 17
Since I wanted to write some private posts which ought to be encrypted as well as hidden, I was naturally looking for an encryption plug-in for wordpress. However, to my great disappointment, I couldn’t find one.
Perhaps I’ll write one. The basic idea is that there will be an option to mark the post as encrypted when writing it.
In that case, when the Save or Publish button will be pressed, the javascript will ask to decrypt the key (which is stored on the server in the encrypted form) and then will use the decrypted key to encrypt the content and convert it to base64. The content then will be modified in place and then sent to server.
When watching the post, the javascript will prompt for password for the key, decrypt it, and then use it in order to decrypt the ciphertext in place.
The cryptographic algorithm which can be used is AES-cbc, which is available in javascript.
Quite secure, since the password is not sent via the net.
Now I just have to find some time to implement it …
Aug 27
I needed to present products and their corresponding branches and tags in Subversion in a Rails app. So I’ve come up with this quite simple solution.
The GenericModel class (attached) is ihnerited by Tag, Branch and Product.
The Product class supports methods find, branches and tags for which it uses ’svn/client’.
The config.yml (which is read into OpenStruct) is very simple:
svn:
url: http://svn/svn/repos
user: roman
password: roman
The Product class tries to provide interface similar to the ActiveRecord (of course I didn’t immitate everything, just the basic stuff). Implementing interfaces in a contract-less language is an adventure
generic_model.rb
product.rb