Archive for the ‘Uncategorized’ Category

KTutorial 0.5.1 released!

2012/12/07

This is the first release licensed under the GPLv2+, and the first one containing translations provided by the KDE localization teams (thank you for your work! 🙂 ).

The release notes contain more information about the changes from 0.5 release.

Check the download page for information about downloading and building KTutorial.

Preventing graphical automated tests from interrupting you

2012/12/06

You may have found that running graphical automated tests (like unit tests for view subdirectories in ktutorial-library and ktutorial-editor) can be very annoying. Ideally, you would launch the tests and then go on working on something else while they run. The problem is that, while you are trying to work on something else, the windows created by the unit tests are constantly appearing and disappearing.

If you don’t want to use the time spent running the tests giving a rest to your eyes far away from your monitor, and you want to use your computer while the tests are running, there is an easy solution: run the tests in a different display than the one you are using.

To do this, you must start that other display before running the tests. Xnest can be used to start another display inside a window in your current display. You should also start a window manager for that display to ensure that the tests will run in a “real” environment. Both things can be done in a single command (and as a user, there is no need to become root for this):
(Xnest :1 2>/dev/null & ) && (kwin -display :1 2>/dev/null & )

That command assumes that you are using just one display, and that you want to start a second display :1. If you are already using several displays, adjust the number accordingly. The redirection of error output (2>/dev/null) is not mandatory; it is just used to prevent the console to be flooded with error messages.

Once the second display is started, you can execute the tests on it with:
DISPLAY=:1 ctest

Of course, you may also export the DISPLAY variable, or run a specific test executable, instead of using ctest.

Finally, once you no longer need the auxiliar display, just close its window. That will end the kwin and Xnest processes.

Move to SourceForge.net

2010/01/31

Just a little note. KTutorial has moved from La Forja de RedIRIS to SourceForge.net.

Thanks to RedIRIS for hosting the project until now.

This is the new KTutorial project page.

Internationalization in Kross scripts

2010/01/04

As I said in the previous post, internationalization in Kross scripts is a subject that deserves its own post. Again, this is based on my own experiences, and I’m by no means an expert in script languages or Kross, so don’t treat this information as a universal truth 😉

Also note that internationalization (from now on, i18n) has a very broad scope. Here we’ll talk only about string i18n (allowing the messages to be translated to other languages). If you are interested in other i18n areas you’ll have to keep looking 😉

So let’s see if I can give some useful information after all 😉

Translation systems

First of all, what systems do we have to translate strings? The de facto standard in free software world is GNU gettext. It provides tools to extract the messages to be translated from the source code, a file format to store the translations, a library to translate the strings at runtime… Most popular programming languages support gettext, being it through its standard API (like in Python) or from 3rd party projects (like in Ruby).

But it is not the only system available. For example, Qt has its own translation system as part of its i18n support. Ruby also has an i18n module that contain a translation system (although it can use gettext files switching the backend).

What does KDE use? Although KDE uses a lot of Qt infrastructure, in the case of string translation it uses gettext instead. Well, an enhanced version of gettext with some very interesting features. For example, the semantic markup helps translators to better understand how a string should be translated, but it also benefits the users as it provides a richer and more consistent appearance for messages. Another interesting feature is Transcript, which aids in the correct translation of case based languages (among others).

Moreover, KDE libraries take care of gettext initialization, catalogs and so on, so you just have to mark the strings to be translated without worrying about setting everything up.

What translation systems can be used from Kross scripts? Thanks to the Translation Module, the KDE translation system can be used in Kross scripts, no matter what programming language the script is written in. But, as Kross only acts as a bridge between the script interpreter and C++ code, the translation systems available for the programming language of the script can be used from Kross. So the i18n module in Ruby or gettext in Python could be used. And if Qt bindings are available for the language, even the Qt translation system could be used!

Anyway, in my humble opinion, the best choice is to use Kross Translation Module (if we know for sure that the script will be executed from Kross). The Translation Module is available no matter which programming language was used to write the script, and it is provided by Kross, so it doesn’t depend on external libraries. Moreover, as it just forwards the function calls to the KDE translation system, all the fancy features given by it are available for free in the scripts. And, finally, the messages can be extracted from the scripts like they are extracted from C++ sources, storing them in the same file (so translators don’t have to care where the strings came from) and accessing them at runtime without any special configuration.

Message extraction

Translators need to know what strings they have to translate, and in order to accomplish this the translatable strings must be extracted from the source code. To do this, an extraction utility analyzes the source code looking for those strings. The programmer must mark the translatable strings so the extraction utility knows which strings have to be extracted and which not.

To mark the string usually just means to wrap the string with a function/method call that will also translate that string to the appropriate language when the application is running.

To extract the strings, gettext provides xgettext, which understands source code in a lot of programming languages, including Python. However, it doesn’t support yet Javascript nor Ruby explicitly. When a programming language is unknown, xgettext tries (as far as I know) with C like strings and functions. So, although neither Javascript nor Ruby are explicitly supported, double quote C like strings can be extracted apparently without problems. But it doesn’t support single quote strings, custom delimited strings or function calls without parenthesis.

See the following Ruby code as an example (note that mark is just an example function name):

mark("Hello world double quotes") # Extracted by xgettext
object.mark("Hello world method") # Extracted by xgettext

mark('Hello world single quotes') # Not extracted by xgettext
mark(%/Hello world custom quotes/) # Not extracted by xgettext
mark "Hello world without parenthesis" # Not extracted by xgettext

xgettext has also a very useful feature: it let’s you specify how the strings were marked in the source code. So it supports the default gettext function names, but can also extract custom functions. For example, you can say “wherever you find a function called i18nc with 2 arguments, treat the first item as string context and the second argument as the string to be translated”. This is used by KDE, as KDE i18n functions have a different name than gettext canonical functions.

Note that the file created by xgettext when the messages are extracted uses a format understood by gettext (although other translation systems may be able to read those files). Anyway, it is not a problem using Kross Translation Module, because as it was already said, KDE uses (an enhanced) gettext as its translation system.

In fact, the extraction of strings in KDE is done with xgettext, and it is automatic if the application is part of KDE’s subversion repository, although it can also be simplified a lot with an script for 3rd party applications, as shown in i18n Build System. However, the Messages.sh for subversion and 3rd party applications given in that article only support C/C++ files. They must be adjusted to also look for messages in Kross scripts. Take a look to the changes in KTutorial commit #65 as an example.

The gettext project for Ruby provides rgettext, which is a xgettext tailored for Ruby source code. However, it just works for Ruby source code, and as far as I can tell it doesn’t allow you to specify how the strings are marked (maybe with -r argument you can extend the behavior of rgettext, but I haven’t tested it), so you can just use the canonical gettext function names. That is, it can’t extract messages from a Ruby script that uses Kross Translation Module (as the function names are the same used in KDE libraries).

So, in the end, in order to be able to extract messages from Kross scripts using the translation module you just have to include the scripts in the files to be looked for strings, and keep a C/C++ style in Javascript and Ruby strings and translation module calls.

Runtime translation, catalog location…

Another section that starts with bold letters… It means that there is a lot to say about this subject, right? Wrong. That’s one of the nicest things about using the translation module: once the messages from the scripts are extracted along with the messages from C++ code you are done. They will be treated like the C++ internationalized strings when translated, merged, installed and used at runtime. Do the string translation already work in C++? So it will for Kross scripts 🙂

Well, I lied. There is one case where this is not so easy: when the scripts aren’t part of the application. If an script is provided as an add-on for the application by 3rd parties, the messages from that script weren’t probably extracted with the rest of messages of the application. So the script must provide also its own translation files like additional data (for example, packaging the script and the translations in a tar.gz file or something like that). The translation files would need to be loaded at runtime, which would require some infrastructure.

Anyway, I haven’t explored this scenario as it seems very strange, at least for tutorials. If someone makes a nice scripted tutorial for an application that tutorial is likely going to end as part of the application itself. It would be very strange if the tutorial was kept as a separate entity, and even more strange if it got its own translations (getting localized seems like a sign that it is good enough to become part of the application 😉 ).

Some notes about Kross

2009/09/27

While experimenting with Kross in order to implement scripted tutorials I collected a series of notes about what can and what can not be done with Kross. Although they are based on my own experiences (testing what happened if I changed things, reading Kross code and debugging it), I consider them to be pretty accurate (at the time of this writing, in the future it may change). But if you use this information for your own code and your computer explodes, don’t blame me 😛

Also take into account that I have tested this with Javascript and Python backends. I have no idea about how mature are other backends.

And now, let’s see those notes:

  • Before Qt 4.5, only slots could be invoked from scripts. From Qt 4.5 and on, slots and methods marked with Q_INVOKABLE macro (which was introduced in Qt 4.5) can be invoked. Kross probably uses Qt Meta-Object System internally to make its magic.
  • Qt does not support Q_OBJECT classes that use templates. So, as you could expect, you can’t use templated classes or templated methods from scripts. Maybe playing with inheritance and method overriding it can be done… but I haven’t tested it.
  • It seems that in C++ classes you can’t have two slots (or invokable methods) with the same name and the same number of arguments (of different types). That is, it seems that Kross doesn’t call the appropriate slot based on the data types passed as arguments, but the first defined slot is always called. However, it only happens then the type of arguments is different, but their number is the same. If the name of the slots is the same but the number of arguments is different, Kross calls the slot with the matching number of arguments. So it supports a partial overloading of slots and invokable methods in C++ classes. Yes, even calling them from Python!
  • In Qt 4.5 the method newInstance was added to QMetaObject, which as you can expect creates a new instance of the QObject subclass associated to the QMetaObject (if the constructor to use is marked as Q_INVOKABLE). However, Kross doesn’t seem to be able (at least yet) to create new objects using invokable constructors. Something similar can be got if, in the C++ code, a method is implemented that given the name of a class returns an object of it. For this, the class names have to be previously associated with their QMetaObject, as Qt doesn’t seem to have a way to get a QMetaObject for the given class name. However, like invokeMethod, newInstance uses Q_ARG for its arguments, and being a macro it receives its values hardcoded, so I don’t see a way to pass parameters from scripts. Nevertheless, a constructor without arguments can be made, finishing the proper object initialization using set methods, or an init method, or something like that. It is not the best solution, but it is good enough. An example of all this can be seen in KTutorial commit #50, where (among other things) creating WaitFors from scripts was added to ScriptModule.
  • Apart from simple types and objects from QObject and child classes there are other data types that can be used in scripts: those supported by QMetaType. These data types are normal classes, not inheriting from QObject. In fact, it seems that data types supported by QMetaType aren’t designed to be classes inheriting from QObject, as classes inheriting from QObject can’t implement a copy constructor, while QMetaTypes need a copy constructor to be registered using qRegisterMetaType. Not being QObjects (thus lacking properties or slots), how they can be used from a script depends on the backend being used. For example, in Javascript backend “new QColor(255, 255, 255)” can be done, and also calling methods like red(), while in Python backend the QColor are just plain strings like “#ffffff”. A good example of what can be done and what can’t be done with each language can be seen looking in the unit tests of each Kross backend.
  • When passing lists and dictionaries to C++ methods, the arguments have to be declared as QList and QMap (QHash doesn’t seem to be supported) storing QVariant (QVariantList and QVariantMap). If, for example, QMap<QString, int> is used, the method call is done successfully, and in the C++ method even the number of values stored in the map can be got. But when the values are tried to be got, it crashes, even if the type of the data matches those declared in the template. May it be a bug?
  • The pointer to simple types (like int*) fail when used as C++ method arguments. Instead of passing a pointer to the integer, the pointer itself contains the value of the integer. It seems that only pointers to QObject (and derived classes) are implemented.
  • Naturally, SIGNAL and SLOT macros don’t work in Kross scripts (as they are a C++ preprocessor matter). So Kross provides a special connect function (or method, depending on the backend) which just uses the names of the signals and slots, and it is not necessary to wrap them with the macros. However, what does it happen when you need to use the macros in other places that are not the typical connect (for example, because you do a connect internally in a method using the name of the signal or slot passed to it)? Looking through Qt code I saw that those macros just add “1” in the case of SLOT and “2” in the case of SIGNAL to the front of the string. So to solve this, just add internally in the method to which the names of signals or slots are passed the appropriate number at the front of the signature and you are done. Take a look to KTutorial commit #55 as an example. Also take into account that if the name of the signal or slot to connect to is passed from the script to a C++ method, the method can’t be declared as receiving a const char* argument, but a QString.
  • Objects from classes created in scripts doesn’t seem to be compatible in any way with C++ code. I hoped that the interpreter made some kind of magic and “translated” them to QObject inherited classes, allowing them to be used in C++ methods receiving QObjects, but it’s not the case. As QObject class is neither available in scripts, classes can’t be made to inherit from it. However, this can be workarounded to some extent playing with signals. It can be done with a base class that emits signals with the object itself as argument in those methods that need to be overriden in child classes. The signals are connected to a function wrote in the script, and that function does the things that would have been done in the overriden method. See, for example, the test method stepWithCustomSetup in ScriptingTest and the ScriptedTutorial class.
  • Both modules and QObjects added to Kross actions (using Kross::Manager::self().addObject() the objects can be added to all the Kross actions) can be used to feed the scripts with C++ objects. In the scripts, modules will be loaded using Kross.module(“moduleName”), whereas QObjects can be used directly with the name they were gave (in the examples of the tutorials the objects are imported when Python is used, but at least based on the tests I made it isn’t necessary).  Personally, I find adding the QObjects to use way easier than using modules (at least, with KTutorial current design).
  • In the case of Python, the methods added by Kross (and which naturally can be called) can be seen in kdebindings/python/krosspython/pythonextension.cpp, in PythonExtension constructor. Those methods are, among others, className() or slotNames().
  • Kross provides a translation module that makes possible internationalize scripts and localize them using .po files like the rest of KDE. The module is Kross::TranslationModule and offers the typical functions i18n, i18nc, etcetera. However, I still have to check how string extraction works in this case, and how to localize a script added a posteriori, for example, downloaded via “Get Hot New Stuff!”. All this suggests that this matter will be worth its own post, and here it is: Internationalization in Kross scripts.
  • In the classes of the C++ objects used in scripts, the arguments of the signals and the return values of the slots that are not declared as pure QObject* but as QObject subclasses don’t work. On the other hand, the arguments of the slots can be QObject subclasses without any problem.
  • WrapperInterface class makes possible to use in scripts objects of classes that aren’t QObject*, nor QWidget*, nor any of the data types supported by QVariant. Unfortunately, although WrapperInterface is something at a generic level in Kross, it isn’t assured that it will work, as it depends on the backend (and thus, the language) used. The Javascript backend doesn’t seem to support this system, although the Python one does.
  • If we know that the scripts will only be written in languages which backend support WrapperInterface, it can be done the arguments of the signals and the return value of the slots of the C++ classes not to need to be declared as QObject*, but being able to be declared as the concrete subclass they belong to. For this, a handler for each class should be added, as shown below:
    QVariant SomeQObjectSubclassHandler(void* ptr) {
    QVariant r;
    r.setValue( static_cast(ptr) );
    return r;
    }
    void Scripting::initialization() {
    ...
    Kross::Manager::self().registerMetaTypeHandler("SomeQObjectSubclass*", SomeQObjectSubclassHandler);
    ...
    }
  • At first, I happily believed that the functions defined in scripts would be magically translated to slots of some object and that in C++ code a signal could be connected to a function in the script using that object. That, unfortunately, doesn’t happen (take into account that signals can be connected to functions, but in the script, not in C++ code as I needed). However, as script functions can be called from C++ code, it can be workarounded to some extent calling the corresponding function when a signal is emitted. An example can be seen in KTutorial commit #53 (although what I needed was under a pretty controlled situation, where signals included the emitter as their only argument).

Qt Meta-Object System and namespaces

2009/04/26

In my recent work in KTutorial (implementing scripted tutorials using Kross) I stumbled upon some problems with Qt Meta-Object system and namespaces that I think are worth mentioning.

Note that these comments apply to Qt 4.5.1. In newer versions the described behaviour may be different (and, in the case of the bug, hopefully it will be already fixed it is fixed in Qt 4.5.3.).

The first is more something to take into account than a problem. When a signal or slot is connected (using QObject::connect directly, or indirectly, for example, through QSignalSpy) the types of the arguments should be qualified using the same namespace used in the signal or slot declaration. You may declare it with the class name alone, without namespace, but only if you always use connect with the class name alone. That is, you always use the namespace, or you never use the namespace, but you can’t mix it.

The second, a strange behaviour if you don’t know what’s going on, involves namespaces in signal signatures, QSignalSpy and QVariant. A perfect mix. QSignalSpy is a useful class from QtTest module that can be used to record the emissions for a signal of an object. The arguments are stored as QVariant objects, that act as general containers for data types.

By default, QVariant supports most of Qt data types, but it can also store other types once they are registered. After using Q_DECLARE_METATYPE macro, a type can be stored in a QVariant (provided it has a public default constructor, public copy constructor and public destructor, which holds true for pointers to any type). Without it, the code won’t even compile.

However, when the type is used in the argument of a signal spied by a QSignalSpy, the type must be also registered using qRegisterMetaType. If not done, it complaints in debug output at runtime with “Don’t know how to handle ‘scripting::ScriptedTutorial*’, use qRegisterMetaType to register it.”.

The strange behaviour comes into play when namespaces are added to the party. If a signal has an argument that is a type (or a pointer to a type) in a namespace, as said above you can declare the argument with the class name alone. If the type is registered with Q_DECLARE_METATYPE and qRegisterMetaType (with the class name alone, without namespace), QSignalSpy will record the emitted signals, and when the QVariant that stored the argument is queried for the userType(), it will even return the same id as qRegisterMetaType returned when the argument type was registered. Apparently, it works.

However, there is no way to get the value of the argument. When a qvariant_cast is used on the QVariant that stores the argument, a default constructed value is returned. That doesn’t mean that the argument can’t be sent in a signal. If it was connected to a slot, it would have received the true argument value. But qvariant_cast doesn’t know how to manage the argument type.

Why? Because, for qvariant_cast, the class name, and the class name qualified with the namespace are different types. When the type is declared using Q_DECLARE_METATYPE, internally the full qualified name is used. If the name registered in qRegisterMetaType doesn’t includes the namespace, it won’t be recognized by qvariant_cast. So the full qualified name must be used in qRegisterMetaType. And if this is done, the full qualified name must be used also in QSignalSpy, and therefore in the declaration of the signal. So, to sum up: use the full qualified name of classes in signals and slots, you’ll live longer and happier 😛

See testSetup() method for an example of all this in KTutorial commit #48.

The last is a true problem, as it is an already reported bug (246221 – QMetaObject::newInstance() returns 0 for class in namespace (as it is an old bug, it seems to be no longer online)). The QMetaObject::newInstance method, introduced in Qt 4.5, doesn’t work when the class is in a namespace. The problem seems to be that when the constructor signature is prepared in newInstance code it includes the namespace. However, indexOfConstructor method doesn’t use the namespace, so when the constructor is looked for it isn’t found and no new instance is created. The bug is fixed in Qt 4.5.3.

Note to myself

2009/03/31

RPATH is great. But remember, when the library is installed in a path included in LD_LIBRARY_PATH, the installed library takes priority over the one pointed by RPATH.

Next time that QTest executables run directly or through Valgrind don’t change their behavior after modifying the library code, but when executed through shell files they do, that’s what is going on.

Yes, pretty obvious. But I’m sure that it is not the first time that you get stuck for an hour in something like that 😉 (and that then, after realizing what’s happening, you feel like a moron 😛 ).

Unit testing a KDE 4 library

2009/03/18

Here it is, my first English post!

I have still some things to finish (unrelated to KTutorial) before I can get a steady development pace, but until I finish them I’m going to make some sporadic work, mostly fixing problems (not necessarily bugs) to have a better base. For example, improving the unit tests.

I’m an advocate of testing before coding, but I can’t understand how or why in this project I had only 1 class and 4 methods tested. That had to change! So I entered in a test frenzy state and covered most of the code (KDevelop4 coverage plugin reports a healthy 91% coverage) with tests, which also helped to unveil some lurking bugs.

However, I’m not going to talk about the tests themselves, but about the infrastructure for them.

Executing tests without installing the library

When checking the first and (then) only test case I found that it passed when run using the shell wrapper, but not when run calling the executable directly.

Shell wrapper? What are you taking about? Ok, ok, let me explain. When you develop a library, you’re likely developing a dynamic library. That is, the applications using it will link to it when executed, not when compiled, and the library will remain as a separate file in the system.

In GNU/Linux the linker usually looks for the libraries in system directories. So if your test executable is linked against your dynamic library, the linker won’t find it until you install it. Apart from using system wide configuration, you can tell the linker other paths to look for the libraries with LD_LIBRARY_PATH environment variable.

And here is where the shell wrapper appears. The KDE 4 macros for CMake add, for each executable, a script which sets the needed paths in LD_LIBRARY_PATH for the executable to run and then calls it. This way, you can run your executable linked with dynamic libraries that are in the build directory but not installed yet.

But I needed the test executable to work even without the shell wrapper so I can run all the tests through CTest (more on this later). Unlike dynamic libraries, static libraries are linked at compiling time and added to the executable, so they aren’t needed separately.

So I thought “well, let’s create a ktutorial-static library to be used only by test executables and not even to be installed”. However, I wasn’t satisfied with that because the size of each test executable is much larger, specially in full debug mode, as each of them now contain the library. And I also felt that it was just a dirty workaround and there had to be a better solution.

And yes, there was. Reading the KDE 4 Macros documentation I found that KDE4_ADD_UNIT_TEST “adds a unit test […] (that) will be built with RPATH pointing to the build dir”. Mmm, what was that RPATH thing? CMake wiki gave me the answer: it was just what I was looking for. It’s like hardcoding LD_LIBRARY_PATH in the executable.

But, if the macro sets it, why didn’t it work? After some diving in KDE 4 Macros I concluded that it was a bug and opened RPATH isn’t set for tests added with KDE4_ADD_UNIT_TEST report. The bug is now fixed, so all the things explained here are superfluous, as now KDE4_ADD_UNIT_TEST works out of the box with dynamic libraries. Yes, you have wasted your time reading all this, sorry 😛

Running the tests

But, why do I need to execute the tests not using the shell wrapper? In KDE 4, the preferred unit testing library is QtTestLib. In QtTestLib each test case is an executable on its own, unlike other libraries where you can execute a test suite that groups several test cases. So you need a way to run all the tests without needing to run each test executable alone.

CMake provides its own test system, CTest. It has several fancy features, like sending the results of the tests to testing dashboards. But right now I just want to execute all the tests and see whether they pass or not. Fortunately, with CMake and CTest that’s a piece of cake.

CTest uses a CTestTestfile.cmake (or DartTestfile.txt, for legacy purposes) where it is specified the tests for its directory and subdirectories to look for other CTestTestfile.cmake. A CTestTestfile.cmake is created and filled by CMake in each build directory if ENABLE_TESTING command was run, which it is when including KDE4Defaults. CMake macro ADD_TEST adds a new test in the CTestTestfile.cmake of its directory. This macro is called from KDE4_ADD_UNIT_TEST, so using it effectively prepares CTest to run all the tests, even those in subdirectories of the base test directory. However, the tests are executed directly, not through their shell wrapper.

Well, I thought that. But… in fact, the generated CTestTestfile.cmake do use the shell wrapper. Since January 2008… But I was sooo smart to forget to update my KDE environment since then. Don’t ask… (Note, however, that this was written some months ago, although I didn’t publish it until now 😉 )

So now CTest works out of the box with KDE 4 Macros. We only have to build the tests (calling CMake with KDE4_BUILD_TESTS=ON variable they will be built with the rest of the project) and run CTest in our build/test directory. It will execute all the tests in that directory and, recursively, in all the needed subdirectories. If we need a more detailed output than the default summary, run ctest with -V or even -VV parameters to see the full test output.

Running QTest test from KDevelop4

A very interesting new feature of KDevelop4 is the support for unit test frameworks (although, as far as I know, only QTest works at this moment). With QTest plugin, you can enable and disable QTest tests to execute and see their results.

With some build systems, you must configure the plugin specifying the executables to be taken into account. However, if your project uses CMake, they are automatically discovered using CTestTestfile.cmake files (there is no problem even if they specify non-QTest tests, as these would be ignored).

There is only a little requeriment: there must be a CTestTestfile.cmake file in the root build directory. So just by using ENABLE_TESTING command in the root CMakeLists.txt file the CTestTestfile.cmake file is created and filled to recursively search in its subdirectories.

The only drawback with this approach is that CTestTestfile.cmake files will be created even in build directories where they aren’t needed (for example, src). However, although it is not the best solution, it is good enough 😉

Macro for adding several tests at once in CMakeLists.txt

In order to add a test, you need two or three CMake macros: KDE4_ADD_UNIT_TEST, TARGET_LINK_LIBRARIES and, optionally, SET (to set a variable with the list of files of the tests). As unit tests usually need just one file, you can avoid creating a variable and set the file in the KDE4_ADD_UNIT_TEST macro without losing legibility.

Anyway, the two calls are almost identical for every test, just changing the name of the test. It will be better to tell CMake just the name of the tests, instead of copy-pasting the calls for each test.

Of course, this can be easily done. As I have no idea about CMake programming, I took a look at KDECORE_UNIT_TESTS macro in CMakeLists.txt for kdecore and tweaked it for my own needs, as seen in KTutorial commit #24.

Preparando la vuelta al trabajo

2008/10/16

Al trabajo en KTutorial, me refiero 😉

Desgraciadamente estos meses desde mi último mensaje no tuve apenas tiempo libre y no pude continuar con el desarrollo de KTutorial desde entonces. Pero afortunadamente eso cambiará pronto.

Mi intención es continuar el desarrollo de KTutorial como mi proyecto de fin de carrera, por lo que, a no ser que las cosas se tuerzan mucho, para junio confío en haber implementado una serie de nuevas características, acompañadas cómo no de una buena documentación para desarrolladores y usuarios.

Dichas características son, principalmente, las ya mencionadas en su día de tutoriales interpretados e integración con GHNS, junto a una notable simplificación de la edición de tutoriales, puede que mediante un editor gráfico. Confío en conseguir un nivel de desarrollo suficiente como para que pueda interesar a los desarrolladores de KDE y, quién sabe, quizás poder verlo en KDE 4.3 ó 4.4… aunque eso sólo el tiempo lo dirá 🙂

Aún no me pondré con ello, no obstante, ya que antes necesito terminar algunas tareas que tengo pendientes. Confío en haberlas despachado en unas semanas.

Respecto al Concurso Universitario de Software Libre, este año volveré a presentarme, pero no con KTutorial. Supongo que, dado que voy a implementar nuevas características, podría hacerlo, pero prefiero presentar algo nuevo. No sé, manías mías. Ya veremos qué tal sale, aunque mi intuición me dice que voy a estar muy enredado con KTutorial y apenas voy a poder dedicarle tiempo al otro proyecto. Pero bueno, lo importante es participar 🙂

Y para acabar, de ahora en adelante seguramente escribiré las entradas en inglés (bueno, “inglés” 😛 ), ya que considero que es más apropiado dada la naturaleza del blog. Supongo que no era necesario indicarlo y que quien leyese las próximas entradas sería capaz de deducirlo sin ayuda… pero nunca se sabe… 😛

¡Hasta dentro de unas semanas!

Versión 0.1 disponible

2008/04/04

Realmente, ya hace una semana que la publiqué. Pero fue una semana de locura con cosas de clase y no encontré un triste momento para escribirlo aquí en el blog 😦 Pero bueno, menos lamentar y más informar 😉

La versión 0.1, así como las instrucciones de compilación e instalación, puede encontrarse en la sección de descargas de la web del proyecto.

Aproveché también para incluir la documentación de la API, un tutorial de uso de la biblioteca (para desarrolladores de aplicaciones, no para usuarios finales) y un documento de diseño. El documento de diseño, no obstante, aún es más un simple borrador que un documento serio.

¿Y ahora? Ahora, lógicamente, a por la versión 0.2. Inicialmente era donde me proponía llegar antes de terminar el concurso,  con algo de tiempo para empezar a revelar la existencia del proyecto a los desarrolladores de KDE y con suerte recibir algo de feedback (la versión española de la palabra no acaba de gustarme 😉 ). Pero con todo el lío que tuve estas últimas semanas con cosas de la universidad, eso no va a ser posible. ¡Una pena!

La idea para esta versión 0.2 es poder crear tutoriales interpretados mediante scripts (gracias a Kross), en lugar de compilados en C++, y utilizar Get Hot New Stuff para poder descargar nuevos tutoriales con facilidad.

Así que nada, ahora, a intentar integrar Kross y GHNS en la medida de lo posible con el tiempo del que dispongo. Aún no investigué GHNS, pero Kross parece que no va a ser tan sencillo como pensaba. Mejor dicho, la integración en sí sí es sencilla. Conseguir lo que creía que podría conseguir directamente con ella, no 😉 Pero eso es otra historia, y como tal ya habrá tiempo de contarla.