Code Comments
Programming Forum and web based access to our favorite programming groups.On Jan 31, 9:54 pm, "andrewmcdonagh" <andrewmcdon...@gmail.com> wrote:
> On Jan 31, 1:00 am, LX-i <lxi0...@netscape.net> wrote:
>
>
>
>
....
> time for a break....(aka kids playing up... ;-) )
>
> Andrew
Ok, so I downloaded and installed vs2005 express, loaded your class
and started using the 'refactoring -> extract method' right click menu
option....
Here's what I've got so far....(if you paste it into your
vs2005...you'll need to spend a few minutes sorting out the line wraps
that posting it to here causes...)
More tomorrow....
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Text;
namespace CodeStats
{
public class CodeStatistics
{
// Properties (public instance variables)
bool updatedStats = false;
String elementId = "";
int locTotal = 0;
int locExecutable = 0;
int locCommented = 0;
// Private instance variables
protected SqlConnection dbConn;
protected SqlConnection dbHelp;
protected char elementType = ' ';
protected String elementSubType = "";
protected String fileName = "";
protected bool inComment = false;
protected List<String> programID = new List<String>();
protected String[] cobolKeywords =
{"ACCEPT","ACCESS","ACQUIRE","ADD","ADVANCING","AFTER","ALL",
"ALPHABET","ALPHABETIC","ALPHABETIC-LOWER","ALPHABETIC-
UPPER",
"ALPHANUMERIC","ALPHANUMERIC-EDITED","ALSO","ALTER","ALTERNATE",
"AND","ANY","APPLY","ARE","AREA","AREAS","ASCENDING","ASSIGN","AT",
"AUTHOR","BEFORE","BINARY","BINARY-1","BIT","BLANK","BLOCK",
"BOTTOM","BY","BYTE-I18N","CALL","CANCEL","CD","CF","CH",
"CHARACTER","CHARACTERS","CLASS","CLASS-NAME","CLOCK-
UNITS",
"CLOSE","COBOL","CODE","CODE-
SET","COLLATING","COLUMN","COMMA",
"COMMON","COMMON-
STORAGE","COMMUNICATION","COMP","COMP-1",
"COMP-2","COMPUTATIONAL","COMPUTATIONAL-1","COMPUTATIONAL-2",
"COMPUTE","CONFIGURATION","CONTAINS","CONTENT","CONTINUE","CONTROL",
"CONTROLS","CONVERTING","COPY","CORR","CORRESPONDING","COUNT",
"CURRENCY","DATA","DATE","DATE-COMPILED","DATE-
WRITTEN","DAY",
"DAY-OF-WEEK","DE","DEBUG-CONTENTS","DEBUG-ITEM","DEBUG-
LINE",
"DEBUG-NAME","DEBUG-SUB-1","DEBUG-SUB-2","DEBUG-SUB-3",
"DEBUGGING","DECIMAL-POINT","DECLARATIVES","DELETE","DELIMITED",
"DELIMITER","DENSITY","DEPART","DEPENDING","DESCENDING",
"DESTINATION","DETAIL","DISABLE","DISP","DISP-2","DISP-
I18N",
"DISPLAY","DISPLAY-2","DIVIDE","DIVISION","DOWN","DUPLICATE",
"DYNAMIC","EGI","ELSE","EMI","EMPTY","ENABLE","END","END-
ADD",
"END-CALL","END-COMPUTE","END-DELETE","END-DIVIDE","END-EVALUATE",
"END-IF","END-MULTIPLY","END-OF-PAGE","END-PERFORM","END-
READ",
"END-RECEIVE","END-RETURN","END-REWRITE","END-SEARCH","END-STRING",
"END-SUBTRACT","END-UNSTRING","END-
WRITE","ENTER","ENTRY",
"ENVIRONMENT","EOP","EQUAL","ERROR","ESI","EVALUATE","EVERY",
"EXCEPTION","EXDEF","EXEC","EXIT","EXREF","EXTEND","EXTERNAL",
"FALSE","FD","FETCH","FILE","FILE-CONTROL","FILLER","FINAL","FIND",
"FIRST","FOOTING","FOR","FREE","FROM","FUNCTION","GENERATE","GET",
"GIVING","GLOBAL","GO","GREATER","GROUP","HEADING","HIGH-VALUE",
"HIGH-VALUES","I-O","I-O-CONTROL","IDENTIFICATION","IF","IMPART",
"IN","INDEX","INDEXED","INDICATE","INITIAL","INITIALIZE","INPUT",
"INPUT-OUTPUT","INSERT","INSPECT","INSTALLATION","INTO","INVALID",
"INVOKE","IS","JUST","JUSTIFIED","KEEP","KEY","LABEL","LAST",
"LEADING","LEFT","LENGTH","LESS","LIMIT","LIMITS","LINAGE",
"LINAGE-COUNTER","LINE","LINE-COUNTER","LINES","LINKAGE","LOCALE",
"LOCK","LOG","LOW-VALUE","LOW-VALUES","MEMORY","MERGE","MESSAGE",
"MODE","MODE-1","MODE-2","MODE-3","MODE-4","MODIFY","MODULES",
"MOVE","MULTIPLE","MULTIPLY","NATIVE","NEGATIVE","NEXT","NO","NOT",
"NUMBER","NUMERIC","NUMERIC-EDITED","OBJECT-COMPUTER","OCCURS","OF",
"OFF","OMITTED","ON","OPEN","OPTIONAL","OR","ORDER","ORGANIZATION",
"OTHER","OUTPUT","OVERFLOW","OWNER","PACKED-
DECIMAL","PADDING",
"PAGE","PAGE-COUNTER","PERFORM","PF","PH","PIC","PICTURE","PLUS",
"POINTER","POINTS","POSITION","POSITIVE","PRINTING","PRIOR",
"PROCEDURE","PROCEDURES","PROCEED","PROGRAM","PROGRAM-ID","PURGE",
"QUEUE","QUOTE","QUOTES","RANDOM","RANK","RD","READ","RECEIVE",
"RECORD","RECORDING","RECORDS","REDEFINES","REEL","REFERENCE",
"REFERENCES","RELATIVE","RELEASE","REMAINDER","REMOVAL","REMOVE",
"RENAMES","REPLACE","REPLACING","REPORT","REPORTING","REPORTS",
"RERUN","RESERVE","RESET","RETURN","REVERSED","REWIND","REWRITE",
"RF","RH","RIGHT","ROUNDED","RUN","SAME","SD","SEARCH","SECTION",
"SECURITY","SEGMENT","SEGMENT-LIMIT","SELECT","SEND","SENTENCE",
"SEQUENTIAL","SET","SIGN","SIZE","SORT","SORT-
MERGE","SOURCE",
"SOURCE-COMPUTER","SPACE","SPACES","SPECIAL-
NAMES","STANDARD",
"STANDARD-1","STANDARD-2","START","STATUS","STOP","STORE","STRING",
"SUB-QUEUE-1","SUB-QUEUE-2","SUB-
QUEUE-3","SUBTRACT","SUM",
"SUPPRESS","SYMBOLIC","SYNC","SYNCHRONIZED","TABLE","TALLYING",
"TAPE","TERMINAL","TERMINATE","TEST","TEXT","THAN","THEN",
"THROUGH","THRU","TIME","TIMES","TO","TOP","TRAILING","TRUE","TYPE",
"UNIT","UNSTRING","UNTIL","UP","UPON","USAGE","USE","USING","VALUE",
"VALUES","VARYING","WHEN","WITH","WORDS","WORKING-STORAGE","WRITE",
"ZERO","ZEROES","ZEROS","+","-","*","/","**",">","<","=",">=","<="};
// Constuctor for no parameter
public CodeStatistics(String csServerName)
{
openSqlConnection(csServerName);
}
// Constructor for passed Element ID
public CodeStatistics(String csServerName, String
csElementId)
{
openSqlConnection(csServerName);
retrieveElementInfo(csElementId);
}
// Establish the element for this class instance
public void retrieveElementInfo(String reiElementId)
{
// Retrieve the information about the passed program
SqlCommand cmd = new SqlCommand("SELECT element_id,
element_type, element_subtype, server_name "
+ "FROM active_elements "
+ "WHERE element_id = '" + reiElementId.Trim() + "'",
dbConn);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
elementType =
Convert.ToChar(dr["element_type"].ToString().Trim().Substring(0,1));
elementSubType =
dr["element_subtype"].ToString().Trim();
fileName = dr["server_name"].ToString().Trim();
elementId = reiElementId;
}
dr.Close();
dr.Dispose();
}
// Update the statistics for the element ID
public void updateStatistics(String usPath, String
usProcessName)
{
if (File.Exists(usPath + fileName))
{
String textLine = "";
clearOutCrossReferenceTables();
textLine = parseFile(usPath, usProcessName,
textLine);
deleteAnyReferencesToCallsIfTheTargetIsD
efinedInTheProgram();
updateLocInTheCscsDatabase();
}
}
private void updateLocInTheCscsDatabase()
{
// Update LOC in the CSCS database
SqlCommand sc = new SqlCommand("UPDATE Active_Elements "
+ "SET Commented_Lines = " +
locCommented.ToString()
+ ", Executable_Lines = " +
locExecutable.ToString()
+ ", Total_Lines = " + locTotal.ToString()
+ "WHERE Element_ID = '" + elementId + "'", dbConn);
sc.ExecuteNonQuery();
sc.Dispose();
}
private void
deleteAnyReferencesToCallsIfTheTargetIsD
efinedInTheProgram()
{
if (programID.Count > 0)
{ // Delete any references to calls if the target is
defined in the program (i.e., nested subprograms)
SqlCommand scDelete = new SqlCommand();
scDelete.CommandText = "DELETE FROM
sdp_CSCI_CALL_Xref "
+ "WHERE Element_ID = '" + elementId + "' "
+ "AND Call_Name IN ('";
for (int i = 0; i < programID.Count; i++)
{
scDelete.CommandText += programID[i] + "'";
if (i < (programID.Count - 1))
{
scDelete.CommandText += ",'";
}
}
scDelete.CommandText += ")";
scDelete.Connection = dbConn;
scDelete.ExecuteNonQuery();
scDelete.Dispose();
}
}
private String parseFile(String usPath, String usProcessName,
String textLine)
{
StreamReader file = File.OpenText(usPath + fileName);
while (!file.EndOfStream)
{
textLine = file.ReadLine().ToUpper();
if ((elementType != 'P') && (elementType != 'L'))
{
textLine = textLine.Trim();
}
countLine(textLine); // Count this line as a "line of
code"
switch (elementType)
{
case 'P':
case 'L':
textLine = textLine.Replace(",", "
").Replace(".", " ").Trim();
updateProcXref(textLine);
updateRejectXref(textLine, usProcessName);
updateCallXref(textLine);
//updateCull(textLine);
break;
}
}
file.Close();
file.Dispose();
return textLine;
}
private void clearOutCrossReferenceTables()
{
// Depending on the type, clear out the cross-reference
tables
switch (elementType)
{
case 'P':
case 'L':
SqlCommand scDel = new SqlCommand();
scDel.Connection = dbConn;
// Delete item/proc xref
scDel.CommandText = "DELETE FROM Proc_Prog_Xref
WHERE ProgName = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete item/reject xref
scDel.CommandText = "DELETE FROM RejectsXref
WHERE program = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete item/call xref
scDel.CommandText = "DELETE FROM
sdp_CSCI_Call_Xref WHERE Element_ID = '" + elementId + "'";
scDel.ExecuteNonQuery();
// Delete cull information
scDel.CommandText = "DELETE FROM
sdp_Dbe_Csci_Xref WHERE CSCI = '" + elementId + "'";
scDel.ExecuteNonQuery();
scDel.CommandText = "DELETE FROM
sdp_Dbr_Csci_Xref WHERE CSCI = '" + elementId + "'";
scDel.ExecuteNonQuery();
scDel.Dispose();
break;
}
}
protected void countLine(String clLine)
{
String commentStart = "";
String commentEnd = "";
String commentSingle = "";
// A line is a line...
locTotal++;
if (clLine != "")
{
switch(elementType)
{
case 'P':
case 'L':
lineOfCobolCode(clLine);
break;
case 'G':
linesOfGuiCode(clLine, ref commentStart, ref
commentEnd, ref commentSingle);
break;
case 'R':
linesOfRunstreamsCode(clLine);
break;
case 'Q':
linesOfIquRunstreamsCode(clLine);
break;
default:
// Anything else, a non-blank line is
executable
locExecutable++;
break;
}
}
}
private void linesOfIquRunstreamsCode(String clLine)
{
// IQ/U Runstreams
if (clLine.Substring(0, 1) == ".")
{
locCommented++;
}
else
{
locExecutable++;
}
}
private void linesOfRunstreamsCode(String clLine)
{
// Runstreams
if ((elementSubType == "IPF") && (clLine.Substring(0, 1)
== "@"))
{ // IPF comment character
locCommented++;
}
else
{
if ((elementSubType == "QLP") && (clLine.Substring(0,
1) == "*"))
{ // QLP comment character
locCommented++;
}
else
{ // Apply ECL comment rules
if ((clLine.Length > 2) && ((clLine.Substring(0,
3) == "@ .") || (clLine.Substring(0, 3) == "@. ")))
{ // ECL comment character
locCommented++;
}
else
{
locExecutable++;
}
}
}
}
private void linesOfGuiCode(String clLine, ref String
commentStart, ref String commentEnd, ref String commentSingle)
{
determineLanguageCommentTags(ref commentStart, ref
commentEnd, ref commentSingle);
if ((commentStart == "") && (commentEnd == "") &&
(commentSingle == ""))
{ // We don't look for comments - if it's not blank,
it's executable
locExecutable++;
}
else
{
if (inComment)
{ // We're in a multi-line comment
locCommented++;
if (clLine.IndexOf(commentEnd) >= 0)
{ // This is the last line of the multi-line
comment
inComment = false;
}
}
else
{
if (clLine.IndexOf(commentStart) >= 0)
{
countNewMultiLineComment(clLine,
commentStart, commentEnd);
}
else
{
countSingleLineComments(clLine,
commentSingle);
}
}
}
}
private void countNewMultiLineComment(String clLine, String
commentStart, String commentEnd)
{
if (clLine.IndexOf(commentEnd) == -1)
{ // Start of a multi-line comment
inComment = true;
}
if ((clLine.IndexOf(commentStart) == 0))
{ // Nothing before the comment - the entire line is
commented
locCommented++;
}
else
{ // Something before the comment - count the line as
executable
locExecutable++;
}
}
private void countSingleLineComments(String clLine, String
commentSingle)
{
if ((commentSingle != "") &&
(clLine.IndexOf(commentSingle) >= 0))
{
if (clLine.IndexOf(commentSingle) == 0)
{ // The entire line is a comment
locCommented++;
}
else
{ // Only the end of the line is commented
locExecutable++;
}
}
else
{
locExecutable++;
}
}
private void determineLanguageCommentTags(ref String
commentStart, ref String commentEnd, ref String commentSingle)
{
// GUI
if ((elementSubType == "HTML") || (elementSubType ==
"CSS") || (elementSubType == "XML"))
{
commentStart = "<!--";
commentEnd = "-->";
}
else
{
if (elementSubType == "XSLT")
{
commentStart = "<xsl:comment>";
commentEnd = "</xsl:comment>";
}
else
{
if (elementSubType == "JS")
{
commentStart = "/*";
commentEnd = "*/";
commentSingle = "//";
}
}
}
}
private void lineOfCobolCode(String clLine)
{
// COBOL
if ((clLine.Length > 6) && (clLine.Substring(6, 1) ==
"*"))
{
locCommented++;
}
else
{
locExecutable++;
}
}
protected void updateProcXref(String upxLine)
{
// For this to work right, we need all items separated by
only one space
upxLine = normalizeSpace(upxLine);
switch (elementType)
{
case 'P':
establishTheCrossReferenceBasedOnCopySta
tement(upxLine);
break;
case 'L':
establishTheCrossReferenceBasedOnPerform
Statement(upxLine);
break;
}
}
private void
establishTheCrossReferenceBasedOnPerform
Statement(String upxLine)
{
// Establish the cross-reference based on perform
statement
if ((upxLine.Length > 9) && (upxLine.Substring(0, 8) ==
"PERFORM "))
{
String[] words = upxLine.Split(' ');
String[] pieces = words[1].Split('-');
// Don't count performs of the proc itself
if ((pieces[0] != elementId) &&
(isElement(pieces[0])))
{ // See if this is already in the xref
SqlCommand scCheck = new SqlCommand("SELECT
ProgName FROM Proc_Prog_Xref "
+ "WHERE ProgName = '" + elementId + "' "
+ "AND ProcName = '" + pieces[0] + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{
executeSQL("INSERT INTO Proc_Prog_Xref "
+ "(ProgName, ProcName, Passive,
EntryPoint) "
+ "VALUES ('" + elementId + "','"
+ pieces[0] + "',1,NULL)");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
private void
establishTheCrossReferenceBasedOnCopySta
tement(String upxLine)
{
// Establish the cross-reference based on copy statement
if ((upxLine.Length > 6) && (upxLine.Substring(0, 5) ==
"COPY "))
{
String[] words = upxLine.Split(' ');
String[] pieces = words[1].Split('-');
if (isElement(pieces[0]))
{ // See if this is already in the cross-reference
SqlCommand scCheck = new SqlCommand("SELECT
ProgName FROM Proc_Prog_Xref "
+ "WHERE ProgName = '" + elementId + "' "
+ "AND ProcName = '" + pieces[0] + "' "
+ "AND EntryPoint = '" + words[1] + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Add this program/proc to the table
executeSQL("INSERT INTO Proc_Prog_Xref "
+ "(ProgName, ProcName, Passive,
EntryPoint) "
+ "VALUES ('" + elementId + "','" +
pieces[0] + "',0,'" + words[1] + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
protected void updateRejectXref(String urxLine, String
urxProcessName)
{
Int32 rejectCode;
// Get rid of extra spaces
urxLine = normalizeSpace(urxLine);
if ((urxLine.IndexOf("REJCDE") >= 0) &&
(urxLine.IndexOf("MOVE ") >= 0))
{ // Line is "MOVE [something] TO REJCDE"
String[] words = urxLine.Split(' ');
if (Int32.TryParse(words[1], out rejectCode))
{
// Mask off narratives to get the lowest 4 digits
rejectCode = rejectCode % 10000;
if (rejectCode > 0)
{ // Is this reject already in the xref?
SqlCommand scCheck = new SqlCommand("SELECT
program FROM RejectsXref "
+ "WHERE program = '" + elementId + "' "
+ "AND reject_num = " +
rejectCode.ToString(), dbConn);
SqlDataReader drCheck =
scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Insert it
executeSQL("INSERT INTO RejectsXref "
+ "(program, reject_num,
last_updated, last_updated_by) "
+ "VALUES ('" + elementId + "'," +
rejectCode.ToString()
+ ",current_timestamp,'" +
urxProcessName + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
}
protected void updateCallXref(String ucxLine)
{
String[] words = normalizeSpace(ucxLine).Split(' ');
// Check for "PROGRAM-ID"
if (words[0] == "PROGRAM-ID")
{ // Save these off - we'll delete them at the end
programID.Add(words[1]);
}
if ((words.Length > 1) && (words[0] == "CALL"))
{
if ((words[1].Substring(0,1) == "\"") ||
(words[1].Substring(0,1) == "'"))
{ // Calling a literal - this is one we'll store
String callName =
words[1].Substring(1,words[1].Length - 2);
SqlCommand scCheck = new SqlCommand("SELECT
Element_ID FROM sdp_CSCI_CALL_Xref "
+ "WHERE Element_ID = '" + elementId + "' "
+ "AND Call_Name = '" + callName +
"'",dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // It's not there - insert it
executeSQL("INSERT INTO sdp_CSCI_CALL_Xref "
+ "(Element_ID, Call_Name) "
+ "VALUES ('" + elementId + "','" +
callName + "')");
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
}
}
}
protected void updateCull(String ucLine)
{
ucLine = normalizeSpace(ucLine);
if ( (ucLine.IndexOf("FETCH ") >= 0) ||
(ucLine.IndexOf("FIND ") >= 0)
|| (ucLine.IndexOf("MODIFY ") >= 0) ||
(ucLine.IndexOf("STORE ") >= 0)
|| (ucLine.IndexOf("DELETE ") >= 0) ||
(ucLine.IndexOf("INSERT ") >= 0)
|| (ucLine.IndexOf("REMOVE ") >= 0))
{
updateCullRecord(ucLine);
}
else
{
splitUpTheWordsAndCheckForDmsFieldNameOr
RprocDataName(ucLine);
}
}
private void
splitUpTheWordsAndCheckForDmsFieldNameOr
RprocDataName(String ucLine)
{
// Split up the words, and check for a DMS field name or
R-proc data name
String[] words = ucLine.Split(' ');
for (int i = 0; i < words.Length; i++)
{
if ((!isCobolKeyword(words[i])) && (!
hasSymbols(words[i])))
{
updateCullItem(words[i], ucLine);
}
}
}
// Update DML records in cull
protected void updateCullRecord(String ucrLine)
{
String[] words = ucrLine.Split(' ');
Int32 word = 0;
String column = "";
// --- CHECK #1 --- record name //
checkRecordName(words, ref word, ref column);
// --- CHECK #2 --- set name //
checkSetname(ucrLine, words, ref word, ref column);
}
private void checkSetname(String ucrLine, String[] words, ref
Int32 word, ref String column)
{
if ((ucrLine.IndexOf(" SET") >= 0) ||
(ucrLine.IndexOf("VIA ") >= 0))
{
String setName = "";
// Find the word "via" or "set"
word = 0;
while ((words[word] != "VIA") && (words[word] !=
"SET"))
{
word++;
}
if ((words[word] == "SET") && (word > 0))
{ // "FETCH xxx WITHIN xxxx SET", "REMOVE xxxx FROM
xxxxx SET", etc.
setName = words[--word];
}
else
{
if ((words[word] == "VIA") && (word <
(words.Length - 1)))
{ // "FETCH xxx VIA xxxx USING xxxx" format
statement
setName = words[++word];
}
}
if (setName != "")
{
// Is this a valid set name?
SqlCommand scSetChk = new SqlCommand("SELECT
set_name FROM dms_sets "
+ "WHERE set_name = '" + setName + "'",
dbHelp);
SqlDataReader drSetChk =
scSetChk.ExecuteReader();
if (drSetChk.HasRows)
{
// What column name do we update?
column = "";
if ((ucrLine.IndexOf("FETCH ") >= 0) ||
(ucrLine.IndexOf("FIND ") >= 0))
{
column = "Fetches";
}
else
{
if (ucrLine.IndexOf("INSERT") >= 0)
{
column = "Inserts";
}
else
{
if (ucrLine.IndexOf("REMOVE") >= 0)
{
column = "Removes";
}
}
}
if (column != "")
{ // Does it already exist in the cross-
reference?
SqlCommand scCheck = new
SqlCommand("SELECT Dbr FROM sdp_Dbr_Csci_Xref "
+ "WHERE Dbr = '" + setName + "'",
dbConn);
SqlDataReader drCheck =
scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Insert a new blank row
SqlCommand scInsert = new
SqlCommand("INSERT INTO sdp_Dbr_Csci_Xref "
+ "(Dbr, Csci, Fetches, Modifies,
Inserts, Stores, Removes, Deletes) "
+ "VALUES ('" + setName + "','" +
elementId + "',0,0,0,0,0,0)", dbConn);
scInsert.ExecuteNonQuery();
scInsert.Dispose();
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
SqlCommand scUpdate = new
SqlCommand("UPDATE sdp_Dbr_Csci_Xref "
+ "SET " + column + " = " + column +
" + 1 "
+ "WHERE Dbr = '" + setName + "' "
+ "AND Csci = '" + elementId +
"'", dbConn);
scUpdate.ExecuteNonQuery();
scUpdate.Dispose();
}
}
drSetChk.Close();
drSetChk.Dispose();
scSetChk.Dispose();
}
}
}
private void checkRecordName(String[] words, ref Int32 word,
ref String column)
{
// Find the word where we're doing the DML
while ((words[word] != "FETCH") && (words[word] !=
"FIND")
&& (words[word] != "MODIFY") && (words[word] !=
"STORE")
&& (words[word] != "DELETE") && (words[word] !=
"INSERT")
&& (words[word] != "REMOVE") && (word <
words.Length))
{
word++;
}
if ((word < (words.Length - 2))
&& ((words[word + 1] == "FIRST") || (words[word + 1]
== "NEXT")
|| (words[word + 1] == "PRIOR") || (words[word +
1] == "LAST")))
{ // "FETCH FIRST xxx", etc.
word++;
}
if ((word < (words.Length - 2)) && (words[word + 1] !=
"RECORD"))
{
// Determine the proper column name
if ((words[word] == "FETCH") || (words[word] ==
"FIND"))
{
column = "Fetches";
}
else
{
if (words[word] == "MODIFY")
{
column = "Modifies";
}
else
{
column = words[word].ToLower() + "s";
}
}
// The next word may be a record name
String recordName = words[++word];
// Is this name a valid record?
SqlCommand scRecChk = new SqlCommand("SELECT
record_name FROM dms_records "
+ "WHERE record_name = '" + recordName + "'",
dbHelp);
SqlDataReader drRecChk = scRecChk.ExecuteReader();
if (drRecChk.HasRows)
{ // Does the record already exist in the cross-
reference?
SqlCommand scCheck = new SqlCommand("SELECT CSCI
FROM sdp_Dbr_Csci_Xref "
+ "WHERE Dbr = '" + recordName + "' "
+ "AND Csci = '" + elementId + "'",
dbConn);
SqlDataReader drCheck = scCheck.ExecuteReader();
if (!drCheck.HasRows)
{ // Add a new zeroed-out row
SqlCommand scInsert = new SqlCommand("INSERT
INTO sdp_Dbr_Csci_Xref "
+ "(Dbr, Csci, Fetches, Modifies,
Inserts, Stores, Removes, Deletes) "
+ "VALUES ('" + recordName + "','" +
elementId + "',0,0,0,0,0,0)", dbConn);
scInsert.ExecuteNonQuery();
scInsert.Dispose();
}
drCheck.Close();
drCheck.Dispose();
scCheck.Dispose();
// Update this count
SqlCommand scUpdate = new SqlCommand("UPDATE
sdp_Dbr_Csci_Xref "
+ "SET " + column + " = " + column + " + 1 "
+ "WHERE Dbr = '" + recordName + "' "
+ "AND Csci = '" + elementId + "'",
dbConn);
scUpdate.ExecuteNonQuery();
scUpdate.Dispose();
}
drRecChk.Close();
drRecChk.Dispose();
scRecChk.Dispose();
}
}
protected void updateCullItem(String uciWord, String uciLine)
{
bool used = false;
bool updated = false;
// Check to see if the word starts with "R" and has a
dash, and is not this proc
if ((uciWord.Substring(0,1) == "R")
&& (uciWord.Substring(3,1) == "-")
&& (uciWord.Substring(0,4) != elementId))
{
if (uciLine.IndexOf("PERFORM") >= 0)
{ // We've got a paragraph name performed
SqlCommand scTables = new SqlCommand("SELECT
DISTINCT table_name rt "
+ "FROM rdms_tables rt, rdms_table_columns
rtc "
+ "WHERE rt.table_name = rtc.table_name "
+ "AND rtc.r_proc_element_name LIKE '"
+ uciWord.Substring(0,4) + "%'",dbHelp);
SqlDataReader drTables =
scTables.ExecuteReader();
while(drTables.HasRows)
{ // See if this table already exists in the
cull look-up
int i = 0; // !WORK this is crap
}
}
else
{
if (uciLine.IndexOf("MOVE") >= 0)
{
if (uciLine.IndexOf("TO") >
uciLine.IndexOf(uciWord))
{
used = true;
}
else
{
updated = true;
}
}
else
{
updated = true;
}
}
}
else
{ // See if the word is a valid DMS field
}
}
// Establish connections with the database
protected void openSqlConnection(String oscServerName)
{
String connString = "";
if (oscServerName == "") {
oscServerName = "[servername]";
}
connString = "server=" + oscServerName +
";database=[database];User ID=[user];Password=[password];";
dbConn = new SqlConnection(connString);
dbConn.Open();
connString = connString.Replace("[database]","[another-
database]");
dbHelp = new SqlConnection(connString);
dbHelp.Open();
}
public String cscsRegValue(String crvKey)
{
SqlCommand crvCmd = new SqlCommand("SELECT reg_value "
+ "FROM sdp_registry "
+ "WHERE reg_key = '" + crvKey + "'", dbConn);
SqlDataReader crvDR = crvCmd.ExecuteReader();
if (crvDR.Read())
{
return(crvDR["reg_value"].ToString().Trim());
}
else
{
return("");
}
}
protected void executeSQL(String esText)
{
SqlConnection esConn = new
SqlConnection(dbConn.ConnectionString + "password=[password];");
SqlCommand esCmd = new SqlCommand(esText, esConn);
esConn.Open();
esCmd.ExecuteNonQuery();
esCmd.Dispose();
esConn.Close();
esConn.Dispose();
}
// Eliminates all embedded spaces more than one
protected String normalizeSpace(String nsText)
{
String workText = nsText;
while (workText.IndexOf(" ") >= 0)
{
workText = workText.Replace(" "," ");
}
return(workText);
}
// Returns "true" if the text passed is an element in CSCS
protected bool isElement(String ieText)
{
Boolean itExists = false;
SqlCommand ieCmd = new SqlCommand("SELECT Actv_Ind FROM
Active_Elements "
+ " WHERE Element_ID = '" + ieText + "'", dbConn);
SqlDataReader ieDR = ieCmd.ExecuteReader();
if (ieDR.HasRows) {
itExists = true;
}
ieDR.Close();
ieDR.Dispose();
ieCmd.Dispose();
return(itExists);
}
// Returns "true" if the word passed is a COBOL keyword
protected bool isCobolKeyword(String ickText)
{
Int32 i = 0;
while ((i < cobolKeywords.Length) && (ickText !=
cobolKeywords[i]))
{
i++;
}
if (i < cobolKeywords.Length)
{
return(true);
}
else
{
return(false);
}
}
// Returns "true" if the words passed has symbols in it
protected bool hasSymbols(String hsText)
{
if ( (hsText.IndexOf("(") >= 0) ||
(hsText.IndexOf(")") >= 0)
|| (hsText.IndexOf("\"") >= 0) ||
(hsText.IndexOf("'") >= 0)
|| (hsText.IndexOf("_") >= 0))
{
return(true);
}
else
{
return(false);
}
}
}
}
Post Follow-up to this messageandrewmcdonagh wrote: > Ok, so I downloaded and installed vs2005 express, loaded your class > and started using the 'refactoring -> extract method' right click menu > option.... > > Here's what I've got so far....(if you paste it into your > vs2005...you'll need to spend a few minutes sorting out the line wraps > that posting it to here causes...) Very. I'll be going from this (probably shortening some of those method names), but I like it. :) [snipped to save bits] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~ / \ / ~ Live from Montgomery, AL! ~ ~ / \/ o ~ ~ ~ / /\ - | ~ daniel@thebelowdomain ~ ~ _____ / \ | ~ http://www.djs-consulting.com ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~ ~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~ ~ h---- r+++ z++++ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ "Who is more irrational? A man who believes in a God he doesn't see, or a man who's offended by a God he doesn't believe in?" - Brad Stine
Post Follow-up to this messageandrewmcdonagh wrote: > Cool! > > Yeah those names are a bit long (but then again, you only have to type > them once as intellisense will create them for you every other time), > but I did it deliberately to show the technique of 'convert comments > into private method names' to get you started on 'self documenting' > code. That's. I tend to comment a lot - more than any other programmer in our shop. (We proved that by looking at the output from this class - my commenting average is between 22% and 28% compared to executable lines in COBOL...) > I'll continue to play with the class over the next few days when I get > time and post the new versions on here.... (I'm thinking we'll > transition to something like a dozen small classes working > together....) > > This exercise is good for me too, as I've never used c# before, only > read about it... I appreciate it - I'm glad it's helping you too. Of course, I'm sort of learning the two together, but I've been surprised how much Java works in C# - and if it doesn't work, it probably just has a different name. > Once we have this out of the way...the next biggest priority on your > learning curve, should be how to develop code that has a full suite of > automated Unit tests - NUnit is the unit testing framework of choice > for .Net and should even be integrated into vs2005.... Normally I > wouldn't do any code changes like these without a suite of unit tests > to show me instantly if I break something... but one leasson at a > time. I'll have to look into that. How should I put this - code "robustness" has been an issue with some of our .net pages. -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~ / \ / ~ Live from Montgomery, AL! ~ ~ / \/ o ~ ~ ~ / /\ - | ~ daniel@thebelowdomain ~ ~ _____ / \ | ~ http://www.djs-consulting.com ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~ ~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~ ~ h---- r+++ z++++ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ "Who is more irrational? A man who believes in a God he doesn't see, or a man who's offended by a God he doesn't believe in?" - Brad Stine
Post Follow-up to this messageandrewmcdonagh wrote:
>
> 1) Create a new Interface called 'KeywordDictionary'
> with a single method 'isKeyword(String keyword)
>
> 2) Create a new Class called CobolKeywordDictionary
> 2.1) Copied the large keyword array into this new class.
> 2.2) Copied the 'isCobolKeyword(String ictText) method into this new
> class.
> 2.3) Changed the copied method's name to match the Interface's
> method (i.e 'isKeyword(String ictText)' )
> 2.4) Renamed the method parameter to be more self commenting:
> 'ictText' became 'keyword'
I like! I had been doing some working with namespaces and the like - I
took what you did, and some research prompted by Pete's comment about
the Dictionary class, and twisted it a bit. There is a List<T> class as
well, which doesn't require key/value combinations, and has a "Contains"
method. This is what it looks like now...
-8<--
using System;
using System.Collections.Generic;
using System.Text;
namespace CSCS.Util
{
class CobolKeywordDictionary : KeywordDictionary
{
// This is loaded with the keywords from the below table
private List<String> cobolKeywords = new List<String>();
// A list of COBOL keywords
private String[] keywords =
{ [oh yeah]
};
public CobolKeywordDictionary()
{
for (int i = 0; i < keywords.Length; i++)
{
cobolKeywords.Add(keywords[i]);
}
}
public bool isKeyword(String keyword)
{
return cobolKeywords.Contains(keyword.ToUpper());
}
}
}
->8--
I could still have the keywords in a separate XML file - but with the
reluctance of our customers to embrace new technology, that keyword list
won't be changing anytime soon.
This is really
stuff! The intent of this look-up is to keep us
from hitting the database to determine if the name is a database name.
However, it just hit me when I was typing this e-mail - I could make
DataSets from the database tables, convert them to lists, and use the
list lookups for the cull building! No repetitive database access!
(You were just the witness to a huge light coming on in my head... And
no, it's not just the glare from where I don't have hair there
anymore... ;) )
I had tried to implement the above with a predicate, but it seemed like
cheating. Since I can't pass a parameter to the predicate method, I had
created a private String that I set to the keyword, then used the
StartsWith method on that string. My problem with that, though, is that
"ACC" came back as true, since "ACCEPT" starts with "ACC". I was going
to put a second check in there, using EndsWith, and then I said to
myself, this needs a "Contains" method or something. :) Looks like I
wasn't alone.
And - your inteface - I could come up with something like
NetworkRecordKeywordDictionary : KeywordDictionary
NetworkItemKeywordDictionary : KeywordDictionary
RelationalTableKeywordDictionary : KeywordDictionary
RelationalItemKeywordDictionary : KeywordDictionary
I actually *will* use a dictionary on the relational items, as I'll have
a proc data name (ex. R119-Home-ELC) that references an actual database
name (HOME_ELC in the HOME_USER table). I may have to add another
method to the interface for those, or change the return type - of
course, I guess at that point it's not really using the
KeywordDictionary interface. :)
Man - I'm excited. :) I really wish that there was a generic way to
code, though, that didn't have to know about what sort of database
backend you have. SqlDataAdapter is the DataAdapter for SQL Server,
while OdbcDataAdapter is the one for ODBC. If I could "genericise" (is
that a word?) those in the code, and just have it use whatever type of
connection I passed to it, I could actually run this against a copy of
the SQL Server database on my laptop (in MySQL or Access or something
else). (And yes, I know I could just code it with ODBC, but I don't
want it to run generically in production when there are libraries
specifically enhanced for it.)
> So, you might ask 'why the interface?' good question!
>
> There is no current need for it, but my OO and Unit testing sense
> tends to say create an interface more often than not - it will pay for
> itself sooner rather than later.
> Besides, Interfaces do not incur any runtime performance costs (that
> are worth caring about).
>
> What i mean about OO sense, is that now we have separated the
> Responsibility of specifying what a KeywordDictionary 'is', compared
> to its implementation - CobolKeywordDictionary in our case, or later,
> HtmlKeywordDictionary, JavaKeywordDictionary, etc....
>
> CobolKeywordDictionary, by using the class directly, I dont need to
> test it, by creating an instance of something that just happens to use
> it (CodeStatistics in our case).
That's great. :) I appreciate the list of steps you took in
refactoring the code, too - I haven't commented about the process much
because I so excited about the results, but I wanted you to know that I
did read it, and understand why you did what you did.
Thanks again for a great post, and lots of help! :) Before you know
it, I'll be able to put C# on my resume! (Not that they look at resumes
in the military...)
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
Post Follow-up to this messageAndrew, I haven't had time to go through this in detail, but the approach is very impressive. You are demonstrating at a code level some of the most important concepts of OO. Great stuff! Pete <snipped to save space>
Post Follow-up to this messageJust to "tie in" with my OO COBOL "collection classes" thread.
If anyone understands the OO COBOL specification AND this thread, am I corre
ct
that *IF* one were doing this in COBOL that using the FACTORY Working-Storag
e
would "solve" the problem that Andrew mentions about,
" Thats ok, but the performance is going to suffer.
Every time you create an instance of this class, its going to: ..."
It is my understanding (limited as it is) that this is the point of (COBOL)
"factory" data (as opposed to method data).
--
Bill Klein
wmklein <at> ix.netcom.com
"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message
news:1170709103.296774.93650@q2g2000cwa.googlegroups.com...
> On Feb 5, 1:42 am, LX-i <lxi0...@netscape.net> wrote:
>
> snipped
>
>
>
> Thats ok, but the performance is going to suffer.
>
> Every time you create an instance of this class, its going to:
>
> 1) Create a Array of the string literals
> 2) Copy that array one by one into a List
>
> Then everytime you call 'isKeyword()' on your class, it asks the List
> if it contains the keyword. Which basically is going to loop through
> its internal data structure, one at a time until it find the keyword
> or finishes not finding it..
>
>
>
> Where as......
>
>
> using System;
> using System.Collections.Generic;
> using System.Text;
>
> namespace CodeStats
> {
> class FastCobolKeywordDictionary : KeywordDictionary
> {
> static Dictionary<String, String> keywords = new
> Dictionary<string,string>();
>
> // Static Constructor - means it will be called
> // once and only once, sometime between when the
> // program begins and the class is instantiated.
>
> static FastCobolKeywordDictionary()
> {
> //...
> keywords.Add("AUTHOR", null);
> keywords.Add("BEFORE", null);
> keywords.Add("BINARY-1", null);
> // ....
>
> }
>
> public bool isKeyword(String keyword)
> {
> return keywords.ContainsKey(keyword);
> }
>
> }
> }
>
> This class has a 'static constructor', which is called once and only
> once by the runtime system for you, at some point between the program
> starting and the first usage of the class.
>
> Plus, when 'isKeyword()' is called, it asks the Dictionary if it
> contains the keyword, which does a super fast lookup, which out
> looping through the entire collection.
>
> Dictionarys (And Hashtables) internally separate their contents into
> buckets based upon the hashcode of the Key. So when asked
> 'ContainsKey(...) they only need to look in the relevant (small)
> bucket for a match, instead of the entire collection.
>
>
>
>
>
>
>
> Sure and personally I wouldn't bother, it doesn't strike me like
> something that would change very often.
>
>
> oh ok...be care, this caching technique is widely know and so are its
> problems.
>
> e.g. when are updates applied to cache,
> concurrency issues
> etc...
>
>
> Yes best to just use '==' as this checks the string values rather than
> their references.
>
>
> note sure I follow you here...
>
> The interface is there to generalise the method, so if you change it
> to specialise again, then you code will need to
>
> if (cobol)
> return cobolKeywordDictionary.isKeyword(something);
> else
> return someOtherKeywordDictionary.isKeyword(Someting,
> andSomethingElse);
>
> always try to 'push' the knowledge of which one to call, to the other
> class (Our keyword dictionaries in this case), that way we can simply
>
> someDictionary.isKeyword(something);
>
>
>
> And that is a great technique - One I'd endorse.... which a twist...as
> above. push the knowledge of the Connection to the data source class
> itself, or pass it when you create an instance of the class.
>
> I tend to always abstract the data reading/writing behind a general
> purpose 'plain old c# ' interface, and let the implementors of that
> interface decide how/where to get their data from.
>
> e.g.
>
>
> interface LineCountReporter
> {
> void WriteTotalLineCount(String sourceFilename, int32
> lineCount);
> }
>
>
> class MySqlLineCountReporter : LineCountReporter
> {
>
> public MySqlLineCountReporter
> {
> dbConnection = // set the dbConnection here...
> }
>
> // provide the connection at object creation time only.
> public MySqlLineCountReporter(Connection connection)
> {
> dbConnection = connection
> }
> public void WriteTotalLineCount(String sourceFilename, int32
> lineCount)
> {
>
> // use MySql database code to write to a table.
> }
> }
>
>
>
>
Post Follow-up to this message"andrewmcdonagh" <andrewmcdonagh@gmail.com> wrote in message news:1170671335.661227.165220@v33g2000cwv.googlegroups.com... <snip> I just want to say that I am enjoying this thread greatly! Andrew your approach to helping Daniel is great also, expecially in a world where so many have a first instinct to just be critical. Yor way seems more like a caring teacher leading gently in the right direction. Daniel you are doing very well. Do not worry that the first code you posted was called "procedure oriented". You have to crawl befoe you can walk. Don Higgins of z390 fame redid his assembler and macro processor from COBOL to Java and it looked procedural to me at first, but it still provided a great capability with far fewer lines of code than the COBOL version. Since then he has added more features and in the process the code looks more and more object oriented. With Adrews and others help you are geeting more and more real experience with objects. Thanks to all for an excellent thread!
Post Follow-up to this message"William M. Klein" <wmklein@nospam.netcom.com> wrote in message news:YXNxh.129392$5l2.119463@fe02.news.easynews.com... > Just to "tie in" with my OO COBOL "collection classes" thread. > > If anyone understands the OO COBOL specification AND this thread, am I > correct that *IF* one were doing this in COBOL that using the FACTORY > Working-Storage would "solve" the problem that Andrew mentions about, > > " Thats ok, but the performance is going to suffer. > > Every time you create an instance of this class, its going to: ..." Yes. That is correct. The factory can be used as Static (one time) storage. You can also declare stuff in there as a PUBLIC PROPERTY (implicit GLOBAL with GET SET methods generated by COBOL.) I have code that does this in OO COBOL. The problem is that if you want to use these properties with DotNET in C# (for example), you can't. The Interop services don't handle Factory properties. (I don't know whether they handle Factory Methods, but I expect they don't...) I'm looking for a better solution for this currently; meantime, I have to pass what was a factory property to each of the Class Methods. (Once the method has it, it can store and retrieve it in the Factory definition and this works OK...) > > It is my understanding (limited as it is) that this is the point of > (COBOL) "factory" data (as opposed to method data). No. Factory seems to be very misunderstood in OO COBOL. What you mention is ONE of the points for using Factory, there are others. (For instance (oops, sorry, unconscious pun...:-)), you can use Factory Methods to do common support functions that are required by a number of Methods, but which you don't want instantiated every time a Method is instantiated. You can use Factory to hold GLOBAL non-instance variables (like a count of the number of objects currently generated, running control totals across all instances, limited only by your imagination :-). It isn't just about static storage. Pete.
Post Follow-up to this messageandrewmcdonagh wrote:
> On Feb 5, 1:42 am, LX-i <lxi0...@netscape.net> wrote:
>
> snipped
Ouch! ;)
>
> Thats ok, but the performance is going to suffer.
>
> Every time you create an instance of this class, its going to:
>
> 1) Create a Array of the string literals
> 2) Copy that array one by one into a List
>
> Then everytime you call 'isKeyword()' on your class, it asks the List
> if it contains the keyword. Which basically is going to loop through
> its internal data structure, one at a time until it find the keyword
> or finishes not finding it..
>
>
>
> Where as......
>
>
> using System;
> using System.Collections.Generic;
> using System.Text;
>
> namespace CodeStats
> {
> class FastCobolKeywordDictionary : KeywordDictionary
> {
> static Dictionary<String, String> keywords = new
> Dictionary<string,string>();
>
> // Static Constructor - means it will be called
> // once and only once, sometime between when the
> // program begins and the class is instantiated.
>
> static FastCobolKeywordDictionary()
> {
> //...
> keywords.Add("AUTHOR", null);
> keywords.Add("BEFORE", null);
> keywords.Add("BINARY-1", null);
> // ....
>
> }
>
> public bool isKeyword(String keyword)
> {
> return keywords.ContainsKey(keyword);
> }
>
> }
> }
>
> This class has a 'static constructor', which is called once and only
> once by the runtime system for you, at some point between the program
> starting and the first usage of the class.
>
> Plus, when 'isKeyword()' is called, it asks the Dictionary if it
> contains the keyword, which does a super fast lookup, which out
> looping through the entire collection.
>
> Dictionarys (And Hashtables) internally separate their contents into
> buckets based upon the hashcode of the Key. So when asked
> 'ContainsKey(...) they only need to look in the relevant (small)
> bucket for a match, instead of the entire collection.
Ah... I shied away from that because I thought, "I don't need a
key-value pair - just the value." Would it still be acceptably
efficient to do the Add()s off the array defined in the constructor? I
could convert it to hard-coded Add()s, that would be easy enough.
Also, regarding the above - would there be anything wrong with making
isKeyword() a static method as well? Then, you wouldn't actually have
to create an object - you could just say something like
if (FastCobolKeywordDictionary.isKeyword(words[i])) {
// do something really
}
I did that today with the NormalizeSpace method - I created a class
called CSCSFuncs (as plain Funcs was already taken), and made
NormalizeSpace() a class method.
(As a *way* aside, I found out that my web host, for $1 more a month,
offers ASP.NET with SQL Server 2005. I'm really tempted to cough up the
extra $12 to start working with some of my websites with this. Plus,
the plan still include PHP and MySQL, so my current stuff should
continue to work as-is. That way, I'd be able to get more experience in
the environment.)
>
> oh ok...be care, this caching technique is widely know and so are its
> problems.
These wouldn't updateable. Basically, I've got to look at every word in
a COBOL program to see if it's a database name. By excluding keywords,
I would not have to "hit the database" for those, which reduces my
database access time. Ditto for words with symbols. All I'm doing is
looking to see if that word is in the database of "database words". If
it is, I determine how it's being used (we track used vs. updated,
although it's kind of weak because an update of the group level item
updates all the elementary items; I think that the existing retrieval
walks up the hierarchy if you ask it to), then update the count.
I may have opportunity to use datasets for the update counts - but, I
would be AcceptChanges()ing often. Also, this process runs when a user
checks in a piece of source code - and, I can say with near certainty
that two people are going to be checking in the same item at the same
time! :) (If they are, we have other problems...)
(And yes, I know that this is "the original intent" of the code, which
may be changed over the years... Maybe straight ExecuteSQL()s would be
better (wrapped in another class, of course).)
>
> note sure I follow you here...
I'm not sure I followed myself... :)
> The interface is there to generalise the method, so if you change it
> to specialise again, then you code will need to
>
> if (cobol)
> return cobolKeywordDictionary.isKeyword(something);
> else
> return someOtherKeywordDictionary.isKeyword(Someting,
> andSomethingElse);
>
> always try to 'push' the knowledge of which one to call, to the other
> class (Our keyword dictionaries in this case), that way we can simply
>
> someDictionary.isKeyword(something);
Unless I return an array... Hmmm... [blink] Man, my power bill is
going to be sky-high this month! :)
But yes, I agree - the lookup for the relational items probably wouldn't
be an isKeyword() call, because I'm not implementing the interface if I
make an isKeyword() method that doesn't return a "bool" value, right?
>
> And that is a great technique - One I'd endorse.... which a twist...as
> above. push the knowledge of the Connection to the data source class
> itself, or pass it when you create an instance of the class.
>
> I tend to always abstract the data reading/writing behind a general
> purpose 'plain old c# ' interface, and let the implementors of that
> interface decide how/where to get their data from.
>
> e.g.
>
>
> interface LineCountReporter
> {
> void WriteTotalLineCount(String sourceFilename, int32
> lineCount);
> }
>
>
> class MySqlLineCountReporter : LineCountReporter
> {
>
> public MySqlLineCountReporter
> {
> dbConnection = // set the dbConnection here...
> }
>
> // provide the connection at object creation time only.
> public MySqlLineCountReporter(Connection connection)
> {
> dbConnection = connection
> }
> public void WriteTotalLineCount(String sourceFilename, int32
> lineCount)
> {
>
> // use MySql database code to write to a table.
> }
> }
I guess I'm not seeing this... How does this help me run the code on my
laptop against MySQL, e-mail to work, and run it on our server there
against SQL Server? (I don't mean this to sound as harsh as it probably
does, but I can't think of another way to word the question... Like I
said, I'm probably just not connecting the dots.)
Thanks again... :) I think I'm going to have to figure out how to use
Google Groups, because I don't want to lose this newsgroup in a couple
of w
s when my cable modem is disconnected!
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
Post Follow-up to this messageandrewmcdonagh wrote:
[snip]
>
> interface DbUtils
> {
> public void recordLinesOfComments();
> ...
>
> }
>
> class MySqlDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
> class SqlDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
>
> class OracleDbUtils : dbUtils
> {
>
>
> public void recordLinesOfComments()
> {
> ....
> }
>
> ....
> }
>
>
> Once you have these set of classes that implement the DB agnostic
> interface your application just then needs to decide which one to
> create an instance of to use. This could be done in the apps main
> class, using a commandline paramerter, machine name, environment
> variable, etc.
So, I've got basically the same thing 4 different times, depending on
the database I'm hitting. I don't guess there's any way around that,
but I do understand the flexibility it gets. The dots are connected
now. :) And, as I don't think I'm going to finish what I'm trying to
do here before I leave, this will help me set up the database on my machine.
(And, I should be able to make the other sets of code by replacing
"SqlConnection" with "OdbcConnection", "SqlDataAdapter" with
"OdbcDataAdapter", etc.)
> This technique is known as 'Inversion of Control'. Instead of the
> control over what implementation to use being hard coded, we invert
> that control by making it runtime configurable.
That's definitely what I was looking for. :) Thanks again for breaking
it down for me.
(Did you look at the "second C#" post - and if so, does it look like I'm
on the right track?)
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
~ / \ / ~ Live from Montgomery, AL! ~
~ / \/ o ~ ~
~ / /\ - | ~ daniel@thebelowdomain ~
~ _____ / \ | ~ http://www.djs-consulting.com ~
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
~ GEEKCODE 3.12 GCS/IT d s-:+ a C++ L++ E--- W++ N++ o? K- w$ ~
~ !O M-- V PS+ PE++ Y? !PGP t+ 5? X+ R* tv b+ DI++ D+ G- e ~
~ h---- r+++ z++++ ~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~
"Who is more irrational? A man who believes in a God he doesn't see, or
a man who's offended by a God he doesn't believe in?" - Brad Stine
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.