source: Dev/branches/rest-dojo-ui/client/dojox/lang/functional/lambda.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

  • Property svn:executable set to *
File size: 4.3 KB
Line 
1define(["../..", "dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array"], function(dojox, dojo, lang, arr){
2        var df = lang.getObject("lang.functional", true, dojox);
3
4// This module adds high-level functions and related constructs:
5//      - anonymous functions built from the string
6
7// Acknoledgements:
8//      - lambda() is based on work by Oliver Steele
9//              (http://osteele.com/sources/javascript/functional/functional.js)
10//              which was published under MIT License
11
12// Notes:
13//      - lambda() produces functions, which after the compilation step are
14//              as fast as regular JS functions (at least theoretically).
15
16// Lambda input values:
17//      - returns functions unchanged
18//      - converts strings to functions
19//      - converts arrays to a functional composition
20
21        var lcache = {};
22
23        // split() is augmented on IE6 to ensure the uniform behavior
24        var split = "ab".split(/a*/).length > 1 ? String.prototype.split :
25                        function(sep){
26                                 var r = this.split.call(this, sep),
27                                         m = sep.exec(this);
28                                 if(m && m.index == 0){ r.unshift(""); }
29                                 return r;
30                        };
31                       
32        var lambda = function(/*String*/ s){
33                var args = [], sects = split.call(s, /\s*->\s*/m);
34                if(sects.length > 1){
35                        while(sects.length){
36                                s = sects.pop();
37                                args = sects.pop().split(/\s*,\s*|\s+/m);
38                                if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); }
39                        }
40                }else if(s.match(/\b_\b/)){
41                        args = ["_"];
42                }else{
43                        var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m),
44                                r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m);
45                        if(l || r){
46                                if(l){
47                                        args.push("$1");
48                                        s = "$1" + s;
49                                }
50                                if(r){
51                                        args.push("$2");
52                                        s = s + "$2";
53                                }
54                        }else{
55                                // the point of the long regex below is to exclude all well-known
56                                // lower-case words from the list of potential arguments
57                                var vars = s.
58                                        replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, "").
59                                        match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {};
60                                arr.forEach(vars, function(v){
61                                        if(!(v in t)){
62                                                args.push(v);
63                                                t[v] = 1;
64                                        }
65                                });
66                        }
67                }
68                return {args: args, body: s};   // Object
69        };
70
71        var compose = function(/*Array*/ a){
72                return a.length ?
73                                        function(){
74                                                var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments);
75                                                for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); }
76                                                return x;
77                                        }
78                                :
79                                        // identity
80                                        function(x){ return x; };
81        };
82
83        lang.mixin(df, {
84                // lambda
85                rawLambda: function(/*String*/ s){
86                        // summary:
87                        //              builds a function from a snippet, or array (composing),
88                        //              returns an object describing the function; functions are
89                        //              passed through unmodified.
90                        // description:
91                        //              This method is to normalize a functional representation (a
92                        //              text snippet) to an object that contains an array of
93                        //              arguments, and a body , which is used to calculate the
94                        //              returning value.
95                        return lambda(s);       // Object
96                },
97                buildLambda: function(/*String*/ s){
98                        // summary:
99                        //              builds a function from a snippet, returns a string, which
100                        //              represents the function.
101                        // description:
102                        //              This method returns a textual representation of a function
103                        //              built from the snippet. It is meant to be evaled in the
104                        //              proper context, so local variables can be pulled from the
105                        //              environment.
106                        s = lambda(s);
107                        return "function(" + s.args.join(",") + "){return (" + s.body + ");}";  // String
108                },
109                lambda: function(/*Function|String|Array*/ s){
110                        // summary:
111                        //              builds a function from a snippet, or array (composing),
112                        //              returns a function object; functions are passed through
113                        //              unmodified.
114                        // description:
115                        //              This method is used to normalize a functional
116                        //              representation (a text snippet, an array, or a function) to
117                        //              a function object.
118                        if(typeof s == "function"){ return s; }
119                        if(s instanceof Array){ return compose(s); }
120                        if(s in lcache){ return lcache[s]; }
121                        s = lambda(s);
122                        return lcache[s] = new Function(s.args, "return (" + s.body + ");");    // Function
123                },
124                clearLambdaCache: function(){
125                        // summary:
126                        //              clears internal cache of lambdas
127                        lcache = {};
128                }
129        });
130       
131        return df;
132});
Note: See TracBrowser for help on using the repository browser.