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

idioms to reduce logic clutter ?

 [1/6] from: carl::cybercraft::co::nz at: 12-Oct-2002 23:32


Hi Jason, A quickish answer... Three REBOL words you may not know off that may help...
>> ? any
USAGE: ANY block DESCRIPTION: Shortcut OR. Evaluates and returns the first value that is not FALSE or NONE. ANY is a native value. ARGUMENTS: block -- Block of expressions (Type: block)
>> ? all
USAGE: ALL block DESCRIPTION: Shortcut AND. Evaluates and returns at the first FALSE or NONE. ALL is a native value. ARGUMENTS: block -- Block of expressions (Type: block)
>> ? switch
USAGE: SWITCH value cases /default case DESCRIPTION: Selects a choice and evaluates what follows it. SWITCH is a function value. ARGUMENTS: value -- Value to search for. (Type: any) cases -- Block of cases to search. (Type: block) REFINEMENTS: /default case -- Default case if no others are found. (Type: any) (SPECIAL ATTRIBUTES) throw -- Carl Read

 [2/6] from: gscottjones:mchsi at: 12-Oct-2002 8:35


Hi, Jason, From: "Jason Cunliffe"
> Greetings smart people
Whoops, I guess that rules me out after all. I misread the subject as saying, "Idiots to reduce logic clutter," and I assumed I would be perfect to answer. :-) ...
> Time to factor out and simplify the mess. Need strategic > advice.. or examples of rebol idioms for idioms to keep > manage logic, keep clutter in check, avoid nested 'either > [using 'find perhaps functions, objects..]
... original email: http://www.escribe.com/internet/rebol/m26449.html First, I'll throw in a few comments interspersed in the sample that you submitted to be sure that we are on the same wavelength. ...
> either error? try [ > ;condition > upass: cgi-obj/userpass > ][ > ;error > if = upass "" [
We know that a form GET only returns name-value pairs where a value was supplied. At this point, I assume that cgi-obj contains the name-value pairs returned from a submitted form. What I don't know is whether the cgi-obj starts with defaults for all fields and then fills in the returned values, or is created directly by decoding and parsing the returns. In the former, then a given field will always be present; whereas, in the later case, only fields with return values will be present. Each offers opportunities for compressing the logic. Given that you are assigning upass inside a try block, I am assuming that cgi-obj only contains returned name-value pairs (otherwise an assignment error would "never" occur). If so, then if an error occurs, it is only do to cgi-object not containing the userpass path. Therefore, there may be no reason to check for:
> if <> upass "" [
As an aside, I assume that the quit command was supposed to be the final line in the first if block, otherwise, one would never pass through to the second if.
> ; ok user has submitted a name and password > ; check to see if they match > upass: cgi-obj/userpass
Just a minor point: this assignment is redundant with the one done in the try block. Given what has been presented, I could see the following compressed version as offering similar functionality. Of course, I have no direct way to test it. ;==================================== ; TEST FOR PASSWORD ;==================================== upass: copy "" loginstatus: false either error? try [ ;condition upass: cgi-obj/userpass ][ ;error: userpass must not have existed print rejoin [ {<b>Bad login!</b>} {no user password provided } {<a href="upload.html">}{try again}{</a>} {<br>} ] quit ][ ; ok user has submitted a name and password ; check to see if they match if not loginstatus: equal? upass logindict/:uname [ ;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 ] ] ;if program execution passes through to here, then a valid ; user name and password cobination have been offered ; and loginstatus should now be "true" ; OK to continue with processing ;======================= If this error checking script continues through a number of fields, I would likely encapsulate the error generating code into a function that allows the error issue statement to be passed as a parameter and that offers a refinement switch that allows the user to (re)register if the error warrants. error-page: func [ err-mess [string!] /register ][ print rejoin [ {<br>} err-mess {<br>Please } {<a href="upload.html">}{try again}{</a>} if register [ {<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>} ] ] ] Finally, I agree with Carl R. that 'all is a great way to check that conditions are correct to continue. For example: a: make object! [b: 1] either all [ not error? try [a/b] not error? try [a/c] ] [print 'yep][print 'nope] a: make object! [b: 1 c: 2] either all [ not error? try [a/b] not error? try [a/c] ] [print 'yep][print 'nope] where the various fields of cgi-object could be checked in various ways (including existence in this example). HTH --Scott Jones

 [3/6] 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 > ;>
<<quoted lines omitted: 14>>
> ] > 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 [
<<quoted lines omitted: 3>>
> ] > ]
Could error on fetching password be treated identically with missing password?
> ][ > ; ok user has submitted a name and password
<<quoted lines omitted: 3>>
> [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 [
<<quoted lines omitted: 10>>
> ] > ]
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

 [4/6] from: greggirwin:mindspring at: 12-Oct-2002 10:16


Jason, et al I agree with those who have already replied. Combining the various strategies mentioned will no doubt give you lots of options to play with. Here's a little snippet used in prebol.r from RT. The messages in-line are small, but could be broken out as Joel suggests as well. if not all [ msg: "Missing input file name argument" in-file msg: "Input file not found" exists? in-file msg: "Missing output file name argument" out-file msg: "Input file is not a REBOL file" script? in-file msg: "Cannot load REBOL input file" not error? try [data: load/all in-file] ][ error msg ] --Gregg

 [5/6] from: al:bri:xtra at: 13-Oct-2002 10:42


Jason wrote:
> ;> ; TEST FOR PASSWORD > ;>
<<quoted lines omitted: 21>>
> ] > ]
Notice the duplication here:
> {<a href="upload.html">}{try again}{</a>} > {<br>}
I'd make this into a small function which takes a error message.
> ][ > ; ok user has submitted a name and password
<<quoted lines omitted: 4>>
> [loginstatus: false] > if not loginstatus [
The above is better written as: if not loginstatus: upass = logindict/:uname [ ; etcetera
> ;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>
<<quoted lines omitted: 5>>
> ] > ]
Just a few suggestions. Andrew Martin ICQ: 26227169 http://valley.150m.com/

 [6/6] from: jason:cunliffe:verizon at: 12-Oct-2002 13:38


Gregg, Scott, Joel, Carl et al.. Thanks for all the quick great answers. Lots to absorb.. One thing I love about Rebol is how it lets one develop so quickly. By adding lots of crude code as I did, I was able to understand and explore what the end user requirements were and test them immediately/iteratively. That included all the visible permutations of user input, as well as the implications and back-end functionality to apply to the inputs. Now I really look forwards to rewriting/designing from scratch, using better rebol idioms and strategies such as you have all suggested. With Rebol less is more. ./Jason

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted