Commits

Anonymous committed 6989bb4

move JS code out of -defines and into .js files

greatly improves readability

JS files are read during application startup, and storing in
the application environment under properties named after their filenames

Comments (0)

Files changed (7)

apps/wriaki/priv/mapred/search_map.js

+// This function is used as the map phase implementation for
+// searching article text
+// Each element in the result should be a structure of
+// {
+//   key: (string), // key of the Riak object for the article
+//   ranges: [ (string) ], // list of matching phrases
+// }
+function(v, d) {
+    // always want the key in the result
+    var result = {key: v.key};
+
+    // if the object was found, and we have word position info
+    if (v.values && v.values[0] && d.p) {
+        // sort positions
+        d.p.sort();
+
+        // create a list of start/end position pairs that attempt
+        // to group "close" positions (within 5 words) together
+        result.ranges=[{start: d.p[0], end: d.p[0]}];
+        for (var i = 1; i < d.p.length; i++) {
+            if (result.ranges[result.ranges.length-1].end-d.p[i] < 5)
+                result.ranges[result.ranges.length-1].end = d.p[i];
+            else
+                result.ranges[result.ranges.length] =
+                {start: d.p[i], end: d.p[i]};
+        }
+
+        // extract the phrases from the text
+        var text = JSON.parse(v.values[0].data).text;
+        var words = text.match(/[a-z0-9\u80-\uff]*/g).filter(
+            function(s) { return s != ""; }).length
+
+        for (var i = 0; i < result.ranges.length; i++) {
+            var s = result.ranges[i].start < 5 ?
+                0 : result.ranges[i].start-5;
+            var e = result.ranges[i].end+5 > words ?
+                words : result.ranges[i].end+5;
+
+            // regexp is basically "match START words, then grab everything
+            // until WORDS-END words from the end"
+            var match = (new RegExp(
+                "(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){"+s+"}"+
+                "(.*)[^a-z0-9\u80-\uff]"+
+                "(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){"+(words-e)+"}"))
+                .exec(text);
+            result.ranges[i] = match[1];
+        }
+    }
+
+    return [result];
+}

apps/wriaki/priv/mapred/summary_map.js

+// This function is used as the map phase implementation for
+// extracting summary data from archives for history production
+// Each element in the result should be a structure of
+// {
+//   version: (string),    // the hash version of the revision
+//   timestamp: (integer), // the time of the revision
+//   message: (string),    // the commit message
+//   editor: (string),     // the username of the editor
+// }
+function(v) {
+    var json = JSON.parse(v.values[0].data);
+    var summary = {
+        version: json.version,
+        timestamp: json.timestamp,
+        message: json.message,
+    };
+    var links = v.values[0].metadata.Links;
+    for(var i in links) {
+        if (links[i][2] == "editor") {
+            summary.editor = links[i][1];
+        }
+    }
+    return [summary];
+}

apps/wriaki/priv/mapred/time_order_reduce.js

+// This function is used as the reduce phase implementation for
+// ordering/paging archives in the history view (TODO)
+function(v) {
+    return v.sort(
+        function(a,b) { return b[2]-a[2]; }
+    );
+}

apps/wriaki/src/article_history.erl

                 Acc,
                 wobj:get_links(Obj)).
 
--define(TIME_ORDER,
-        iolist_to_binary(
-          [<<"function(v) {\n">>,
-           <<"return v.sort(\n">>,
-           <<"function(a,b) { return b[2]-a[2]; }\n">>,
-           <<"); }">>])).
-
--define(SUMMARY_EXTRACTION,
-        iolist_to_binary(
-          [<<"function(v) {\n">>,
-           <<"var json = JSON.parse(v.values[0].data);\n">>,
-           <<"var summary = {\n">>,
-           <<"version: json.version,\n">>,
-           <<"timestamp: json.timestamp,\n">>,
-           <<"message: json.message,\n">>,
-           <<"};\n">>,
-           <<"var links = v.values[0].metadata.Links;\n">>,
-           <<"for(var i in links) {\n">>,
-           <<"if (links[i][2] == \"editor\") {\n">>,
-           <<"summary.editor = links[i][1];\n">>,
-           <<"}\n">>,
-           <<"}\n">>,
-           <<"return [summary];\n">>,
-           <<"}">>])).
-
 get_version_summaries(ArticleKey) ->
     {ok, Client} = wrc:connect(),
     {ok, [{1, Results}]} = 
         wrc:mapred(Client,
                    [{?B_HISTORY, ArticleKey}],
                    [{link, <<"archive">>, '_', false},
-%%%{reduce, {jsanon, ?TIME_ORDER}, <<>>, false}, %TODO: paging
-                    {map, {jsanon, ?SUMMARY_EXTRACTION}, <<>>, true}]),
+%%%{reduce, {jsanon, time_order_fun()}, <<>>, false}, %TODO: paging
+                    {map, {jsanon, summary_fun()}, <<>>, true}]),
     {ok, Results}.
+
+%% code for summary map phase is in priv/mapred/summary_map.js
+summary_fun() ->
+    wriaki:get_app_env(summary_map,
+                       <<"function() { return []; }">>).
+
+%% code for time order reduce phase is in priv/mapred/time_order_reduce.js
+time_order_fun() ->
+    wriaki:get_app_env(time_order_reduce,
+                       <<"function(v) { return v; }">>).

apps/wriaki/src/wiki_resource.erl

                                     {results, Results}]),
     {C, RD, Ctx}.
 
--define(SEARCH_FUN,
-        iolist_to_binary(
-          [<<"function(v, d) {\n">>,
-
-           %% always want the key in the result
-           <<"var result = {key: v.key};\n">>,
-
-           %% if the object was found, and we have word position info
-           <<"if (v.values && v.values[0] && d.p) {\n">>,
-
-           %% sort positions
-           <<"d.p.sort();\n">>,
-
-           %% create a list of start/end position pairs that attempt
-           %% to group "close" positions (within 5 words) together
-           <<"result.ranges=[{start: d.p[0], end: d.p[0]}];\n">>,
-           <<"for (var i = 1; i < d.p.length; i++) {\n">>,
-           <<"if (result.ranges[result.ranges.length-1].end-d.p[i] < 5)\n">>,
-           <<"result.ranges[result.ranges.length-1].end = d.p[i];\n">>,
-           <<"else\n">>,
-           <<"result.ranges[result.ranges.length] = {start: d.p[i], end: d.p[i]};\n">>,
-           <<"}\n">>,
-
-           %% extract the phrases from the text
-           <<"var text = JSON.parse(v.values[0].data).text;\n">>,
-           <<"var words = text.match(/[a-z0-9\u80-\uff]*/g).filter(function(s) { return s != \"\"; }).length\n">>,
-
-           <<"for (var i = 0; i < result.ranges.length; i++) {\n">>,
-           <<"var s = result.ranges[i].start < 5 ? 0 : result.ranges[i].start-5;\n">>,
-           <<"var e = result.ranges[i].end+5 > words ? words : result.ranges[i].end+5;\n">>,
-           %% regexp is basically "match START words, then grab everything
-           %% until WORDS-END words from the end"
-           <<"var match = (new RegExp(\"(?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){\"+s+\"}(.*)[^a-z0-9\u80-\uff](?:[a-z0-9\u80-\uff]+[^a-z0-9\u80-\uff]+){\"+(words-e)+\"}\")).exec(text);\n">>,
-           <<"result.ranges[i] = match[1];\n">>,
-           <<"}\n">>,
-
-           <<"}\n">>, % end of if values & positions
-
-           <<"return [result];\n">>,
-           <<"}">>])).
-
 search(Client, RawSearch) ->
     case wriaki:search_enabled() of
         true ->
                 wrc:mapred(Client,
                            {modfun, riak_search, mapred_search,
                             [<<"article">>, iolist_to_binary(Search)]},
-                           [{map, {jsanon, ?SEARCH_FUN}, <<>>, true}]),
+                           [{map, {jsanon, search_fun()}, <<>>, true}]),
             case RawResults of
                 [{0, Results}] ->
                     [ [{title, base64url:decode(
             []
     end.
 
+%% code for search map phase is in priv/mapred/search_map.js
+search_fun() ->
+    wriaki:get_app_env(search_map,
+                       <<"function(v) { return [{key:v.key}]; }">>).
+
 split_search(Search) ->
     Tokens = string:tokens(Search, " "),
     string:join([ [<<"text:">>, T] || T <- Tokens ], " OR ").

apps/wriaki/src/wriaki.erl

 
 -export([set_bucket_props/0,
          search_enabled/0,
+         read_mapred_js/0,
          get_app_env/2]).
 
 -include_lib("wriaki.hrl").
         {ok, Val} -> Val;
         undefined -> Default
     end.
+
+%% Read each file in PRIV/mapred/<filename>.js and set its content
+%% as wriaki application env <filename>
+read_mapred_js() ->
+    Dir = filename:join(code:priv_dir(wriaki), "mapred"),
+    Filenames = filelib:wildcard("*.js", Dir),
+    lists:foreach(
+      fun(Name) ->
+              {ok, Content} = file:read_file(filename:join(Dir, Name)),
+              Atom = list_to_atom(hd(string:tokens(Name, "."))),
+              application:set_env(wriaki, Atom, Content)
+      end,
+      Filenames).

apps/wriaki/src/wriaki_sup.erl

 
 init([]) ->
     wriaki:set_bucket_props(),
+    wriaki:read_mapred_js(),
     
     Ip = wriaki:get_app_env(web_ip, "0.0.0.0"),
     Port = wriaki:get_app_env(web_port, 8000),