// we basically want to update the doc and start text of this method void RubyCodeOperation::updateMethodDeclaration() { CodeDocument * doc = getParentDocument(); RubyClassifierCodeDocument * rubydoc = dynamic_cast<RubyClassifierCodeDocument*>(doc); UMLClassifier *c = rubydoc->getParentClassifier(); UMLOperation * o = getParentOperation(); bool isInterface = rubydoc->getParentClassifier()->isInterface(); QString endLine = getNewLineEndingChars(); // now, the starting text. QString strVis = rubydoc->scopeToRubyDecl(o->getVisibility()); // no return type for constructors QString fixedReturn = RubyCodeGenerator::cppToRubyType(o->getTypeName()); QString returnType = o->isConstructorOperation() ? QString("") : (fixedReturn + QString(" ")); QString methodName = o->getName(); QString RubyClassName = rubydoc->getRubyClassName(c->getName()); // Skip destructors, and operator methods which // can't be defined in ruby if ( methodName.startsWith("~") || QRegExp("operator\\s*(=|--|\\+\\+|!=)$").exactMatch(methodName) ) { getComment()->setText(""); return; } if (RubyClassName == methodName) { methodName = "initialize"; } methodName.replace(QRegExp("operator\\s*"), ""); methodName = methodName.mid(0, 1).lower() + methodName.mid(1); QString paramStr = QString(""); QStringList commentedParams; // assemble parameters UMLAttributeList list = getParentOperation()->getParmList(); int nrofParam = list.count(); int paramNum = 0; for(UMLAttribute* parm = list.first(); parm; parm = list.next()) { QString paramName = RubyCodeGenerator::cppToRubyName(parm->getName()); paramStr += paramName; if (! parm->getInitialValue().isEmpty()) { paramStr += QString(" = ") + RubyCodeGenerator::cppToRubyType(parm->getInitialValue()); } paramNum++; if (paramNum != nrofParam ) paramStr += ", "; } QString startText; if (isInterface) { // Assume 'isInterface' means a module in Ruby, so // generate module methods startText = "def "+ RubyClassName + '.' + methodName + '(' + paramStr +')'; } else { startText = "def "+ methodName + '(' + paramStr +')'; } startText += ""; setEndMethodText("end"); setStartMethodText(startText); // Lastly, for text content generation, we fix the comment on the // operation, IF the codeop is autogenerated & currently empty QString comment = o->getDoc(); if (comment.isEmpty()) { if (getContentType() == CodeBlock::AutoGenerated) { UMLAttributeList parameters = o->getParmList(); for(UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) { comment += endLine + "* _" + iterator.current()->getName() + "_ "; comment += (' ' + iterator.current()->getDoc().replace( QRegExp("[\\n\\r]+[\\t ]*"), endLine + " " ) ); } // add a returns statement too if(!returnType.isEmpty() && !QRegExp("^void\\s*$").exactMatch(returnType)) comment += endLine + "* _returns_ " + returnType + ' '; getComment()->setText(comment); } } else { comment.replace(QRegExp("[\\n\\r]+ *"), endLine); comment.replace(QRegExp("[\\n\\r]+\\t*"), endLine); comment.replace(" m_", " "); comment.replace(QRegExp("\\s[npb](?=[A-Z])"), " "); QRegExp re_params("@param (\\w)(\\w*)"); int pos = re_params.search(comment); while (pos != -1) { comment.replace( re_params.cap(0), QString("@param _") + re_params.cap(1).lower() + re_params.cap(2) + '_' ); commentedParams.append(re_params.cap(1).lower() + re_params.cap(2)); pos += re_params.matchedLength() + 3; pos = re_params.search(comment, pos); } UMLAttributeList parameters = o->getParmList(); for (UMLAttributeListIt iterator(parameters); iterator.current(); ++iterator) { // Only write an individual @param entry if one hasn't been found already // in the main doc comment if (commentedParams.contains(RubyCodeGenerator::cppToRubyName(iterator.current()->getName())) == 0) { comment += (endLine + "@param _" + RubyCodeGenerator::cppToRubyName(iterator.current()->getName()) + '_'); if (iterator.current()->getDoc().isEmpty()) { comment += (' ' + RubyCodeGenerator::cppToRubyType(iterator.current()->getTypeName())); } else { comment += (' ' + iterator.current()->getDoc().replace(QRegExp("[\\n\\r]+[\\t ]*"), endLine + " ")); } } } comment.replace("@ref ", ""); comment.replace("@param", "*"); comment.replace("@return", "* _returns_"); // All lines after the first one starting with '*' in the doc comment // must be indented correctly. If they aren't a list // item starting with '*', then indent the text with // two spaces, ' ', to line up with the list item. pos = comment.find(endLine + '*'); if (pos != -1) { pos += endLine.length() + 1; pos = comment.find(endLine, pos); } while (pos > 0) { pos += endLine.length(); if (comment[pos] != '*') { comment.insert(pos, " "); pos += 2; } pos = comment.find(endLine, pos); } QString typeStr = RubyCodeGenerator::cppToRubyType(o->getTypeName()); if ( !typeStr.isEmpty() && !QRegExp("^void\\s*$").exactMatch(typeStr) && comment.contains("_returns_") == 0 ) { comment += endLine + "* _returns_ " + typeStr; } getComment()->setText(comment); } // In Java, for interfaces..we DONT write out non-public // method declarations. And for Ruby modules? if (isInterface) { UMLOperation * o = getParentOperation(); if(o->getVisibility() != Uml::Visibility::Public) setWriteOutText(false); } }
/** * Write a list of class operations. * @param classname the name of the class * @param opList the list of operations * @param permitScope the visibility enum * @param h output stream for the header file */ void RubyWriter::writeOperations(const QString &classname, const UMLOperationList &opList, Uml::Visibility::Enum permitScope, QTextStream &h) { // UMLOperation *op; // UMLAttribute *at; switch (permitScope) { case Uml::Visibility::Public: h << m_indentation << "public" << m_endl << m_endl; break; case Uml::Visibility::Protected: h << m_indentation << "protected" << m_endl << m_endl; break; case Uml::Visibility::Private: h << m_indentation << "private" << m_endl << m_endl; break; default: break; } foreach (const UMLOperation* op, opList) { QString methodName = cleanName(op->name()); QStringList commentedParams; // Skip destructors, and operator methods which // can't be defined in ruby if (methodName.startsWith(QLatin1Char('~')) || methodName == QLatin1String("operator =") || methodName == QLatin1String("operator --") || methodName == QLatin1String("operator ++") || methodName == QLatin1String("operator !=")) { continue; } if (methodName == classname) { methodName = QLatin1String("initialize"); } methodName.remove(QLatin1String("operator ")); methodName = methodName.mid(0, 1).toLower() + methodName.mid(1); UMLAttributeList atl = op->getParmList(); // Always write out the docs for ruby as the type of the // arguments and return value of the methods is useful bool writeDoc = true; // for (UMLAttribute& at = atl.first(); at; at = atl.next()) // writeDoc |= !at->getDoc().isEmpty(); if (writeDoc) { h << m_indentation << "#" << m_endl; QString docStr = op->doc(); docStr.replace(QRegExp(QLatin1String("[\\n\\r]+ *")), m_endl); docStr.replace(QRegExp(QLatin1String("[\\n\\r]+\\t*")), m_endl); docStr.replace(QLatin1String(" m_"), QLatin1String(" ")); docStr.replace(QRegExp(QLatin1String("\\s[npb](?=[A-Z])")), QLatin1String(" ")); QRegExp re_params(QLatin1String("@param (\\w)(\\w*)")); int pos = re_params.indexIn(docStr); while (pos != -1) { docStr.replace(re_params.cap(0), QString(QLatin1String("@param _")) + re_params.cap(1).toLower() + re_params.cap(2) + QLatin1Char('_')); commentedParams.append(re_params.cap(1).toLower() + re_params.cap(2)); pos += re_params.matchedLength() + 3; pos = re_params.indexIn(docStr, pos); } docStr.replace(QLatin1Char('\n'), QString(QLatin1String("\n")) + m_indentation + QLatin1String("# ")); // Write parameter documentation foreach (UMLAttribute* at, atl) { // Only write an individual @param entry if one hasn't been found already // in the main doc comment if (commentedParams.contains(cppToRubyName(at->name())) == 0) { docStr += (m_endl + m_indentation + QLatin1String("# @param _") + cppToRubyName(at->name()) + QLatin1Char('_')); if (at->doc().isEmpty()) { docStr += (QLatin1Char(' ') + cppToRubyType(at->getTypeName())); } else { docStr += (QLatin1Char(' ') + at->doc().replace(QRegExp(QLatin1String("[\\n\\r]+[\\t ]*")), m_endl + QLatin1String(" "))); } } } docStr.remove(QLatin1String("@ref ")); docStr.replace(QLatin1String("@param"), QLatin1String("*")); docStr.replace(QLatin1String("@return"), QLatin1String("* _returns_")); // All lines after the first '# *' in the doc comment // must be indented correctly. If they aren't a list // item starting with '# *', then indent the text with // three spaces, '# ', to line up with the list item. pos = docStr.indexOf(QLatin1String("# *")); QRegExp re_linestart(QLatin1String("# (?!\\*)")); pos = re_linestart.indexIn(docStr, pos); while (pos > 0) { docStr.insert(pos + 1, QLatin1String(" ")); pos += re_linestart.matchedLength() + 2; pos = re_linestart.indexIn(docStr, pos); } h << m_indentation << "# " << docStr << m_endl; QString typeStr = cppToRubyType(op->getTypeName()); if (!typeStr.isEmpty() && typeStr != QLatin1String("void") && docStr.contains(QLatin1String("_returns_")) == 0) { h << m_indentation << "# * _returns_ " << typeStr << m_endl; } } h << m_indentation << "def " << methodName << "("; int j=0; foreach (UMLAttribute* at, atl) { QString nameStr = cppToRubyName(at->name()); if (j > 0) { h << ", " << nameStr; } else { h << nameStr; } h << (!(at->getInitialValue().isEmpty()) ? QLatin1String(" = ") + cppToRubyType(at->getInitialValue()) : QString()); j++; }