pl.comp.lang.ruby

Opublikowane przez Jarosław Zabiełło Thu, 05 Jan 2006 10:36:00 GMT

Pojawiła się inicjatywa założenia grupy dyskusyjnej pl.comp.lang.ruby. Aby grupa powstała potrzebne są głosy poparcia sympatyków tego języka na pl.news.nowe-grupy.

Posted in  | Tagi  | brak comments

Komentarze i filmy z konferencji Django + Ruby on Rails

Opublikowane przez Jarosław Zabiełło Thu, 05 Jan 2006 10:26:00 GMT

Zostały udostępnione nagrania wideo z ostatniej konferencji Snakes and Rubies organizowanej przez developerów Django oraz Ruby on Rails. Wiele osób umieściło także komentarze na temat tej konferencji w swoich blogach.

Posted in ,  | Tagi ,  | brak comments

Rails i Django organizują wspólną konferencję!

Opublikowane przez Jarosław Zabiełło Thu, 17 Nov 2005 20:00:00 GMT

3 grudnia developerzy Rubiego i Pythona mają się spotkać razem na uniwersytecie DePaul w Chicago. Będzie można usłyszeć dwóch liderów aplikacji webowych drugiej generacji. Przemawiać będzie twórca Railsów: David Heinemeier Hansson oraz twórca Django: Adrian Holovaty. Można wysłać za pomocą internetu pytania do obu mówców na które będą odpowiadać podczas konferencji. Zobacz http://snakesandrubies.com/event Mam nadzieję że będzie z tego dostępny jakiś film albo chociaż transkrypcja.

Posted in ,  | Tagi ,  | brak comments

Brakująca metoda GetMany dla ADOdb

Opublikowane przez Jarosław Zabiełło Tue, 15 Nov 2005 11:01:00 GMT

Jedną z najlepszych bibliotek opakowujących połączenia do baz relacyjnych dla PHP jest "ADOdb":http://adodb.sf.net. Pomijając wiele zalet używania ADOdb (zintegrowany cache, moduł w C, czytelne API) zamiast PEAR::DB lub natywnych (i koszmarnych składniowo) funkcji PHP chciałbym zatrzymać się nad jedną niedoróbka. Otóż od dawna brakuje tam Funkcji GetMany() która byłaby odpowiedzialna za pobieranie porcji danych z bazy. Jest co prawda funkcja SelectLimit() ale jest jest beznadziejna gdyż nie umożliwia korzystania z parametryzowanych zapytań SQL. Poza tym ma fatalną, nieintuicyjną nazwę. Skoro jest GetOne(), GetAll(), GetRow() to dlaczego jej też nie nazwali GetMany()? Postanowiłem te braki uzupełnić. Poniżej przykład implementacji opartej na ADOdb:
<?php
require_once 'adodb/adodb.inc.php';
require_once 'adodb/adodb-errorhandler.inc.php';

class Database
{
    var $conn;
    
    function Database($cfg)
    {
        $this->conn =& NewADOConnection($cfg['dbtype']);
        $this->conn->Connect(
            $cfg['host'], 
            $cfg['user'], 
            $cfg['passwd'], 
            $cfg['db']);
         $this->conn->SetFetchMode(ADODB_FETCH_ASSOC);
    }
    
    function GetAll($sql, $params=null)
    {
        return $this->conn->GetAll($sql, $params);
    }
       
    function GetRow($sql, $params=null)
    {
        return $this->conn->GetRow($sql, $params);
    }   
    
    function GetOne($sql, $params=null)
    {
        return $this->conn->GetOne($sql, $params);
    }   
    
    function GetMany($sql, $params=null, $from, $limit)
    {
        $result = array();
        $recordSet = $this->conn->Execute($sql, $params);
        while (!$recordSet->EOF) {
            if ($from > 0) {
                $from -= 1;
                $recordSet->MoveNext();
            } elseif ($limit > 0) {
                $limit -= 1;
                $result[] = $recordSet->fields;
                $recordSet->MoveNext();
            } else {
                $recordSet->MoveNext();
            }
        }
        return $result;
    }   
}

$cfg = array(
    'dbtype' => 'mysql',
    'host' => 'localhost',
    'user' => 'root',
    'passwd' => '',
    'db' => 'baza',
    );

# przykład:

$db = new Database($cfg);
var_dump($db->GetMany("SELECT * FROM tabelka", null, 0, 10));
?>

Posted in  | Tagi  | 9 comments

Ruby, Python vs Java,C++

Opublikowane przez Jarosław Zabiełło Mon, 14 Nov 2005 20:41:00 GMT

Od czasu do czasu na grupach dyskusyjnych mają miejsce przepychanki na temat wyższości jednych języków nad drugimi. Czasami takie dyskusje wywołują sporo emocji. Zmęczony ciągłymi ogólnikowymi sloganami o tym jak to w C++ lub Javie pisze się lepiej i szybciej (dobry dowcip) programy niż w językach dynamicznych takich jak Python czy Ruby, postanowiłem rzucić małe wyzwanie miłośnikom tych języków.

Zadanie polegało na napisaniu wyszukiwarki do polskiego tekstu Koranu (w sumie nie widziałem nic takiego, stąd pomysł). Aby nie było za banalnie, trzeba było napisać taki kod który by automatycznie wyssał przekład Koranu ze strony internetowej http://www.planetaislam.com/koran.html następnie przetworzył go i wstawił do bazy mysql oraz przełączył się w tryb wyszukiwania fraz.

Wyzwanie zostało przyjęte i… mijają tygodnie za tygodniami a moi dyskutanci nie są w stanie przedstawić żadnego działającego kodu w Javie ani w C++. Tak to teoria zderza się z praktyką. Oto naprędce stworzona wersja w Ruby:

require 'mysql'
require 'open-uri'

@przeklad = 'bielawski'
@conn = Mysql.new('localhost', 'login', 'hasło', 'koran', 3308)

def download(max_chapter=15)
  def clean_html(src) # nie znam biblioteki czyszczacej html wiec robie to regexem
    src.gsub(/&nbsp;/, ' ').gsub(/(<[^>]+>)/, '').gsub(/[ ]{2,}/, ' ').gsub(/&#/, '').gsub(/&quot;/, '"')
  end   
  @lines = []
  1.upto(max_chapter) do |sura|
    url = sprintf('http://www.planetaislam.com/koran/%s/%03d.htm', @przeklad, sura)
    src = clean_html(open(url).read)
    rows = src.scan(/(\d+?)[. ]([^\d]+)/) # wyluskuj wersety i numery rozdzialow
    rows.each do |row|
      @lines << sprintf('%s:%s %s', sura, row[0], row[1].gsub(/[\s]{2,}/, ' ').strip)
    end
    f = File.new("#{@przeklad}.txt", "w") # zapisuje sobie do pliku
    @lines.each { |line| f.write("#{line}\n") }                               
  end
end
def loaded_db
  @conn.list_tables.include?(@przeklad) # Sprawdzam czy juz istnieje tabela z danymi.
end
def load_db
  @conn.query("DROP TABLE IF EXISTS #{@przeklad}")
  @conn.query("CREATE TABLE #{@przeklad} (
    id int(10) unsigned NOT NULL auto_increment,
    sura varchar(255) NOT NULL,
    nr int(10) unsigned NOT NULL,
    verse text NOT NULL,
    PRIMARY KEY (id)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci")
  @conn.query("SET CHARACTER SET latin2")
  @lines.each do |line|
    sura, nr, verse = line.scan(/(\d+?):(\d+?) (.+)/)[0]
    verse.gsub!(/'/,"''") # uzywam topornego sql bo cos mi metoda prepare nie dziala, moze zla biblioteka?
    @conn.query("INSERT INTO #{@przeklad} (sura, nr, verse) VALUES(#{sura}, #{nr}, '#{verse}')")
  end
end  
def search_result(phrase)
  @conn.query("SET CHARACTER SET cp1250")
  sql = "SELECT * FROM " + @przeklad + " WHERE verse LIKE '%" + phrase + "%' "
  c = @conn.query(sql)
  while row = c.fetch_row
    puts sprintf("Sura %s,%s %s\n", row[1], row[2], row[3])
  end
end

if $0 == __FILE__
  if !loaded_db          
    download
    load_db
  end
  search_result('kobieta')
end

A oto ostateczna wersja w Pythonie:

#!python

"""
Wyszukiwarka do Koranu

Przykłady uzycia:
    python koran.py --txt zabijajcie
    python koran.py --sura=ix
    python koran.py --sura=9 --nr=4
    python koran.py --sura=IX --nr=4    

Wymagania:
    interpreter Pythona 2.4 + standardowe biblioteki
    pythonowska biblioteka MySQLdb
    serwer MySQL 4.1

Autor:
    Jarosław Zabiełło http://zabiello.com
"""

import HTMLParser, os, re, urllib2, sys
from optparse import OptionParser
import MySQLdb

class Koran(object):
    dbname ="koran"
    przeklad = 'bielawski'
    lines = []

    def __init__(self):
        self.conn = MySQLdb.connect(
            host='localhost',
            port=3308,
            user='login',
            passwd='hasło',
            db=self.dbname)

    def download(self, max_chapter=15):
        """Sciagam dane z internetu i je troszke oczyszczam z nadmiarowego kodu html"""
        def html_clean(src):
            x = HtmlStripper()
            x.feed(src)
            return src = x.get_fed_data()            
        self.lines = []
        for i in xrange(1,max_chapter):
            url = 'http://www.planetaislam.com/koran/%s/%03d.htm' % (self.przeklad, i)
            src =  html_clean(urllib2.urlopen(url).read()) # pobrany caly plik
            rows = re.findall(r'(\d+?)[. ]([^\d]+)', src) # wyluskuj wersety i numery rozdzialow            
            for row in rows:
                self.lines.append('%s:%s %s' % (i, row[0], re.sub(r'[\s]{2,}', ' ', row[1]).strip()))
        self.lines = [unicode(line, 'iso-8859-2').encode('utf-8') for line in self.lines]
        f = open(self.przeklad+'.txt', 'w')  # zapisuje sobie kopie na dysk
        for line in self.lines:
            f.write('%s\n' % line)
        f.close()

    def loaded_db(self):
        """Sprawdzam czy juz istnieje tabela z danymi."""
        c = self.conn.cursor()
        c.execute("SHOW TABLES")
        rows = c.fetchall()
        if self.przeklad in [row[0] for row in rows]:
            c.execute("SELECT COUNT(*) FROM %s" % self. przeklad)
            return c.fetchone()[0]
        return False

    def load_db(self):
        "Zakladam ze stworzono baze o nazwie self.dbname i laduje dane do tabeli self.przeklad"
        sqls = (
            "DROP TABLE IF EXISTS %s" % self.przeklad,
            '''CREATE TABLE %s (
                id int(10) unsigned NOT NULL auto_increment,
                sura varchar(255) NOT NULL,
                nr int(10) unsigned NOT NULL,
                verse text NOT NULL,
                PRIMARY KEY (id)
            ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci''' % self.przeklad)
        c = self.conn.cursor()
        for sql in sqls: # odtwarzam baze
            c.execute(sql)
        c.execute("SET CHARACTER SET UTF8")
        sql = "INSERT INTO "+self.przeklad+" (sura, nr, verse) VALUES (%s,%s,%s)"
        for line in self.lines:
            found = re.match(r'(\d+?):(\d+?) (.+)', line)
            if found:
                c.execute(sql, found.groups())
        c.close()

    def set_i18n(self, cursor, phrase=None):
        if sys.platform == 'win32': # zakladam ze bede wyswietlal wyniki w okienku konsoli, czyli kodowanie dosowe
            if phrase:
                phrase = unicode(phrase, 'cp1250').encode('cp852')
            cursor.execute("SET CHARACTER SET cp852")
        elif sys.platform == 'linux':
            cursor.execute("SET CHARACTER SET latin2")
        return phrase

    def search_result(self, phrase):
        """Wyszukuje wersetow wg prostej zasady: znadz wszystkie wersety w ktorych gdziekolwiek
        wystepuje fraza phrase. Dla wygody dodalem obsluge polskich znakow spod konsoli dosowej
        i linuksa."""
        c = self.conn.cursor()
        phrase = self.set_i18n(c, phrase)
        sql = "SELECT * FROM " + self.przeklad + " WHERE verse LIKE '%" + phrase + "%' "
        print sql
        c.execute(sql)
        rows = c.fetchall()
        c.close()
        print "Znaleziono %d wersetow:\n" % len(rows)
        for row in rows:
            print "Sura %s,%s %s\n" % (int_to_roman(int(row[1])), row[2], row[3])

    def show_verse(self, sura, nr=0, context=0):
        c = self.conn.cursor()
        self.set_i18n(c)
        if sura.isalpha():
            sura = roman_to_int(sura)
        if sura and nr: # wyswietl pojedyncza sure
            sql = "SELECT verse FROM " + self.przeklad + " WHERE sura=%s AND nr=%s"
            c.execute(sql, (sura, nr))
            verse = c.fetchone()[0]
            print "Sura %s,%s %s\n" % (int_to_roman(int(sura)), nr, verse)
        else: # wyswietl cala sure
            sql = "SELECT nr, verse FROM " + self.przeklad + " WHERE sura=%s ORDER BY nr"
            c.execute(sql, [sura])
            rows = c.fetchall()
            for row in rows:
                print "Sura %s,%s %s\n" % (int_to_roman(int(sura)), row[0], row[1])
        c.close()

class HtmlStripper(HTMLParser.HTMLParser):
    """src: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440481"""
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def get_fed_data(self):
        return ''.join(self.fed)

def int_to_roman(input):
    """src: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81611"""
    if type(input) != type(1):
        raise TypeError, "expected integer, got %s" % type(input)
    if not 0 < input < 4000:
        raise ValueError, "Argument must be between 1 and 3999"   
    ints = (1000, 900,  500, 400, 100,  90, 50,  40, 10,  9,   5,  4,   1)
    nums = ('M',  'CM', 'D', 'CD','C', 'XC','L','XL','X','IX','V','IV','I')
    result = ""
    for i in range(len(ints)):
        count = int(input / ints[i])
        result += nums[i] * count
        input -= ints[i] * count
    return result

def roman_to_int(input):
    """src: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81611"""
    if type(input) != type(""):
        raise TypeError, "expected string, got %s" % type(input)
    input = input.upper()
    nums = ['M', 'D', 'C', 'L', 'X', 'V', 'I']
    ints = [1000, 500, 100, 50,  10,  5,   1]
    places = []
    for c in input:
        if not c in nums:
            raise ValueError, "input is not a valid roman numeral: %s" % input
    for i in range(len(input)):
        c = input[i]
        value = ints[nums.index(c)]
        try:
            nextvalue = ints[nums.index(input[i +1])]
            if nextvalue > value:
                value *= -1
        except IndexError:
            pass
        places.append(value)
    sum = 0
    for n in places:
        sum += n
    return sum

if __name__ == '__main__':
    appl = Koran()
    if not appl.loaded_db():
        print 'Pobieram dane z internetu....'
        appl.download()
        print 'Wkladam dane do bazy...'
        appl.load_db()
    parser = OptionParser()
    parser.add_option('--txt', dest='txt', help='wyszukiwana fraza')
    parser.add_option('--sura', dest='sura', help='numer Sury (liczba dziesietna lub rzymska)')
    parser.add_option('--nr', dest='nr', help='numer wersetu dla Sury')
    (options, args) = parser.parse_args()
    if options.txt:
        appl.search_result(options.txt)
    elif options.sura:
        appl.show_verse(options.sura, options.nr)
    else:
        print "Wywolaj z parametrem --help"

W międzyczasie zdążyłem nawet wykorzystać swój kod Pythona aby dodać go jako moduł do Plone. :)

Posted in ,  | Tagi , ,  | 80 comments

Optymalizacja użycia railsów

Opublikowane przez Jarosław Zabiełło Sun, 13 Nov 2005 20:43:00 GMT

Optymalizacja użycia Railsów: http://weblog.textdrive.com/article/175/rails-optimizing-resource-usage

Posted in  | Tagi  | 5 comments

Wymiana stronki

Opublikowane przez Jarosław Zabiełło Sun, 13 Nov 2005 20:37:00 GMT

Moja stara strona domowa oparta na PHP powoli odchodzi do lamusa. Chciałem wymienić to na coś gotowego do blogów. Wybrałem Typo, wzorcową aplikację opartą na frameworku Ruby on Rails.

3 comments

Starsze wpisy: 1 ... 11 12 13