Тук ще напиша набързо решенията на проблемите, който възникнаха при първия ми по-сериозен сблъсък с web-framework-а Rails (предназначен за езика Ruby).
1. Инсталиране (тук ще карам малко по спомен)
# сдобивате се някак си със rubygems - това е пакетния мениджър на Руби (за линукс потребителите - потърсете за подходящ пакет за любимата ви дистрибуция)
gem update --system # ъпдейтвате rubygems най-вече
gem install rails --version 2.2.2 # инсталирате рейлс
gem install postgresql-pr # инсталирате адаптера за работа с postgres (ако разбира се искате да ползвате postgres - по дефоулт 2.2.2 идва със sqlite3)
gem install rspec-rails # инсталира rspec - най-новия писък на модата, тъй нареченото BDD - Behaviour Driven Development
2. Предварителни настройване на проекта
rails my_app # създава папка my_app със скелета на цял рейлс проект
# от сега нататък приемам че се намираме в папката my_app, създадена по-горе
haml --rails . # добавя haml към проекта (това е удобен темплейтен език, изглежда по-добре от дефоултния erb)
ruby script/plugin install git://github.com/technoweenie/restful-authentication.git # инсталирате си restful authentication
mv vendor/plugins/restful-authentication vendor/plugins/restful_authentication # !!много важно - променяте името на плъгина (махате му тирето) - без този ред не работи като хората
ruby script/generate authenticated user sessions --rspec # база на аутентикацията (т.е user-и и сесии)
четвъртък, 19 февруари 2009 г.
четвъртък, 1 януари 2009 г.
свободна музика?
Отдавна не бях блогвал, но стечението на обстоятелствата (което ще опиша след малко) беше предпоставка за това да прегледам блога на Яна и да видя ... линка към моя блог, което пък ми напомни че и аз имам 'таковъ животну' ... както и да е :)
Значи напоследък забелязах че apache-то ми се държи странно (apache е web сървър - демек нещото което като човека X напише в любимия си браузър "http://iskren.info" показва грозна зелена страница). И тъкмо ме бяха обхванали мрачни мисли свързание с форматране, преинсталиране, рестартиране (последното имаше донякъде положителен ефект) когато ми дойде гениална мисъл ... да му погледна log-а. Дам ... като се сетих (толкова късно) направо ми стана гадно, че се познавам.
Та - гледам аз лога на апачето и какво да видя - постоянни request-и от всички краища на планетата, хвърчат към моето apache-нце и то неуморимо ги удовлетворява. И понеже първото на което ми попадна погледа беше достъп на файл в една от директориите на Пешо веднага си казах - той се е разчел нещо. Но уви - след като му писах веднагически, отговори че не той е ровещият се в сървъра. След кратка мисловна пауза и по-подробно разглеждане на лога останових ... че някакви сайтчета индексират моя, за да може да пускат "безплатна музика" на хората, които ги посещават (например http://grooveshark.com).
Следващото нещо което направих, беше да потърся iskren.info в google. След самата страница и мой цитат в блога на Яна, изплуваха и мистериозните сайтове предлагащи безплатна музика, който просто сочеха към сървъра ми. След като се загледах по-подробно в единия от сайтовете, реших да прочета "Terms & conditions" - е да, хората повториха 101 пъти, че музиката не е на техния сървър и те не носят никаква отговорност за нея, нямат никаква връзка с хората, на чиито сървъри е музиката ... итн, итн.
От една страна ОК - имам музика, сложил съм я (вече) за свободно сваляне от http-то, за да мога по-лесно да пусна на някой приятел някоя песничка, която ме е накефила. Обаче това диво адресиране от всевъзможни сайтове, тази популяризация ... няма ли да почукат на вратата след някой друг ден 2-3 гардероба и да поискат нечии хард?
Майната му! Като съм решил да имам общодостъпна музика на компютъра - така ще бъде! Защо трябва само да се крием и да слагаме пароли на всичко? В крайна сметка това е един от плюсовете на това, че не живеем в Америка - страната на неограничените възможности ... на държавата спрямо гражданите й.
За много години на всички (ако някой въобще чете това), и да бъде свободата :)
Значи напоследък забелязах че apache-то ми се държи странно (apache е web сървър - демек нещото което като човека X напише в любимия си браузър "http://iskren.info" показва грозна зелена страница). И тъкмо ме бяха обхванали мрачни мисли свързание с форматране, преинсталиране, рестартиране (последното имаше донякъде положителен ефект) когато ми дойде гениална мисъл ... да му погледна log-а. Дам ... като се сетих (толкова късно) направо ми стана гадно, че се познавам.
Та - гледам аз лога на апачето и какво да видя - постоянни request-и от всички краища на планетата, хвърчат към моето apache-нце и то неуморимо ги удовлетворява. И понеже първото на което ми попадна погледа беше достъп на файл в една от директориите на Пешо веднага си казах - той се е разчел нещо. Но уви - след като му писах веднагически, отговори че не той е ровещият се в сървъра. След кратка мисловна пауза и по-подробно разглеждане на лога останових ... че някакви сайтчета индексират моя, за да може да пускат "безплатна музика" на хората, които ги посещават (например http://grooveshark.com).
Следващото нещо което направих, беше да потърся iskren.info в google. След самата страница и мой цитат в блога на Яна, изплуваха и мистериозните сайтове предлагащи безплатна музика, който просто сочеха към сървъра ми. След като се загледах по-подробно в единия от сайтовете, реших да прочета "Terms & conditions" - е да, хората повториха 101 пъти, че музиката не е на техния сървър и те не носят никаква отговорност за нея, нямат никаква връзка с хората, на чиито сървъри е музиката ... итн, итн.
От една страна ОК - имам музика, сложил съм я (вече) за свободно сваляне от http-то, за да мога по-лесно да пусна на някой приятел някоя песничка, която ме е накефила. Обаче това диво адресиране от всевъзможни сайтове, тази популяризация ... няма ли да почукат на вратата след някой друг ден 2-3 гардероба и да поискат нечии хард?
Майната му! Като съм решил да имам общодостъпна музика на компютъра - така ще бъде! Защо трябва само да се крием и да слагаме пароли на всичко? В крайна сметка това е един от плюсовете на това, че не живеем в Америка - страната на неограничените възможности ... на държавата спрямо гражданите й.
За много години на всички (ако някой въобще чете това), и да бъде свободата :)
петък, 23 май 2008 г.
<T>emplate magic
Просто не мога да се сдържа да не се похваля какво извращение успях да подкарам на C++ наскоро. Става дума за тип, в който може да се слага всеки друг тип (по един във всеки момент) и да се взима текущия тип (като се каже какъв е). Т.е исках да върви подобен код:
Та значи горното нещо в началото ми се струваше сън, докато не осъзнах, че е напълно реално - нужни са само 2 помощни класа (т.е общо 3) и горният код РАБОТИ.
Накратко:
1. Абстрактен базов клас, поддържащ методи set и get, приемащи/връщащи void *
2. темплейтен наследник на горния клас, в който се пази указател към T, но самите функции разбира се връщат пак void * (защото са в йерархия)
3. клас wrapper на горния, който не е темплейтен, но съдържа темплейтнати функции (т.е класа не е темплейт, но някой негови функции са), който държи един указател към базата и когато поискат нещо от него той прави dynamic_cast до наследник от искания тип, след което каства резултата към нещо човечко (т.е void * --> Т * --> Т). Хубавото е, че примерно set функцията сама разбира типа на шаблона (дедуцира го от аргумента) - затова няма смисъл да го пишем изрично (т.е set <int> (4). За get функцията обаче е задължителен (е няма пълно щастие :) ).
Хубавото тука е, че се извършва type checking от компилатора (при dynamic_cast), както и освобождаването на заделената памет от виртуалния деструктор на 2рия клас - т.е общо взето прехвърляме задълженията си към компилатора (както и според мен трябва да се прави).
п.с.: За да е малко по-полезно това чудо добавих и функция, която преобразува всеки тип до стринг (за да мога да печатам по лесно наред). Та наложи се да сложа и темплейт-специализация на тази вункция за типа int (т.е функцията to_str за едни типове да работи по един начин, за int да работи по друг). Тази функция, се третира като нормална, и за това трябва да стой в cpp файл, който се линква отделно (т.е не в h/hpp файла със шаблона, защото ако се инклудне от поне 2 места става мазало). По принцип темплейтите трябва да са написани в един h файл, защото компилатора не позволява да ги разделяме (extern template не е имплементирано почти никъде), но точно специализациите може (и трябва) да се пишат в отделен файл - иначе казва redefinition of ...
generic x;
x.set (5);
x.get <int> ();//--> 5
x.set (std::string ("alabala"))
x.get <std::string> ();//--> alabala
//type checking
x.is <int> ();//false
Та значи горното нещо в началото ми се струваше сън, докато не осъзнах, че е напълно реално - нужни са само 2 помощни класа (т.е общо 3) и горният код РАБОТИ.
Накратко:
1. Абстрактен базов клас, поддържащ методи set и get, приемащи/връщащи void *
2. темплейтен наследник на горния клас, в който се пази указател към T, но самите функции разбира се връщат пак void * (защото са в йерархия)
3. клас wrapper на горния, който не е темплейтен, но съдържа темплейтнати функции (т.е класа не е темплейт, но някой негови функции са), който държи един указател към базата и когато поискат нещо от него той прави dynamic_cast до наследник от искания тип, след което каства резултата към нещо човечко (т.е void * --> Т * --> Т). Хубавото е, че примерно set функцията сама разбира типа на шаблона (дедуцира го от аргумента) - затова няма смисъл да го пишем изрично (т.е set <int> (4). За get функцията обаче е задължителен (е няма пълно щастие :) ).
Хубавото тука е, че се извършва type checking от компилатора (при dynamic_cast), както и освобождаването на заделената памет от виртуалния деструктор на 2рия клас - т.е общо взето прехвърляме задълженията си към компилатора (както и според мен трябва да се прави).
п.с.: За да е малко по-полезно това чудо добавих и функция, която преобразува всеки тип до стринг (за да мога да печатам по лесно наред). Та наложи се да сложа и темплейт-специализация на тази вункция за типа int (т.е функцията to_str за едни типове да работи по един начин, за int да работи по друг). Тази функция, се третира като нормална, и за това трябва да стой в cpp файл, който се линква отделно (т.е не в h/hpp файла със шаблона, защото ако се инклудне от поне 2 места става мазало). По принцип темплейтите трябва да са написани в един h файл, защото компилатора не позволява да ги разделяме (extern template не е имплементирано почти никъде), но точно специализациите може (и трябва) да се пишат в отделен файл - иначе казва redefinition of ...
#include <cstdio>
#include <string>
class base {
public:
virtual void *get () = 0;
virtual void set (const void *) = 0;
virtual ~base () {}
};
template <typename T>
class derived : public base {
T *_data;
public:
derived () : _data (NULL) {}
virtual void *get () {
return static_cast <void *> (_data);
}
virtual void set (const void *data) {
delete _data;
_data = new T (*static_cast <const T *> (data));//copy constructor
}
virtual ~derived () {
delete _data;
}
};
class wrapper {
base *_p;
public:
wrapper () : _p (NULL) {}
template <typename T> T get () {
return *static_cast <T *> (dynamic_cast <derived <T> *> (_p)->get ());
}
template <typename T> bool is () {
return dynamic_cast <derived <T> *> (_p) != NULL;
}
template <typename T> void set (const T &nv) {
delete _p;
_p = new derived <T>;
_p->set (&nv);
}
};
int main () {
wrapper x;
x.set (5);
printf ("%d\n", x.get <int> ());
x.set (std::string ("alaabala"));
printf ("%s\n", x.get <std::string> ().c_str ());
printf ("%d %d\n", (int)(x.is <int> ()), (int)(x.is <std::string> ()));
return 0;
}
сряда, 30 април 2008 г.
pointer-to-member-function C++
(който не разбира заглавието - става дума за указатели към член-функции в класове на C++ - който и това не разбира да го прескочи :))
Ако искате да напишете код, който да работи с даден обект и да вика негова функция, обаче самата функция да може да се променя (т.е да напишете по-обща функция един вид) тогава е полезно да може да предавате така наречения указател-към-член-функция. В следните няколко парченца код ще опитам да покажа как точно става това граматически - на книжовен C++, защото лично аз имах малко проблеми докато докарам синтаксиса преди няколко дена.
Основният проблем е, че типът на една функция, която е в клас не е просто връщана-стойност (*) (аргуенти), защото тези функции получават един неявен указател this, който сочи към данните на обекта. Освен това този указател е от различен тип за всеки клас (т.е не може просто да кажем че това е member функция и да стане) - трябва като цитираме съответна функция да кажем и от кой клас е:
Сега вече типа става:
забележете, че ако функцията е const трябва да го кажем изрично - защото от това зависи типа на указателя this, който както казах неявно се предава.
Ако искаме да подадем mem_fun на някоя фунция (за да може тя да вика точно тази функция за даден обект - обекта отделно трябва да го дадем разбира се) трябва да я приемем по следния начин:
сега остава да покажа как се предава :)
Можете да подавате и указатели към оператори - просто трябва да ги изпишете (style="font-family:courier new;">&rational::operator +) - държат се като обикновенни функции (но се викат по интересно ;)).
При статичните функции е по-лесно - защото при тях няма този скрит указател this който казва на кой клас е. Т.е техния тип е като на обикновенна функция, а за да ги подадете пишете име-на-клас::име-на-функция както при член функциите
Ето една страничка с (може би) малко по-подробна информация по въпроса:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
Ако искате да напишете код, който да работи с даден обект и да вика негова функция, обаче самата функция да може да се променя (т.е да напишете по-обща функция един вид) тогава е полезно да може да предавате така наречения указател-към-член-функция. В следните няколко парченца код ще опитам да покажа как точно става това граматически - на книжовен C++, защото лично аз имах малко проблеми докато докарам синтаксиса преди няколко дена.
Основният проблем е, че типът на една функция, която е в клас не е просто връщана-стойност (*) (аргуенти), защото тези функции получават един неявен указател this, който сочи към данните на обекта. Освен това този указател е от различен тип за всеки клас (т.е не може просто да кажем че това е member функция и да стане) - трябва като цитираме съответна функция да кажем и от кой клас е:
името-на-класа::името-на-функцията.
Сега вече типа става:
връщана-стойност (име-на-клас::*име-на-функция) (аргументи) [const]
забележете, че ако функцията е const трябва да го кажем изрично - защото от това зависи типа на указателя this, който както казах неявно се предава.
class cls {
int mem_fun (const char *) const;
static void static_mem_fun (double, char);
};
Ако искаме да подадем mem_fun на някоя фунция (за да може тя да вика точно тази функция за даден обект - обекта отделно трябва да го дадем разбира се) трябва да я приемем по следния начин:
void mem_fun_user (const cls &c, int (cls::*f) (const char *) const) {
/*по този начин я викаме - обърнете внимание на скобите и звездата*/
/*ако c беше указтел към клас тогава викаме със '->*' */
int p = (c.*f) ("haha");
}
сега остава да покажа как се предава :)
void foo () {
cls c;
/*не слагайте допълнителни скоби, или аперсанта другаде - НЕ РАБОТИ - точно както съм го дал така :)*/
mem_fun_user (c, &cls::mem_fun);
}
Можете да подавате и указатели към оператори - просто трябва да ги изпишете (style="font-family:courier new;">&rational::operator +) - държат се като обикновенни функции (но се викат по интересно ;)).
При статичните функции е по-лесно - защото при тях няма този скрит указател this който казва на кой клас е. Т.е техния тип е като на обикновенна функция, а за да ги подадете пишете име-на-клас::име-на-функция както при член функциите
Ето една страничка с (може би) малко по-подробна информация по въпроса:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
понеделник, 28 април 2008 г.
Сефтето на блога
Ето го и първия пост :) Дано не зарежа и това начинание, както много други.
Като ми дойде музата пак ;)
Като ми дойде музата пак ;)
Абонамент за:
Публикации (Atom)