WaterDoc: thing.for_each - a defmethod
Contract a_thing.<for_each include=regular_key returns="last" exclude=optional />
for_each is the most useful looping (iteration) method in Water. > /> my_colors. it./> my_colors The content of for_each is executed once for each element in "_subject". During that execution, "it" is bound to the object whose fields are being looped over "key" is bound to the name of the field within "it" currently being looped over and "value" is bound to the value of that field. "_subject" is bound to "_subject" of the outer environment to the call. Other local variables that are bound before the call to for_each, but in the same lexical scope (such as the same method body) will still be bound each time the body of the for_each is executed. By default the object being looped over is treated as a vector and only its integer fields are looped over starting with field 0 (zero). The "include" argument is usually a method that determines exactly which fields to loop over: The system provides several methods that were made expressly for the value of include: vector_key (the default) Passes the integer-named fields in a vector. This method is handled specially by for_each for performance and to process only those integer fields from 0 to just under the length of the node. system_key Passes fields such as "_parent". Rarely used. meta_key Passes only field names that are strings that contain an _f_ substring. string_key Passes all non_system, non_integer, non-meta_key named fields. regular_key Passes all user fields and all integer-named fields that are non-negative. non_system_key Passes all non_system field keys, thus it passes string_keys, vector_keys, meta_keys, and negative integer fields. return_true Passes all fields. You can write your own methods to include other fields than the above methods allow. The method is called with each key as "_subject". If the method returns false, the field will not be processed, otherwise it will be. _subject.. /> /> . /> If the value of "include" is NOT a method, then it is considered to be a vector of the valid field names to loop over. . returns="all"> value result= /> . returns="all"> value result= /> The exclude parameter, like the include parameter can take a method or a vector. If a field name passed the include test, then it is tested against the exclude parameter. If the field name is either in the exclude vector or the exclude method is called and returns true, then the field name is excluded and not looped over. . > key result= /> Early Return: You can force for_each to exit the loop and return a value by calling within the content of for_each. If you call then the for_each loop will be exited and so will the containing defmethod, which will return "some_value". Normal Return: If for_each does not hit an early return, what it returns depends on the value of the "returns" arguments. "last" (the default) returns the value of the last expression in its content that was executed. "all" returns a vector of the values of all the last expressions from each iteration. "all_except_null" like "all" except nulls are not included in the returned vector. Example: . value. result= /> . value result= /> Beware: Do not loop over the fields of an object that you are changing in the code of the content of a call to for_each. You need to get all of the keys first, then iterate through them and change the object that they came from. You can get the keys via the 'keys' method. Note in the examples below pretend that the call to 'echo' is really code that modifies mything. .. /> but that leaves you with 'value' inside of the for_each bound to the key that you're after. You use this value to get the real value from the object via 'get' like so: . > mything.. /> A more elegant way to accomplish the task is to use the 'include' parameter of for_each and they the key and value variables will be bound as you would expect. > mything.> />