biohisham has asked for the wisdom of the Perl Monks concerning the following question:

Hello every one, I have been in Perl Monks these two months, my journey start was from here down the path of Perl, I haven't come with any significant things yet however.

I have just written my first serious application that does something (considered "something" in my eyes anyways :p). After having learnt Tk for a while I got the idea of writing this GUI application that makes it easier for you to write a node in the Monastery, it makes short the process of having to manually fill in the markup elements by tag in the Monastery.

I'm aware that it has been done before but I haven't found that code in here, hence I thought this is going to be my first offering to our Dear Monastery. At the same time get advice from those who're masters in programming and who know Tk better than I do since my coding style is still evolving and requires perfection.

. Here's the thing:

  1. if you want to download the code for your review or usage please make sure you have the Tk module installed in your machine.
  2. if you want to use the code as is, you probably need to save it as a .wpl file instead of .pl file for convinience but that would disable the console and hence you wouldn't see error messages since I haven't provided for a log file to save errors to, (I don't know how to do it yet).
  3. I declared the variables in-bulk to avoid typing "my" over and over.

Special thanks to my buddies in here who took it upon themselves to correct some of my mistakes and provide generous suggestions, esp my man ssandv, dear ELISHEVA and my look-up example Marshall.

Now to cut it short, please take a critical scan at my code and give me your feed back to some of the issues illustrated therein or to any other that you thing are relevant.

You can find my code in the link below, I made comments on the things I got stuck, and I am soliciting advice, criticism, encouragement from you all.
#!/usr/local/bin/perl ###################################################################### +#################################### ###################################################################### +#################################### #This is a program that simulates some of the tasks of posting and pre +viewing a node at PerlMonks. # # I thought of making such a program for the following reasons: + # # 01-Practice the Tk module to a decent level or ma +stery. # # 02-Make a GUI that could enable Perl newbies to p +ost nodes quicker without # # using some of the deprecated tags like <pre> and. + # # 03-Participate at the Monastery by contributing s +omething that can also be used # # by everyone who wants a speedier approach to posting a node with s +ome of the following advantages: # # *The lengthoverhead of the preview button response +is minimized. # # *Minimizing the clutter of the most used tags at yo +ur personalized node dispatcher. # # *Giving an insight into the MarkUp of the Monastery + that is visualizable. # # *presenting wpl.exe to newbies and how it allows a +program to run without console. # # *Some other advantages and ideas like checking the +module availablity, strictures..etc# # 04- Improve my coding style and entertain construc +tive criticism from all. # ###################################################################### +#################################### ###################################################################### +#################################### ###Checking whether the required modules are installed + before everything else### @modules=("use Tk", "require Tk::BrowseEntry", "require Tk::DialogBox" +,"require Tk::Dialog"); foreach(@modules){ eval; if($@){ $_=~/\w+\W(\S+)/; print "Module $1 does not exist, please install it fir +st!\n"; } }; use strict; use warnings; use Tk; ## Declaring Main, side Panel, Top Panel, Text Area, p +review Area and Two menus## my ($main, $menuBar, $sideBar, $textBar,$textArea, $prevArea); my ($fileMenu, $editMenu); $main = MainWindow->new(); $main->title('PM HTML Encoder (BioHisham@gmail.com) '); $menuBar=$main->Frame()->pack(-side=>'top',-fill=>'x'); $sideBar=$main->Frame()->pack(-side=>'left', -expand=>1, -fill=>'both' +); $textBar=$main->Frame()->pack(); $fileMenu=$menuBar->Menubutton(-text=>'File', -relief=>'raised')->pack +(-side=>'left'); $editMenu=$menuBar->Menubutton(-text=>'Edit', -relief=>'raised')->pack +(-side=>'left'); $textArea=$textBar->Scrolled( #text Area, the width is not t +he default 70 like the PM's, 'Text', #because my screen width doesn +'t allow that. -scrollbars=>'ow', #the o let's the scrollbar sho +w when necessary. -width=>'50', -height=>'30' )->pack(-side=>'left'); $prevArea=$textBar->Scrolled( #preview Area. 'Text', -scrollbars=>'ow', -width=>'50', -height=>'30' )->pack(-side=>'right'); ## Populating the File menu and setting behavior + ## ## I dont know what else to place on these menus ho +wever :( ## my $exitCmd=$fileMenu->command( -label=>'exit', -accelerator=>'(Alt + F4)', -command=>sub{exit;} ); $main->bind('<Alt - F4>'=>sub{exit;}); ######################################## ### Buttons FOR: ### ### CODE, Paragraph, ### ### preview, Read More, ### ### Internal Links, ### ### External Links, ### ### Lists invocation and Preview ### ###################################### my ($codeTag, $html_var,$listTag,$readTag,$internLink, $extLink,$lineT +ag,$prevTag,$paraTag, $listButton, $resetAll); #Buttons $codeTag=$sideBar->Button( -text=> 'CODE', -relief=>'ridge', -height=> 2, -width=> 10, -command=>\&CodeIt)->pack(); $paraTag=$sideBar->Button( -text=> 'PARAGRAPH', -relief=>'ridge', -height=> 2, -width=> 10, -command=>\&ParaIt)->pack(); #$lineTag=$sideBar->Button( #this is the <br> not deployed yet # -text=>'Line Break', # -relief=>'ridge', # -height=> 2, # -width=>10, # -command=>\&LineIt # )->pack(); $readTag=$sideBar->Button( -text=> 'Read More', #Not sure I presented this the right + way though cuz it confused me -relief=> 'ridge', -height=> 2, -width=> 10, -command=>\&LinkIt )->pack(); $internLink=$sideBar->Button( -text=> 'Internal link', -relief=> 'ridge', -height=> 2, -width=> 10, -command=>\&linkIt_Intern, )->pack(); $extLink=$sideBar->Button( -text=> 'External Link', -relief=> 'ridge', -height=> 2, -width=> 10, -command=> \&linkIt_Ext, )->pack(); $listButton=$sideBar->Button( #Hitting this button casuses many i +nstances of the listBrowse widget -text=> 'list', -height=> 2, -width=> 10, -relief=> 'ridge', -command=> \&listBrowse, )->pack(); $resetAll=$sideBar->Button( -text=> 'Reset All', -height=> 3, -width=> 10, -relief=> 'groove', -background=>'white', -command=>sub{ for($textArea, $prevArea){ $_->delete('1.0','end'); } } )->pack(-fill=>'x', -expand=>'1', -side=>'bottom'); ## Since lists are either ordered or unordered + I made a BrowseEntry ### ## to show lists types upon hitting the List B +utton. ### require Tk::BrowseEntry; require Tk::DialogBox; require Tk::Dialog; my $choice="number"; #the default list item. sub listBrowse{ $listTag=$sideBar->BrowseEntry( -variable=>\$choice, -browsecmd=>\&Verify )->pack(); $listTag->insert("end","Number"); $listTag->insert("end","Bullet"); } my ($number,$listItems, $dialog, $errorDialog, $entry); $dialog=$main->DialogBox( -title=>'Enter List Length', -buttons=>['ok', 'cancel'] ); $errorDialog=$main->Dialog( #this is an error message w +hen the user enters -title=>'error', #an invalid choice in the D +ialogBox. -text=>'invalid number', -bitmap=>'error', -buttons=>['Ok'] ); $entry = $dialog->add( #adding an entry widget to th +e dialog box body. 'Entry', -width=>40, )->pack(); $prevTag=$sideBar->Button( -text=>'PREVIEW', -relief=>'ridge', -height=> 2, -width=>10, -command=> \&SeeIt, )->pack(); MainLoop; { #setting scope for $srting# sub CodeIt{ my ($string, $pos); $string = "<code>\nPlace Code Here\n</code>"; $textArea->insert('end',"$string"); } sub ParaIt{ my ($string, $pos); $string = "<p>\nenter some lines of text\n</p>"; $textArea->insert('end',"$string"); } sub SeeIt{ #this subroutine would create a temporary file to write the te +xt area content to and then #would use the temporary file as the source to write to the pr +eview area from. #N.B: I COULD NOT unlink OR delete THE TEMPORARY FILE THUS CRE +ATED AND COULDN'T HANDLE THE while #LOOP TO WORK OFF THE TEXT AREA DIRECTLY WITHOUT CREATING AN I +NTERMEDIARY CHANNEL. my (@data, $line, $filename); $html_var=$textArea->get('1.0','end'); #get the text from the +widget into a string variable. $filename="FileInputSample.tmp"; open FH, ">$filename" or die "$!"; print FH $html_var; open FH, "$filename", or die "$!"; while(@data=<FH>){ foreach $line (@data){ #This has been thorny because + one list type overrules the other. #Could not get to allow mixing + of list types. $line =~ s/(<.?code>)//; $line =~ s/(<p>|<ol>)/\n/; $line =~ s/<\/p>//; if($line =~ s/<.?ol>//){ my $i=1; map {s/<li>/"\t".$i++."-"/e} @ +data; map {s/<\/li>//} @data; }elsif($line =~ s/<.?ul>//){ map {s/<li>/"\t* "/e} + @data; map {s/<\/li>//} @data +; } #elsif } #foreach $prevArea->delete('1.0', 'end'); $prevArea->insert('1.0',"@data"); }#while close ('FH'); unlink("$filename") or die "Failed to delete the temporary fil +e $!\n"; #deleting the file } #sub LineIt{ #related to the deactivate +<br> # $string="<br>Enter a new Line"; # $pos=$textArea->index('insert'); #get current cursor positio +n # $textArea->insert("$pos","$string"); # } sub LinkIt{ #When I tested this one, I don't think I can make it + work as it should by #retracting the linked page to a mere hypertext. my ($string, $pos); $string=qq("<readmore title="Link Title Here"> Text Goes here +</readmore>"); $pos=$textArea->index('insert'); $textArea->insert("$pos","$string"); } sub linkIt_Intern{ my ($string, $pos); $string = "[Node Name or Node ID, pad: or doc: or username]"; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } sub linkIt_Ext{ my ($string, $pos); $string = qq([href://http://www.Site.com|Label]); $pos=$textArea->index('insert'); $textArea->insert("$pos", "$string"); } my $result; #the result from the DialogBox which can be ok or cancel. my $flag; #a flag returned to control subroutines flow. sub Verify{ #whether the choice is equal to bulltes or numbers and act acc +ordingly if($choice eq "Bullet"){ $entry->delete('0.0','end'); #reset the entry widge +t in the dialog box. my $result=$dialog->Show; #show the dialog box a +nd capture response. if($result eq "ok"){ $number=$entry->get(); #if the return value of VerifyListNumber is 1 +or 0 and acts accordingly: Bullets() if(VerifyListNumber()); +#dont go to bullets() unless flag is 1 $errorDialog->Show() if(!VerifyListNumber()); +#when the flag is 0. }elsif($result eq "cancel"){ $entry->delete('0.0','end'); return; } }elsif($choice eq "Number"){ $entry->delete('0.0','end'); my $result=$dialog->Show; if($result eq "ok"){ $number=$entry->get(); Numbers() if (VerifyListNumber()); $errorDialog->Show() if(!VerifyListNum +ber()); }elsif($result eq "cancel"){ $entry->delete('0.0','end'); return; } } } sub VerifyListNumber{ chomp $number; if($number=~/\D+/){ $flag=0; return $flag; }else{$flag=1; return $flag;} } sub Bullets{ my ($string, $pos); $listItems="<li>Enter Item</li>\n"; $string = "<ul>\n".($listItems x $number)."\n</ul>"; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } sub Numbers{ my ($string, $pos); $listItems="<li>Enter Item</li>\n"; $string = "<ol>\n".($listItems x $number)."\n</ol>"; $pos = $textArea->index('insert'); $textArea->insert("$pos","$string"); } }#ending the subroutines scope. # Any ideas, feedback and criticism are accepted with an open h +eart. # Thanks for your time, your efforts and your assitance. #This has been when I could come up with to the best of my abilities, +I could not simulate underlined text to #represent links to websites, I couldn't get the program distinguish m +ultiple instances of lists and operate #accordingly, there might be other bugs lurking around but I could not + unearth them for a critical eye scanning #is sharper and finer than a learner's eye.

Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.

Replies are listed 'Best First'.
Re: RFC: Monastery Markup Renderer
by toolic (Bishop) on Sep 16, 2009 at 20:29 UTC
    I believe it is customary to post your code directly in your OP node (inside 'readmore' tags), rather than linking to your scratchpad. I would prefer it that way since the spad tends to be too transient, and I feel like I'm shooting at a moving target :)
    I'm aware that it has been done before but I haven't found that code in here, hence I thought this is going to be my first offering to our Dear Monastery.
    Can you comment on how your code differs from PerlMonks Editor, from an over-all functionality point of view. Conceptually, do they do similar things?
Re: RFC: Monastery Markup Renderer
by toolic (Bishop) on Sep 17, 2009 at 02:08 UTC
    I composed this reponse using your code... on Windoze even! I just downloaded the code as-is, and it works right out of the box.

    I can vouch for basic functionality, and it seems straightforward to use. If you plan to add more capabilities, here is my wishlist:

    • Save to a file
    • Do not pre-fill code, paragraphs, etc.
    • More formatting: bold, italics, blockquote, h1, etc.

    Bug report:

    • Why are the 'readmore' tags surrounded by double quotes?
    • paragraph tags can not be inserted at the cursor; they always show up at the bottom

    Code review

    • When I see blocks of comments, I think "POD". This also allows you to use perldoc as a manpage for your code.
    • You could check your code with perlcritic
    • I ran your code through perltidy
    • Is there any point to checking whether the required modules are installed? Once you hit the actual 'use', won't the code die anyway?
    • I've never used the Tk modules, but there seem to be a lot of variables
      *Do not pre-fill code, paragraphs, etc
      *Is there any point to checking whether the required modules are installed? Once you hit the actual 'use', won't the code die anyway?
      Would you elaborate more? as I think I am not totally aware of the technical meaning of pre-fill. Also the second point, I don't know whether it suffices to work without checking the existence of modules first, I was notified of this by ssandv but in brevity and I could not understand the purport technically. I would however want to make a list of wishlists collected from the interaction I receive on this node and they'd all hold equal importance to me.

      For the read more tags I thought I would have the user not worry about double-quoting themselves in case they thought they wanted to double-quote, but I do not see this as much of a difference hence I am removing them double-quotes from the readmore tags

      The reason why paragraphs can not be inserted the cursor is because it would not be clean to have paragraphs tags overlapping, suppose you wanted to add some more text to describe something in a particular paragraph, you would lose track of where that paragraph is had they been overlapping and the tag filling up where the cursor is

      I have these couple of serious bugs with the listing however, whenever you hit the list button, it creates a different instance of the list-type to choose from, the second issue is that, in numbered lists, I could not treat different lists as discontiguous entities, hence, if you have used numbered list to have written this replay this way to me, you would not get the lists numbered from 1 for every time, like the numbering of a new list starts at the end of the number for the previous last list item.

      I'd land at POD once this code catches real fire, I see that I haven't received the response I expected however, and now that this node is getting covered up by new nodes is kinda of difficult to garner more response,however, I tried "POD"ing but it felt like getting me off the topic since It requires viewing and testing on its own too, this is why I'd land at it later.

      Tk is easier than I thought it would be, As for the many variables names, I know, for most of them, you can just work without declarations, as in $main->Button()->pack and that is it without specifying a variable as $button to hold the button name, for some other variables, you'd need to use them other places hence you need to assign them to variables. I have done it this way to be able to follow what is going on and what each button has for example by looking at the variable holding its method calls instead of digging through the code to establish what this certain part or that other part is all about

      Finally, thanks and looking forward to more interaction with you

      Would still compare my little ugly code to GrandFather's grand code, thanks for finding where it resides, I would come back to your question soon as I can afford.


      Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
        Here is what I mean by 'pre-fill'. Currently, when I click on your 'PARAGRAPH' button, it gives me this:
        <p> enter some lines of text </p>

        I think it is unnecessary to give me the text 'enter some lines of text'. I know that I have to enter text. And now I have to select all that text and over-write it. I am too Lazy for all that. The same goes for 'code' tags and list tags.

        The reason why paragraphs can not be inserted the cursor is because it would not be clean to have paragraphs tags overlapping
        Are you aware that the ending 'p' tag is not required? I never use </p> when I'm composing a node. Here is what my node would look like with 2 paragraphs:
        <p>1st paragraph <p>2nd one

        So, all I'd like when I hit your 'PARAGRAPH' button is the following:

        <p>

        But it's easier to write POD than all those commented-out lines. It's as simple as:

        =pod This is a program that simulates some of the tasks of posting and prev +iewing a node at PerlMonks. I thought of making such a program for the following reasons: + 01-Practice the Tk module to a decent level or mastery. + 02-Make a GUI that could enable Perl newbies to post nodes quicker +without using some of the deprecated tags like <pre> and. =cut
        There's nothing to test. And it's a for-free manpage which you or anyone can view:
        perldoc renderer.pl