00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "rubywriter.h"
00020
00021 #include <kdebug.h>
00022 #include <klocale.h>
00023 #include <kmessagebox.h>
00024 #include <qfile.h>
00025 #include <qtextstream.h>
00026 #include <qregexp.h>
00027
00028 #include "classifierinfo.h"
00029 #include "../umldoc.h"
00030 #include "../umlattributelist.h"
00031 #include "../association.h"
00032 #include "../attribute.h"
00033 #include "../classifier.h"
00034 #include "../operation.h"
00035 #include "../umlnamespace.h"
00036
00037 RubyWriter::RubyWriter() {
00038 }
00039
00040 RubyWriter::~RubyWriter() {}
00041
00042 void RubyWriter::writeClass(UMLClassifier *c) {
00043 if(!c) {
00044 kDebug()<<"Cannot write class of NULL concept!" << endl;
00045 return;
00046 }
00047
00048 QString classname = cleanName(c->getName());
00049
00050 UMLClassifierList superclasses = c->getSuperClasses();
00051 UMLAssociationList aggregations = c->getAggregations();
00052 UMLAssociationList compositions = c->getCompositions();
00053
00054
00055 QString fileName = findFileName(c, ".rb");
00056 if (fileName.isEmpty()) {
00057 emit codeGenerated(c, false);
00058 return;
00059 }
00060
00061 QFile fileh;
00062 if( !openFile(fileh, fileName) ) {
00063 emit codeGenerated(c, false);
00064 return;
00065 }
00066 QTextStream h(&fileh);
00067
00068
00069 classifierInfo = new ClassifierInfo(c, m_doc);
00070 classifierInfo->fileName = fileName;
00071 classifierInfo->className = cleanName(c->getName());
00072
00074
00076
00077
00078
00079 QString str;
00080
00081 str = getHeadingFile(".rb");
00082 if(!str.isEmpty()) {
00083 str.replace(QRegExp("%filename%"), fileName);
00084 str.replace(QRegExp("%filepath%"), fileh.name());
00085 h<<str<<m_endl;
00086 }
00087
00088 if(forceDoc() || !c->getDoc().isEmpty()) {
00089 QString docStr = c->getDoc();
00090 docStr.replace(QRegExp("\\n"), "\n# ");
00091 docStr.replace("@ref ", "");
00092 docStr.replace("@see", "_See_");
00093 docStr.replace("@short", "_Summary_");
00094 docStr.replace("@author", "_Author_");
00095 h<<"#"<<m_endl;
00096 h<<"# "<<docStr<<m_endl;
00097 h<<"#"<<m_endl<<m_endl;
00098 }
00099
00100
00101 UMLClassifier *concept;
00102
00103 h<< "class " << cppToRubyType(classname) << (superclasses.count() > 0 ? " < ":"");
00104
00105 int i = 0;
00106 for (concept = superclasses.first(); concept; concept = superclasses.next()) {
00107 if (i == 0) {
00108 h << cppToRubyType(concept->getName()) << m_endl;
00109 } else {
00110
00111
00112 h << m_indentation << "include "<< cppToRubyType(concept->getName()) << m_endl;
00113 }
00114 i++;
00115 }
00116
00117 h << m_endl;
00118
00119
00120 if (forceDoc() || classifierInfo->hasAccessorMethods) {
00121 h << m_indentation << "#" << m_endl;
00122 h << m_indentation << "# Accessor Methods" << m_endl;
00123 h << m_indentation << "#" << m_endl << m_endl;
00124
00125
00126 writeAttributeMethods(&(classifierInfo->atpub), Uml::Visibility::Public, h);
00127 writeAttributeMethods(&(classifierInfo->atprot), Uml::Visibility::Protected, h);
00128 writeAttributeMethods(&(classifierInfo->atpriv), Uml::Visibility::Private, h);
00129 h << m_endl;
00130 }
00131
00132
00133 writeOperations(c, h);
00134
00135
00136 h << "end" << m_endl << m_endl;
00137
00138
00139 fileh.close();
00140 emit codeGenerated(c, true);
00141 }
00142
00143
00145
00146
00147 QString RubyWriter::cppToRubyType(const QString &typeStr) {
00148 QString type = cleanName(typeStr);
00149 type.replace("const ", "");
00150 type.replace(QRegExp("[*&\\s]"), "");
00151 type.replace(QRegExp("[<>]"), "_");
00152 type.replace("QStringList", "Array");
00153 type.replace("QString", "String");
00154 type.replace("bool", "true|false");
00155 type.replace(QRegExp("^(uint|int|ushort|short|ulong|long)$"), "Integer");
00156 type.replace(QRegExp("^(float|double)$"), "Float");
00157 type.replace(QRegExp("^Q(?=[A-Z])"), "Qt::");
00158 type.replace(QRegExp("^K(?!(DE|Parts|IO)"), "KDE::");
00159
00160 return type;
00161 }
00162
00163 QString RubyWriter::cppToRubyName(const QString &nameStr) {
00164 QString name = cleanName(nameStr);
00165 name.replace(QRegExp("^m_"), "");
00166 name.replace(QRegExp("^[pbn](?=[A-Z])"), "");
00167 name = name.mid(0, 1).lower() + name.mid(1);
00168 return name;
00169 }
00170
00171 void RubyWriter::writeOperations(UMLClassifier *c,QTextStream &h) {
00172
00173
00174 UMLOperationList oppub,opprot,oppriv;
00175
00176 oppub.setAutoDelete(false);
00177 opprot.setAutoDelete(false);
00178 oppriv.setAutoDelete(false);
00179
00180
00181 UMLOperationList opl(c->getOpList());
00182 for(UMLOperation *op = opl.first(); op ; op = opl.next()) {
00183 switch(op->getVisibility()) {
00184 case Uml::Visibility::Public:
00185 oppub.append(op);
00186 break;
00187 case Uml::Visibility::Protected:
00188 opprot.append(op);
00189 break;
00190 case Uml::Visibility::Private:
00191 oppriv.append(op);
00192 break;
00193 default:
00194 break;
00195 }
00196 }
00197
00198 QString classname(cleanName(c->getName()));
00199
00200
00201 if(forceSections() || !oppub.isEmpty()) {
00202 writeOperations(classname, oppub, Uml::Visibility::Public, h);
00203 }
00204
00205 if(forceSections() || !opprot.isEmpty()) {
00206 writeOperations(classname, opprot, Uml::Visibility::Protected, h);
00207 }
00208
00209 if(forceSections() || !oppriv.isEmpty()) {
00210 writeOperations(classname, oppriv, Uml::Visibility::Private, h);
00211 }
00212
00213 }
00214
00215 void RubyWriter::writeOperations(const QString &classname, UMLOperationList &opList,
00216 Uml::Visibility permitScope, QTextStream &h)
00217 {
00218 UMLOperation *op;
00219 UMLAttribute *at;
00220
00221 switch (permitScope) {
00222 case Uml::Visibility::Public:
00223 h << m_indentation << "public" << m_endl << m_endl;
00224 break;
00225 case Uml::Visibility::Protected:
00226 h << m_indentation << "protected" << m_endl << m_endl;
00227 break;
00228 case Uml::Visibility::Private:
00229 h << m_indentation << "private" << m_endl << m_endl;
00230 break;
00231 default:
00232 break;
00233 }
00234
00235 for (op=opList.first(); op ; op=opList.next()) {
00236 QString methodName = cleanName(op->getName());
00237 QStringList commentedParams;
00238
00239
00240
00241 if ( methodName.startsWith("~")
00242 || methodName == "operator ="
00243 || methodName == "operator --"
00244 || methodName == "operator ++"
00245 || methodName == "operator !=" )
00246 {
00247 continue;
00248 }
00249
00250 if (methodName == classname) {
00251 methodName = "initialize";
00252 }
00253
00254 methodName.replace("operator ", "");
00255 methodName = methodName.mid(0, 1).lower() + methodName.mid(1);
00256
00257 UMLAttributeList atl = op->getParmList();
00258
00259 bool writeDoc = forceDoc() || !op->getDoc().isEmpty();
00260
00261
00262 writeDoc = true;
00263
00264
00265
00266 if (writeDoc) {
00267 h << m_indentation << "#" << m_endl;
00268 QString docStr = op->getDoc();
00269
00270 docStr.replace(QRegExp("[\\n\\r]+ *"), m_endl);
00271 docStr.replace(QRegExp("[\\n\\r]+\\t*"), m_endl);
00272
00273 docStr.replace(" m_", " ");
00274 docStr.replace(QRegExp("\\s[npb](?=[A-Z])"), " ");
00275 QRegExp re_params("@param (\\w)(\\w*)");
00276 int pos = re_params.search(docStr);
00277 while (pos != -1) {
00278 docStr.replace( re_params.cap(0),
00279 QString("@param _") + re_params.cap(1).lower() + re_params.cap(2) + '_' );
00280 commentedParams.append(re_params.cap(1).lower() + re_params.cap(2));
00281
00282 pos += re_params.matchedLength() + 3;
00283 pos = re_params.search(docStr, pos);
00284 }
00285
00286 docStr.replace("\n", QString("\n") + m_indentation + "# ");
00287
00288
00289 for (at = atl.first(); at ; at = atl.next()) {
00290
00291
00292 if (commentedParams.contains(cppToRubyName(at->getName())) == 0) {
00293 docStr += (m_endl + m_indentation + "# @param _" + cppToRubyName(at->getName()) + '_');
00294 if (at->getDoc().isEmpty()) {
00295 docStr += (' ' + cppToRubyType(at->getTypeName()));
00296 } else {
00297 docStr += (' ' + at->getDoc().replace(QRegExp("[\\n\\r]+[\\t ]*"), m_endl + " "));
00298 }
00299 }
00300 }
00301
00302 docStr.replace("@ref ", "");
00303 docStr.replace("@param", "*");
00304 docStr.replace("@return", "* _returns_");
00305
00306
00307
00308
00309
00310 pos = docStr.find("# *");
00311 QRegExp re_linestart("# (?!\\*)");
00312 pos = re_linestart.search(docStr, pos);
00313 while (pos > 0) {
00314 docStr.insert(pos + 1, " ");
00315
00316 pos += re_linestart.matchedLength() + 2;
00317 pos = re_linestart.search(docStr, pos);
00318 }
00319
00320 h << m_indentation << "# "<< docStr << m_endl;
00321
00322 QString typeStr = cppToRubyType(op->getTypeName());
00323 if (!typeStr.isEmpty() && typeStr != "void" && docStr.contains("_returns_") == 0) {
00324 h << m_indentation << "# * _returns_ " << typeStr << m_endl;
00325 }
00326 }
00327
00328 h<< m_indentation << "def " + methodName << "(";
00329
00330 int j=0;
00331 for (at = atl.first(); at; at = atl.next(), j++) {
00332 QString nameStr = cppToRubyName(at->getName());
00333 if (j > 0) {
00334 h << ", " << nameStr;
00335 } else {
00336 h << nameStr;
00337 }
00338 h << (!(at->getInitialValue().isEmpty()) ?
00339 (QString(" = ") + cppToRubyType(at->getInitialValue())) :
00340 QString(""));
00341 }
00342
00343 h <<")" << m_endl;
00344
00345 h << m_indentation << m_indentation << m_endl;
00346
00347 h << m_indentation << "end" << m_endl << m_endl;
00348
00349 }
00350
00351 }
00352
00353
00354
00355 void RubyWriter::writeAttributeMethods(UMLAttributeList *attribs,
00356 Uml::Visibility visibility, QTextStream &stream)
00357 {
00358
00359 if (attribs->count() == 0 || visibility == Uml::Visibility::Private)
00360 return;
00361
00362 UMLAttribute *at;
00363 for(at=attribs->first(); at; at=attribs->next())
00364 {
00365 QString varName = cppToRubyName(cleanName(at->getName()));
00366
00367 writeSingleAttributeAccessorMethods(varName, at->getDoc(), stream);
00368 }
00369
00370 }
00371
00372 void RubyWriter::writeSingleAttributeAccessorMethods(
00373 const QString &fieldName,
00374 const QString &descr,
00375 QTextStream &h)
00376 {
00377 QString description = descr;
00378 description.replace(QRegExp("m_[npb](?=[A-Z])"), "");
00379 description.replace("m_", "");
00380 description.replace("\n", QString("\n") + m_indentation + "# ");
00381
00382 if (!description.isEmpty()) {
00383 h << m_indentation << "# " << description << m_endl;
00384 }
00385
00386 h << m_indentation << "attr_accessor :" << fieldName << m_endl << m_endl;
00387
00388 return;
00389 }
00390
00394 Uml::Programming_Language RubyWriter::getLanguage() {
00395 return Uml::pl_Ruby;
00396 }
00397
00398 const QStringList RubyWriter::reservedKeywords() const {
00399
00400 static QStringList keywords;
00401
00402 if (keywords.isEmpty()) {
00403 keywords << "__FILE__"
00404 << "__LINE__"
00405 << "BEGIN"
00406 << "END"
00407 << "alias"
00408 << "and"
00409 << "begin"
00410 << "break"
00411 << "case"
00412 << "class"
00413 << "def"
00414 << "defined?"
00415 << "do"
00416 << "else"
00417 << "elsif"
00418 << "end"
00419 << "ensure"
00420 << "false"
00421 << "for"
00422 << "if"
00423 << "in"
00424 << "module"
00425 << "next"
00426 << "nil"
00427 << "not"
00428 << "or"
00429 << "redo"
00430 << "rescue"
00431 << "retry"
00432 << "return"
00433 << "self"
00434 << "super"
00435 << "then"
00436 << "true"
00437 << "undef"
00438 << "unless"
00439 << "until"
00440 << "when"
00441 << "while"
00442 << "yield";
00443 }
00444
00445 return keywords;
00446 }
00447
00448 #include "rubywriter.moc"