diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,20 @@
 # Changelog
 
+### 0.14.2
+
+* Generated JavaScript now also works as a Node module
+* JavaScript constructors are now named properly instead of "constrWrapper"
+* Now generates valid Ruby code again
+
 ### 0.14.1
 
 * Expose modules Rest.Gen.Base.ActionInfo and Rest.Gen.Base.ApiTree
   again.
 * Make test cases compile again.
+
+##### Revisions
+
+* Allow `Cabal == 1.16.*`
 
 ## 0.14
 
diff --git a/files/Javascript/base.js b/files/Javascript/base.js
--- a/files/Javascript/base.js
+++ b/files/Javascript/base.js
@@ -1,63 +1,117 @@
-$apinamespace$ =
+var $apinamespace$ =
   function (url, secureUrl)
   {
     var postfix = '/v' + this.version + '/';
     var sUrl = url + postfix;
     $apinamespace$.setContext(this, sUrl);
-    this.contextUrl = sUrl;
     this.secureContextUrl = (secureUrl || url.replace(/^http:/, "https:")) + postfix;
   };
-$apinamespace$.addObject =
-  function (obj1, obj2)
+
+if (typeof module === "object" && module && typeof module.exports === "object")
+{
+  // Export as Node module.
+  module.exports = $apinamespace$;
+
+  $apinamespace$.ajaxCall = nodeRequest;
+}
+else
+{
+  if (typeof define === "function" && define.amd)
+    // Export as AMD.
+    define("$apinamespace$", [], function () { return $apinamespace$; });
+
+  else
+    // Export as global.
+    window.$apinamespace$ = $apinamespace$;
+
+  $apinamespace$.ajaxCall = jQueryRequest;
+}
+
+$apinamespace$.addObject = function (obj1, obj2)
+{
+  for (var fld in obj2)
+    obj1[fld] = obj2[fld];
+};
+
+$apinamespace$.defaultAjaxOptions = {};
+
+function jQueryRequest (method, url, params, success, error, contentType, dataType, data, callOpts)
+{
+  var callData =
+    { type: method
+    , url: url + (params ? '?' + $dollar$.param(params) : '')
+    , cache: false
+    , success: success || function () {}
+    , error: error || function () {}
+    , contentType: contentType
+    , dataType: dataType
+    , xhrFields: { withCredentials: true }
+    , data: data || []
+    };
+
+  $apinamespace$.addObject(callData, $apinamespace$.defaultAjaxOptions);
+  $apinamespace$.addObject(callData, callOpts);
+
+  return $dollar$.ajax(callData);
+}
+
+function nodeRequest (method, url, params, onSuccess, onError, contentType, dataType, data, callOpts)
+{
+  var allParams = {};
+  $apinamespace$.addObject(allParams, params);
+
+  if (method === "GET" || method === "HEAD")
+    // Avoid cached API responses.
+    allParams._ = Date.now();
+
+  var headers = { "Content-type": contentType };
+
+  if (dataType === 'json')
+    headers.Accept = 'text/json';
+  else if (dataType === 'xml')
+    headers.Accept = 'text/xml';
+
+  var callData =
+    { url     : url
+    , qs      : allParams
+    , method  : method
+    , headers : headers
+    };
+
+  if (data) callData.body = data;
+
+  $apinamespace$.addObject(callData, $apinamespace$.defaultAjaxOptions);
+  $apinamespace$.addObject(callData, callOpts);
+
+  return require("request")(callData, callback);
+
+  function callback (error, message, response)
   {
-    for (var fld in obj2)
-    {
-      obj1[fld] = obj2[fld];
-    }
-  };
-$apinamespace$.ajaxCall =
-  function (method, url, params, success, error, contentType, dataType, data, callOpts)
+    var parsedResponse = parse(response);
+    if (message.statusCode >= 200 && message.statusCode < 300)
+      onSuccess && onSuccess(parsedResponse, message);
+    else if (onError)
+      onError(error, parsedResponse, message);
+  }
+
+  function parse (response)
   {
-    var callData =
-      { type: method
-      , url: url + (params ? '?' + $dollar$.param(params) : '')
-      , cache: false
-      , success: success || function () {}
-      , error: error || function () {}
-      , contentType: contentType
-      , dataType: dataType
-      , xhrFields: { withCredentials: true }
-      , data: data || []
-      };
-    $apinamespace$.addObject(callData, callOpts);
-    return $dollar$.ajax(callData);
-  };
+    if (dataType === 'json')
+      return JSON.parse(response);
+    else return response;
+  }
+}
+
 $apinamespace$.setContext =
   function (obj, url)
   {
+    obj.contextUrl = url;
     for (var fld in obj)
     {
       if (obj[fld] != undefined && obj[fld].apiObjectType != undefined && obj[fld].apiObjectType == 'resourceDir')
       {
         var newUrl = url + fld.replace(/([a-z0-9])([A-Z])/g, '$dollar$1-$dollar$2').toLowerCase() + '/'
         $apinamespace$.setContext(obj[fld], newUrl);
-        obj[fld].contextUrl = newUrl;
       }
     }
-  };
-$apinamespace$.makeSilkConstructor =
-  function ()
-  {
-    return function constrWrapper (url)
-           {
-             if (this instanceof constrWrapper)
-             {
-               $apinamespace$.setContext(this, url);
-               this.contextUrl = url;
-             }
-             else
-             {
-               return constrWrapper.access(url);
-             }
-           };
   };
diff --git a/rest-gen.cabal b/rest-gen.cabal
--- a/rest-gen.cabal
+++ b/rest-gen.cabal
@@ -1,5 +1,5 @@
 name:                rest-gen
-version:             0.14.1
+version:             0.14.2
 description:         Documentation and client generation from rest definition.
 synopsis:            Documentation and client generation from rest definition.
 maintainer:          code@silk.co
@@ -48,7 +48,7 @@
     Rest.Gen.Utils
   build-depends:
       base >= 4.5 && < 4.8
-    , Cabal >= 1.18 && < 1.22
+    , Cabal >= 1.16 && < 1.22
     , HStringTemplate >= 0.6 && < 0.8
     , aeson >= 0.7 && < 0.8
     , blaze-html >= 0.5 && < 0.8
diff --git a/src/Rest/Gen/JavaScript.hs b/src/Rest/Gen/JavaScript.hs
--- a/src/Rest/Gen/JavaScript.hs
+++ b/src/Rest/Gen/JavaScript.hs
@@ -21,9 +21,12 @@
                 [ unModuleName ns ++ ".prototype.version" .=. string (show ver)
                 , mkJsCode (unModuleName ns) priv r
                 ]
-     return $ prelude ++ cod
+     return $ mkJsModule (prelude ++ cod)
   where attrs = [("apinamespace", unModuleName ns), ("dollar", "$")]
 
+mkJsModule :: String -> String
+mkJsModule content = "(function (window) {\n\n" ++ content ++ "\n\n})(this);"
+
 mkJsCode :: String -> Bool -> Router m s -> Code
 mkJsCode ns priv = mkJs ns . sortTree . (if priv then id else noPrivate) . apiSubtrees
 
@@ -33,7 +36,7 @@
 mkRes :: String -> ApiResource -> Code
 mkRes ns node = mkStack $
   [ if hasAccessor node
-      then resourceLoc ns node .=. ns ++ ".makeSilkConstructor()"
+      then resourceLoc ns node .=. mkAccessorConstructor ns node
       else resourceLoc ns node .=. jsObject []
   , resourceLoc ns node ++ ".apiObjectType" .=. string "resourceDir"
   , mkAccessFuncs ns node
@@ -41,6 +44,14 @@
   , mkPostFuncs ns node
   ]
 
+mkAccessorConstructor :: String -> ApiResource -> Code
+mkAccessorConstructor ns resource =
+  let constrName = jsDir (cleanName (resName resource))
+  in functionDecl constrName ["url"] $
+       jsIf (code $ "this instanceof " ++ constrName)
+            (proc (ns ++ ".setContext") (code "this, url"))
+         <-> jsElse (ret $ call (constrName ++ ".access") (code "url"))
+
 mkPreFuncs :: String -> ApiResource -> Code
 mkPreFuncs ns node =
   let items = filter ((\i -> not $ postAction i || isAccessor i) . itemInfo) $ resItems node
@@ -83,7 +94,7 @@
               ++ maybe "" (\i -> "' + encodeURIComponent(" ++ i ++ ") + '/") mIdent
       mIdent   = (if isAccessor ai then const Nothing else id) $ fmap (jsId . cleanName . description) $ ident ai
   in function fParams $ ret $
-        proc (ns ++ "." ++ "ajaxCall")
+        call (ns ++ "." ++ "ajaxCall")
           [ string (method ai)
           , code $ (if (https ai) then "this.secureContextUrl" else "this.contextUrl") ++ " + '" ++ urlPart ++ "'"
           , code "params"
diff --git a/src/Rest/Gen/Ruby.hs b/src/Rest/Gen/Ruby.hs
--- a/src/Rest/Gen/Ruby.hs
+++ b/src/Rest/Gen/Ruby.hs
@@ -3,6 +3,7 @@
 
 import Data.Char
 import Data.List
+import Data.List.Split (splitOn)
 import Data.Maybe
 
 import Code.Build
@@ -17,9 +18,13 @@
 
 mkRbApi :: H.ModuleName -> Bool -> Version -> Router m s -> IO String
 mkRbApi ns priv ver r =
-  do prelude <- readContent "Ruby/base.rb"
+  do rawPrelude <- readContent "Ruby/base.rb"
+     let prelude = replace "SilkApi" (unModuleName ns) rawPrelude
      let cod = showCode . mkRb (unModuleName ns) ver . sortTree . (if priv then id else noPrivate) . apiSubtrees $ r
-     return $ cod ++ prelude
+     return $ cod ++ "\n" ++ prelude
+
+replace :: String -> String -> String -> String
+replace from to = intercalate to . splitOn from
 
 mkRb :: String -> Version -> ApiResource -> Code
 mkRb ns ver node =
