Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: idioms to reduce logic clutter ?

From: joel:neely:fedex at: 12-Oct-2002 3:55

Jason Cunliffe wrote:
> Time to factor out and simplify the mess... >
Here are some simplification strategies: - use default values, which can trigger default behaviors - use FUNC/RETURN to manage "premature" exits - use long strings - avoid large in-line literals - avoid use-once variables - eliminate dead code <OBSCURENOTE> The phrase foo: either error? [foo: expression] [defaultvalue] [foo] ensures that FOO will either be the result of a successful evaluation or will be the specified default value, as in foo: either error? try [foo: 1 / a] [0] [foo] which will result in FOO containing zero if there's a problem, such as an undefined word
>> a
** Script Error: a has no value ** Near: a
>> foo: either error? try [foo: 1 / a] [0] [foo]
== 0 or an invalid divisor
>> a: 0
== 0
>> foo: either error? try [foo: 1 / a] [0] [foo]
== 0 but will give the desired result if the TRYed expression succeeds
>> a: .5
== 0.5
>> foo: either error? try [foo: 1 / a] [0] [foo]
== 2 </OBSCURENOTE> Now let's apply them in one of many possible ways. (In-line comments followed by sketch of simplified version.)
> ;> ; TEST FOR PASSWORD > ;> > upass: copy "" > loginstatus: false > > either error? try [ > ;condition > upass: cgi-obj/userpass > ][ > ;error > if = upass "" [ > print rejoin [ > {<b>Bad login!</b>} > {no user password provided } > {<a href="upload.html">}{try again}{</a>} > {<br>} > ] > ] > quit
It appears that QUIT really means "I've finished assembling my reply page." The following IF expression appears to be dead code, as it follows a QUIT inside the error branch.
> if <> upass "" [ > print rejoin [ > {funny password provided. Please } > {<a href="upload.html">}{try again}{</a>} > {<br>} > ] > ]
Could error on fetching password be treated identically with missing password?
> ][ > ; ok user has submitted a name and password > ; check to see if they match > upass: cgi-obj/userpass > either = upass logindict/:uname > [loginstatus: true] > [loginstatus: false]
The above EITHER expression is just a round-about way of saying loginstatus: upass = logindict/:uname
> if not loginstatus [
... but if this is the only use, why use up a name?
> ;trouble in paradise - help them out.. > print rejoin [ > {<br>Username and password do not match. <br>Please } > {<a href="upload.html">}{try again}{</a>} > {<form method="POST" action="echo-login.r" enctype="multipart/form-data"> > <i>Forgot your login or need to register ? <br> > Please enter your email address here: </i> > <input type="text" name="email_address" value=""/> > <input type="submit" value="send login by email"/> > </form>} > ] > quit > ] > ] >
One approach for using the above hints would look like this: 8<-------- blah_blah_cgi: make object! [ ;; all chunks of message text go here: ;; (embedded whitespace disappears unless wrapped in <pre></pre>) ;; parameterize messages with common structure msg_retry_missing: func [what [string!]] [ rejoin [ {<b>Bad login!</b> no } what { provided.<br /> <a href="upload.html">try again</a>.<br />} ] ] msg_bad_password: {<br>Username and password do not match.<br /> Please <a href="upload.html">try again</a><br /> <form method="POST" action="echo-login.r" enctype="multipart/form-data"> <i>Forgot your login or need to register?<br /> Please enter your email address here: </i><br /> <input type="text" name="email_address" value=""/><br /> <input type="submit" value="send login by email"/> </form>} msg_blah_blah: {...} ;; process form content, return string form_results: func [ a_user [string!] ;; form userID or default (empty string) a_pass [string!] ;; form passwd or default (empty string) ... ;; other form data /local vpass ;; valid password for a_user ][ if empty? a_pass [return msg_retry_mising "user password"] if empty? a_name [return msg_retry_mising "user name"] if any [ empty? vpass: either error? [vpass: logindict/:a_name] [none] [vpass] vpass <> upass ][ return msg_bad_password ] ;; now process validated form content, and return appropriate results ] run: func [] [ ... print form_results either error? [upass: cgi-obj/userpass] [""] [upass] either error? [upass: cgi-obj/username] [""] [upass] ... ... ] ] blah_blah_cgi/run 8<-------- Here are a few benefits: - All of the "boilerplate" messages are grouped together in the source, making it easier to find them, make changes, check for consistent wording, etc... - Separating the management of CGI parameter values/defauts from the processing FUNC makes it easier to build a test harness that calls FORM_RESULTS with a variety of test args and verifies that the result string is appropriate for those args. - Wrapping everything in an object makes it easier to comment out that single last line (evaluating the RUN method) so that you can DO the file in an interactive environment and test the various methods. Once everything is kosher, just uncomment the RUN line at the end. This could be made more sophisticated (e.g. use explicitly DEFAULT_USER , DEFAULT_PASSWORD , and other "magic" values, instead of assuming empty strings), but I hope this is a start in the/a right direction. -jn- -- When a great many people are unable to find work, unemployment results. -- Calvin Coolidge FIX)PUNCTUATION)joel)dot)neely)at)fedex)dot)com