Commits

Bryan Fink  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

  • Participants
  • Parent commits a0bdb59

Comments (0)

Files changed (7)

File 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];
+}

File 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];
+}

File 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]; }
+    );
+}

File 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; }">>).

File 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 ").

File 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).

File 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),