Merge & Storing input validation logic as a custom property
Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller
Merge & Storing input validation logic as a custom property
I'm wanting to store the input validation logic for a field, as a custom property of that field.
For example
- Set the MyTestCondition of field "ABC" to Field "ABC" >=5 then return true else return false (mucking around with quote marks abridged)
- If MyTestCondition of field "ABC" then doOption1 else doOption2
I've been trying (unsuccessfully) to achieve this using LC's Merge function. The last sentence in the dictionary entry for Merge sounded very promising - "It also executes any return statements enclosed in "<?" and "?>", and replaces them by the value returned."
I'd appreciate any advice on:
1) Am I going down a sensible path trying to store validation logic as a custom property of a field, or should I just give up and go down the (in the short term MUCH easier) path of storing validation logic in scripts that are activated using the field name?
2) If "Storing validation logic as a custom property is a genius plan" - Am I on a sensible path trying to achieve this using the Merge function, or are there easier ways to achieve the same?
3) If "Merge is the only function that you'll ever need" - Please send me some examples of how I would construct a Merge statement to test the value of a field.
The furthest that I've got so far is -
Put "<? if field " & quote & "ABC" & quote & " >= 5 then return true else return false ?>" into tTest
Answer merge(tTest)
But this is always returning false regardless of the value of field "ABC".
Can <? ?> and [[]] be mixed within a single Merge statement?
This does work - Answer merge("<? if 6 >= 5 then return true else return false ?>")
But this doesn't work - Answer merge("<? if [[4+2]] >= 5 then return true else return false ?>")
Sorry, but, other than a 2008 issue of RevUp, Google has revealed very few examples of LC's merge function.
Thanks in advance
Kim
For example
- Set the MyTestCondition of field "ABC" to Field "ABC" >=5 then return true else return false (mucking around with quote marks abridged)
- If MyTestCondition of field "ABC" then doOption1 else doOption2
I've been trying (unsuccessfully) to achieve this using LC's Merge function. The last sentence in the dictionary entry for Merge sounded very promising - "It also executes any return statements enclosed in "<?" and "?>", and replaces them by the value returned."
I'd appreciate any advice on:
1) Am I going down a sensible path trying to store validation logic as a custom property of a field, or should I just give up and go down the (in the short term MUCH easier) path of storing validation logic in scripts that are activated using the field name?
2) If "Storing validation logic as a custom property is a genius plan" - Am I on a sensible path trying to achieve this using the Merge function, or are there easier ways to achieve the same?
3) If "Merge is the only function that you'll ever need" - Please send me some examples of how I would construct a Merge statement to test the value of a field.
The furthest that I've got so far is -
Put "<? if field " & quote & "ABC" & quote & " >= 5 then return true else return false ?>" into tTest
Answer merge(tTest)
But this is always returning false regardless of the value of field "ABC".
Can <? ?> and [[]] be mixed within a single Merge statement?
This does work - Answer merge("<? if 6 >= 5 then return true else return false ?>")
But this doesn't work - Answer merge("<? if [[4+2]] >= 5 then return true else return false ?>")
Sorry, but, other than a 2008 issue of RevUp, Google has revealed very few examples of LC's merge function.
Thanks in advance
Kim
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
What made you choose the "merge" command in the first place? It is compact and powerful, to be sure, but what made you think it would be a good fit?
So as it reads, this sets the custom property to either true or false, depending on the text in fld "ABC". What beyond that did you want to do? I am not trying to put a damper on anything, but I have always found that simpler is better, more robust, easier to read later, easier to manage, and, er, that may be enough. If you have a "true" in the custom property. do you need a hand in using it later on?
In other words, can you give an example beyond the above where you find yourself with poor tools? Tell me what in the simple line of code above is missing.
The "merge" command is NOT the only thing you need. It may well be, for quite a while, that you do not need it at all. You need the ordinary stuff.
Craig Newman
Code: Select all
Set the MyTestCondition of field "ABC" to Field "ABC" >=5
In other words, can you give an example beyond the above where you find yourself with poor tools? Tell me what in the simple line of code above is missing.
The "merge" command is NOT the only thing you need. It may well be, for quite a while, that you do not need it at all. You need the ordinary stuff.
Craig Newman
Re: Merge & Storing input validation logic as a custom property
Hi Craig
Thanks for your reply.
What I want to do is store field validation logic in the field (and not in script). To this end - I want to
(1) store the CONDITION component of an IF statement as a custom property of the field. I want to store the text of the condition (e.g. ">=5"), not the result of that test (e.g. "true"); then
(2) evaluate this custom property within an IF statement.
I saw the last sentence of the Merge function dictionary entry and thought "that sounds like what I'm after", but I may have been on entirely the wrong track. I've since seen the Value function and wondered if that would do it. Or maybe Do does it
Regards
Kim
Thanks for your reply.
What I want to do is store field validation logic in the field (and not in script). To this end - I want to
(1) store the CONDITION component of an IF statement as a custom property of the field. I want to store the text of the condition (e.g. ">=5"), not the result of that test (e.g. "true"); then
(2) evaluate this custom property within an IF statement.
I saw the last sentence of the Merge function dictionary entry and thought "that sounds like what I'm after", but I may have been on entirely the wrong track. I've since seen the Value function and wondered if that would do it. Or maybe Do does it
Regards
Kim
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
Kim.
They all do something, oftentimes, with a little tweaking, the same thing.
So you want to store ">=5" as a string, but use that later to create a conditional of some kind, that will validate some statement. Try this, just to make sure I see what you mean. On a new card make a button and two fields. In fld 1 put "<=5". In the button script:
Something like that? And there is no question you could do this with "merge", so I see where you were coming from.
Craig
They all do something, oftentimes, with a little tweaking, the same thing.
So you want to store ">=5" as a string, but use that later to create a conditional of some kind, that will validate some statement. Try this, just to make sure I see what you mean. On a new card make a button and two fields. In fld 1 put "<=5". In the button script:
Code: Select all
on mouseUp
put "" into fld 2 --just to see it change
ask "enter a number"
do "if" && it && field 1 && "then put Higher into fld 2"
end mouseUp
Craig
Last edited by dunbarx on Wed Apr 17, 2019 4:26 am, edited 1 time in total.
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
In fooling around with Kim's post, I tried this:
Not much different than the "do" statement in the post above, and it seems that this ought to do what it purports, but instead throws an error. Anyone see where I made a syntax error? I cannot find it.
Craig
Code: Select all
on mouseUp
put "" into fld 2
ask "enter a number"
do "if" && it && field 1 && "then put Higher into fld 2 else put Lower into fld 2"
end mouseUp
Craig
-
- VIP Livecode Opensource Backer
- Posts: 9856
- Joined: Sat Apr 08, 2006 7:05 am
- Location: Los Angeles
- Contact:
Re: Merge & Storing input validation logic as a custom property
Kim, do you want to run the validation on keyDown, closeField, or something else?
Side note: Merge is so useful in so many contexts that I can appreciate your choice to explore it here. I'm with Craig on this, that this particular exercise isn't the best fit for that. But super kudos for such inventive thinking. Seriously, I wouldn't have thought of merge here, but I can imagine other contexts where it would be useful for ad hoc evaluation of code snippets. Well done.
When we learn how you want to trigger this we can explore a more concise method. But yes, putting formatting parameters in a custom property is an excellent choice here, even if not merge-compatibile specifically. It's akin to CSS attributes, so your thinking is in line with designers of some of the best such systems around.
Side note: Merge is so useful in so many contexts that I can appreciate your choice to explore it here. I'm with Craig on this, that this particular exercise isn't the best fit for that. But super kudos for such inventive thinking. Seriously, I wouldn't have thought of merge here, but I can imagine other contexts where it would be useful for ad hoc evaluation of code snippets. Well done.
When we learn how you want to trigger this we can explore a more concise method. But yes, putting formatting parameters in a custom property is an excellent choice here, even if not merge-compatibile specifically. It's akin to CSS attributes, so your thinking is in line with designers of some of the best such systems around.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
Kim.
All this doing and merging is very instructional, and terrific practice at making LC do your bidding.
But I strongly suggest you rethink your methodology. The road you are on is harder than it has to be. How might you simplify your thinking, so you can simplify your coding?
Craig
All this doing and merging is very instructional, and terrific practice at making LC do your bidding.
But I strongly suggest you rethink your methodology. The road you are on is harder than it has to be. How might you simplify your thinking, so you can simplify your coding?
Craig
Re: Merge & Storing input validation logic as a custom property
Thanks Craig and Richard.
Yes - the evaluation of the IF statement, which will test the CONDITION that I store as a custom property, is triggered by the user exiting the field.
I'll have another try with this over the next couple of days and get back to you with the results. As you have rightly guessed, part of the reason why I've chosen this approach is to try and teach myself a new aspect of LC. I realise that there are much much easier ways to achieve the same if I store the validation logic in script instead of as a custom property.
Regards
Kim
Yes - the evaluation of the IF statement, which will test the CONDITION that I store as a custom property, is triggered by the user exiting the field.
I'll have another try with this over the next couple of days and get back to you with the results. As you have rightly guessed, part of the reason why I've chosen this approach is to try and teach myself a new aspect of LC. I realise that there are much much easier ways to achieve the same if I store the validation logic in script instead of as a custom property.
Regards
Kim
Re: Merge & Storing input validation logic as a custom property
Hi,
try this:
try this:
- Choose your field, give it a custom property "cCondition".
- Put a condition in, here as a simple example:
Code: Select all
is a number
- Put the evaluation code into the field script:
Code: Select all
on closeField if the controlkey is down then \ exit closeField -- just for safety, to avoid modal loops ... focus on fld "next_fld" -- Important: Move the focus away from this field! do "get " & (me && the cCondition of me) -- Evaluate the condition if it then -- Condition met: wait 0 with messages -- = "Do nothing!" -- answer "Condition met!" -- or say something ... else -- Condition not met: answer "Condition not met!" -- Complain! end if pass closeField end closeField
- Enjoy! Each time a new wrong value is entered the field complains! :)
- You want to use "closeField", that's sent when the user leaves the field AND its content has changed.
Beware not to create a "modal loop" where you have one answer box after the other - thus we focus out (to the next field in the UI) at the beginning of the handler.
. - It's quite useful to have a placeholder in cCondition. This allows for more sophisticated conditions:
(We want a numeric value between 1 and 99 in the field. The fields content is, seen from the field script, simply "me". Then we add double square brackets (= "[[me]]") so we can use it conveniently in merge())
Code: Select all
([[me]] is a number) and ([[me]] > 0) and ([[me]] < 100)
For sure, you'll have to change the field script - replace these 2 lines:with:Code: Select all
do "get " & (me && the cCondition of me) -- Evaluate the condition if it then -- Condition met:
We greatly enhanced the capabilities of our script, even found reason to use "merge", and, best of all, saved 1 precious line of code ;-)))Code: Select all
if merge("[[" & merge(the cCondition of me) & "]]") then -- Test it:
. - I'm using merge here in 2 ways - the inner merge replaces the placeholders, the outer merge evaluates the resulting expression. Regarding the "<? ?>" notation, I searched & tested, but found nothing I could really comprehend. Anybody cares explaining?
All code published by me here was created with Community Editions of LC (thus is GPLv3).
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
If you are exploring the sort of thing Axwald presented, to exercise LC for fun and profit, then go for it.
Otherwise I still suggest, and this also will exercise LC, to do what you intend differently. You call this "storing the validation logic in a script". I call it rethinking.
In other words, what is the advantage of storing an expression, and then building another expression that incorporates the first one? All this to test a certain condition. Why not just use an expression? And yes, all that would live in a handler, though values, not conditionals, might well live in a custom property.
Can you give an example, perhaps in pseudoCode, where your current idea is better?
Craig
Otherwise I still suggest, and this also will exercise LC, to do what you intend differently. You call this "storing the validation logic in a script". I call it rethinking.
In other words, what is the advantage of storing an expression, and then building another expression that incorporates the first one? All this to test a certain condition. Why not just use an expression? And yes, all that would live in a handler, though values, not conditionals, might well live in a custom property.
Can you give an example, perhaps in pseudoCode, where your current idea is better?
Craig
Re: Merge & Storing input validation logic as a custom property
Hi,
Reason: Too often I had to roll out an update when only one slightly different SQL string was required.
(I'm writing database frontends that basically do what a CRM can do too, just my solutions live besides such one, and vastly extend & improve its often limited & bothersome capabilities. So my typical project contains 1 standalone (acts mainly as main menu), and a varying number of "module stacks" that each has its own task. And most these tasks is done displaying data from a db, modifying it, and writing it back. Mucho SQL!)
Solution: There's now a tiny section in my startup process that looks for a certain file "[ApplicationName].cPrp". If such exists, it reads the first 3 bytes of it, and when these are not a special signature (meaning "done already" ...), reads all, decrypts it, decodes the contained nested array & overwrites all the cProps of all the stacks that have entries within, and saves the affected stacks.
Finally, it writes the data back to the file, with the above mentioned 3 byte signature for "done already" in front. So that it doesn't do the same again at next startup.
That's a very easy thing & runs w/o any noticeable startup time penalty.
Now I can, if required, email such a file to a special user for a quick field test. Or I can have now identical stacks for different customers, with different databases.
Bonus: I wrote a tool to handle this, and to create the "[ApplicationName].cPrp's. Since I have all my SQL-containing cProps named wisely I can now quickly create a file with all SQL strings in all stacks in a whole project folder.
This I can save as a plaintext file (and import again) too - so now I can quickly find where the hell I have used this field, or that other. Or where I call this stored procedure, or that view that I'm about to change.
With search & replace. Without having to run a full grep over all the project & editing each single stack ...
This stuff is, in my view, not exactly "programmatic logic", it's just strings that are prone to change.
Like Kim's condition statement, like text strings shown in error messages that may need to be localized one day, like version numbers etc.
Having these hardcoded doesn't save me much work while developing, if any - but it has a heavy cost in the maintenance of a larger project.
Back in the good old days I'd have saved such stuff in the resource fork of my stacks, but since such got steved, well, cProps are a nice replacement.
Have fun!
I just recently (while refactoring) moved all my SQL strings into custom properties. And use them now with a system similar to the one described.
Reason: Too often I had to roll out an update when only one slightly different SQL string was required.
(I'm writing database frontends that basically do what a CRM can do too, just my solutions live besides such one, and vastly extend & improve its often limited & bothersome capabilities. So my typical project contains 1 standalone (acts mainly as main menu), and a varying number of "module stacks" that each has its own task. And most these tasks is done displaying data from a db, modifying it, and writing it back. Mucho SQL!)
Solution: There's now a tiny section in my startup process that looks for a certain file "[ApplicationName].cPrp". If such exists, it reads the first 3 bytes of it, and when these are not a special signature (meaning "done already" ...), reads all, decrypts it, decodes the contained nested array & overwrites all the cProps of all the stacks that have entries within, and saves the affected stacks.
Finally, it writes the data back to the file, with the above mentioned 3 byte signature for "done already" in front. So that it doesn't do the same again at next startup.
That's a very easy thing & runs w/o any noticeable startup time penalty.
Now I can, if required, email such a file to a special user for a quick field test. Or I can have now identical stacks for different customers, with different databases.
Bonus: I wrote a tool to handle this, and to create the "[ApplicationName].cPrp's. Since I have all my SQL-containing cProps named wisely I can now quickly create a file with all SQL strings in all stacks in a whole project folder.
This I can save as a plaintext file (and import again) too - so now I can quickly find where the hell I have used this field, or that other. Or where I call this stored procedure, or that view that I'm about to change.
With search & replace. Without having to run a full grep over all the project & editing each single stack ...
This stuff is, in my view, not exactly "programmatic logic", it's just strings that are prone to change.
Like Kim's condition statement, like text strings shown in error messages that may need to be localized one day, like version numbers etc.
Having these hardcoded doesn't save me much work while developing, if any - but it has a heavy cost in the maintenance of a larger project.
Back in the good old days I'd have saved such stuff in the resource fork of my stacks, but since such got steved, well, cProps are a nice replacement.
Have fun!
All code published by me here was created with Community Editions of LC (thus is GPLv3).
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!
If you use it in closed source projects, or for the Apple AppStore, or with XCode
you'll violate some license terms - read your relevant EULAs & Licenses!
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
Kim.
Axwald has made a case, and nicely. Let us know how you get on...
Craig
Axwald has made a case, and nicely. Let us know how you get on...
Craig
-
- VIP Livecode Opensource Backer
- Posts: 9856
- Joined: Sat Apr 08, 2006 7:05 am
- Location: Los Angeles
- Contact:
Re: Merge & Storing input validation logic as a custom property
Generalization.
With form input validation specifically, consider the beautifully simple way HTML handles such things:
Code: Select all
<input type="number" name="quantity" min="1" max="5">
With a library checking closefield and possibly other messages, it wouldn't be too hard to have delishiously sparse custom property values defining at least the range of evaluations HTML supports.
For example, if the library sees the existence of custom properties valChecker["min"] and valChecker["max"] it would know to limit inputs to only numbers within that range, and dispatch a message to the target if outside that range so the target object can take whatever action might be appropriate for its context.
For any object not containing a valChecker property set the closeField message would just be passed, so it would have no adverse effect on anything else.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
-
- VIP Livecode Opensource Backer
- Posts: 9751
- Joined: Wed May 06, 2009 2:28 pm
- Location: New York, NY
Re: Merge & Storing input validation logic as a custom property
Kim.
Lots of stuff.
I still would love to see a (OK if pseudo) typical case that you want to validate. Then we can fool around with various solutions and methods.
Craig
Lots of stuff.
I still would love to see a (OK if pseudo) typical case that you want to validate. Then we can fool around with various solutions and methods.
Craig
Re: Merge & Storing input validation logic as a custom property
Thanks all
To answer your questions about "why". I'm building an e-forms app (for my first paying client). Up until a week ago all of my data validation only considered the single field being entered.
1) I stored validation logic in as a custom property of the field. For example -
Set the ValRule1 of this field to "GreaterThanOrEqualTo,5"
2) Then I have a repeat loop handler, triggered by exit field
Repeat for each xRule in the ValRule1 of this field
Switch item 1 of xRule
Case "GreaterThanOrEqualTo"
If this field >= item 2 of xRule then
etc
It all worked fine, it was nicely self documenting, and it was easy to maintain, and if I copied and renamed a field then I didn't need to do anything to get the input validation working. Then a week ago my client came up with a requirement to validate field A based on the contents of field B. Of course they did. It would have taken me 10 minutes to write this as a handler, but I like my "store validation logic as a custom property of the field" model, so I thought that I'd put the effort into incorporating this new requirement into my existing CP based model. At first I looked at storing the name of field B, the break points for field B values, the break points for Field A values; all as items in my Custom property. It would have been a bit ugly, but I could probably have implemented this variant in 30 minutes.
Then I thought - "If LC could store the CONDITION part of an IF statement as a custom property, then I'd have a very flexible nicely self documenting implementation". And the next thing that I knew I was down the "storing code as data" rabbit hole.
I'm justifying this on the basis of (1) it's future proofing, and (2) Its a good LC learning experience; but the next thing after this on my to-do list after this is "deploy to Apple", and I've never enjoyed wading through the Apple treakle, so can probably add (3) Postpone the task that I'm not looking forward to
My actual need is - If field A = 90 and field B > 0 then "Fail" else "Pass"
It's a validation of a latitude, where the user has the option of entering the latitude as either decimal degrees or degrees & minutes. This will trigger on exiting either Field A or Field B (the trigger handler is already written / working). So the part that I want to store as a Custom Property is "field A = 90 and field B > 0".
Regards
Kim
To answer your questions about "why". I'm building an e-forms app (for my first paying client). Up until a week ago all of my data validation only considered the single field being entered.
1) I stored validation logic in as a custom property of the field. For example -
Set the ValRule1 of this field to "GreaterThanOrEqualTo,5"
2) Then I have a repeat loop handler, triggered by exit field
Repeat for each xRule in the ValRule1 of this field
Switch item 1 of xRule
Case "GreaterThanOrEqualTo"
If this field >= item 2 of xRule then
etc
It all worked fine, it was nicely self documenting, and it was easy to maintain, and if I copied and renamed a field then I didn't need to do anything to get the input validation working. Then a week ago my client came up with a requirement to validate field A based on the contents of field B. Of course they did. It would have taken me 10 minutes to write this as a handler, but I like my "store validation logic as a custom property of the field" model, so I thought that I'd put the effort into incorporating this new requirement into my existing CP based model. At first I looked at storing the name of field B, the break points for field B values, the break points for Field A values; all as items in my Custom property. It would have been a bit ugly, but I could probably have implemented this variant in 30 minutes.
Then I thought - "If LC could store the CONDITION part of an IF statement as a custom property, then I'd have a very flexible nicely self documenting implementation". And the next thing that I knew I was down the "storing code as data" rabbit hole.
I'm justifying this on the basis of (1) it's future proofing, and (2) Its a good LC learning experience; but the next thing after this on my to-do list after this is "deploy to Apple", and I've never enjoyed wading through the Apple treakle, so can probably add (3) Postpone the task that I'm not looking forward to
My actual need is - If field A = 90 and field B > 0 then "Fail" else "Pass"
It's a validation of a latitude, where the user has the option of entering the latitude as either decimal degrees or degrees & minutes. This will trigger on exiting either Field A or Field B (the trigger handler is already written / working). So the part that I want to store as a Custom Property is "field A = 90 and field B > 0".
Regards
Kim