Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
JavaScript library to import other JavaScript libraries
branch: master

This branch is 2 commits ahead of openjsan:master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
tests
Build.PL
Changes
MANIFEST
MANIFEST.SKIP
README

README

NAME
    JSAN - JavaScript Archive Network

SYNOPSIS
      <script type="text/javascript" src="/js/JSAN.js"></script>
      <script>
          JSAN.use('Test.Simple');
          plan({tests: 1});
          ok(1 == 1, 'one does equal one!');
      </script>

      // Or in a library.
      try {
          JSAN.use('Some.Library');
      } catch (e) {
          alert("Requires JSAN");
      }

DESCRIPTION
    This library allows JavaScript to behave more like traditional
    programming languages and offers the programmer the abilility to create
    well-designed, modular code.

    */

    var JSAN = function () { JSAN.addRepository(arguments) }

    JSAN.VERSION = 0.09;

    /*

  Class Properties
   globalScope
      JSAN.globalScope = _player;

    By default "globalScope" is set to the value of "self". This works great
    in web browswers, however other environments may not have "self" (an
    alias for "window" in web browswers) for a global context. In those
    cases, such as embedded JavaScript, you should reset "globalScope"
    before calling "use()".

   includePath
      JSAN.includePath = [];

    The "includePath" is a list of URLs that should be used as prefixes for
    libraries when they are "use()"d. If you are adding repositories please
    consider using the "addRepository()" method.

   errorLevel
      JSAN.errorLevel = "die";

    By default the "errorLevel" is set to *none*. This will supress errors
    when trying to load libraries.

    *die* will throw an exception and it is the responsibility of the
    calling code to catch it.

    *warn* will use the "alarm()" function, usually present in web browsers,
    to alert a user on error. This is good for debugging (in web browsers).

   errorMessage
      var error = JSAN.errorMessage;

    This contains the text of any error, no matter what the "errorLevel".
    Inspect it to discover problems.

   loaded
      JSAN.loaded["Foo/Bar.js"] = Foo.Bar;

    This object lists path to class definition mappings. The object is
    populated with members by "JSAN.require()". The class definition is the
    one found when evaluating the package name during namespace creation. It
    is the same class definition that "JSAN.require()" and "JSAN.use()"
    returns.

  Class Methods
   JSAN.use()
        JSAN.use('Test.Simple');
        JSAN.use('DOM.Display');

    Download and import a library. There is a mapping that is done with the
    library name: it must be converted into a URL. Here is how it works.

      Test.Simple        Test/Simple.js
      HTTP.Request       HTTP/Request.js
      Foo.Bar.Baz        Foo/Bar/Baz.js

    Each "includePath" is then prepended, and the file requested, until it
    is found. The first working path in "includePath" is used.

    The library's constructor and prototype are imported into the calling
    context. You can also request certain functions, or groups of functions,
    to be imported explicitly. These groups can be done either singly or in
    an array, whichever is more convenient. You can also explicitly choose
    to import nothing. Here is an example of each.

      // Explicitly choose certain functions
      JSAN.use('Test.More', 'plan', 'ok', 'is');
  
      // Explicitly choose a certain tag
      JSAN.use('Digest.MD5', ':all');

      // Explicitly choose nothing
      JSAN.use('Digest.MD5', []);

      // Be really weird
      var stuff = [ 'h', 'i', ['j'] ];
      stuff.push( 'abc' );
      JSAN.use('Some.Module', 'a', 'b', [ 'c', 'd' ], stuff, 'f' );

   JSAN.require()
      JSAN.require('Some.Class');

    Loads a class into your scope. This will not export any symbols.

   JSAN.exporter()
      JSAN.exporter(Test.More, 'plan', 'is', 'cmpOk');

    Export symbols from the class defined in the first argument to the
    global scope. Note that the first argument to "JSAN.exporter()" is not a
    string, but the actual class definition. The example above will export
    the functions "plan", "is", and "cmpOk" from the "Test.More" namespace
    to yours.

   JSAN.addRepository()
      JSAN.addRepository('js/private');

    Add any number of paths to "includePath". This will move the repository
    to the beginning of the list and it will be checked first for libraries.
    Calling "addRepository()" will add your include path for the entirety of
    the request, no matter how many times you call "JSAN.use()".

    As with use(), it will accept any combination of arrays and strings.

  Methods
   use()
  Compile Time
    "JSAN" creates an interesting sort of compile time for libraries loaded
    through it. This means that code that does not exist inside of a
    function is considered *compile time* code. This has certain
    implications when a library uses JSAN to import another library.

  Namespaces
    JavaScript - exempting version 2 anyway - does not have a notion of
    namespaces. For this reason something very important has been missing.
    However, JavaScript's object system is perfectly suited to create
    namespaces for well written code.

    The first thing you have to do when creating a library is define the
    namespace. The namespace must match the library name as well so "use()"
    can import the classes and functions correctly.

    The name of this library, "JSAN", or the name of our testing system,
    "Test.Simple", are examples of namespaces. A namespace is built by
    defining objects at each level until you reach the final name.

    Defining a namespace for JSAN is simple.

      var JSAN = {};

    Defining the namespace for "Test.Simple" takes a little more work. First
    you have to create an object at the variable named "Test" if it doesn't
    already exist. Then you can create an object, or place a constructor, at
    the "Test.Simple" location.

      if (Test == undefined) var Test = {};
      Test.Simple = {};

    So far we've just been inserting blank objects at the final namespace.
    That's fine if your library implements functions and does not implement
    a class. However, if you implement a class you will want to place a
    constructor in the final namespace instead.

      if (Name == undefined) var Name = {};
  
      Name.Space = function () {
          // This is the constructor.
      }

    Further, you'll want to define you class. This is done by defining the
    prototype in your namespace.

      Name.Space.prototype = {
          publicProperty: 'you see me',
      
          _privateProperty: 'boo',
      
          publicMethod: function (arg1, arg2) {
              // We do stuff man.
          },
      
          _privateMethod: function () {
              this._privateProperty = "no peaking";
          }
      };

  Exporting
    The "use()" function supports an Exporter style system. This means that
    you can create functions that will be exported to the caller
    automatically, functions that will be exported when requested, and
    groups of functions - called tags - that are exported when requested.

   EXPORT
    Set up functions that are auto-exported unless the caller declares a
    function list.

      Name.Space.EXPORT = [ 'functionOne', 'functionTwo' ];

    Importing the default functions.

      jsan.use('Name.Space');

    Importing specific functions.

      jsan.use('Name.Space', 'functionOne'); // Don't want functionTwo()

   EXPORT_OK
    Set up functions that are exported only by request.

      Name.Space.EXPORT    = [ 'functionOne', 'functionTwo' ];
      Name.Space.EXPORT_OK = [ 'specialOne',  'specialTwo'  ];

    Import the default functions. This will not import any functions inside
    the "EXPORT_OK" list.

      jsan.use('Name.Space');

    Import some specific function from "EXPORT_OK". This will not import any
    functions from the "EXPORT" list.

      jsan.use('Name.Space', 'specialOne');

   EXPORT_TAGS
    Set up a grouping of functions that can be exported all at once. This
    example also illustrates something I dislike about JavaScript arrays.
    I'll leave that for you to discover.

      function _expandTheFreakingLists () {
          var expanded = [];
          for (var i = 0; i <= arguments.length; i++ ) {
              var list = arguments[i];
              for (var j = 0; j <= list.length; j++) {
                  expanded.push(list[j]);
              }
          }
          return expanded;
      }

      Name.Space.EXPORT_TAGS = {
          ":common": Name.Space.EXPORT,
          ":all":    _expandTheFreakingLists(Name.Space.EXPORT, Name.Space.EXPORT_OK)
      };

    Now import all the functions.

      jsan.use('Name.Space', ':all');

    Import the common functions and one special one.

      jsan.use('Name.Space', ':common', 'specialOne');

  Writing Libraries
   Class Libraries
    Class libraries implement a public class that will be exported to the
    caller. The public class contains the same name as the package "use()"
    was called with.

    First, you have to set up a namespace.

      if (DOM == undefined) DOM = {};

      DOM.Display = function () {};

    Next you can define the class's prototype.

      DOM.Display.prototype = {
          register: {},
  
          hideElement: function (id) {
              // Do stuff.
          },
  
          showElement: function (id) {
              // Do stuff.
          },
  
          showOnlyElement: function (id) {
              // Do stuff.
          },
  
          registerElement: function (id) {
              // Do stuff.
          }
      };

    At this point your library may have dependences. If that's the case you
    can use "JSAN" to try and import them. This works because you have,
    theoretically, modified the "JSAN.includePath" on your initial
    invocation of the library. So your libraries being "use()"d need not
    know anything about "includePath"s.

      if (typeof JSAN != 'undefined') {
          JSAN.use('Some.Dependency');
      }

   Functional Libraries
    Functional libraries strictly intend to export a set of functions to the
    caller. While they may contain a class, or many classes, those classes
    are not part of the publicly documented API. These are simple to create
    but a few rules do apply.

    First, you still have to set up a namespace.

      if (Digest == undefined) var Digest = {};
      Digest.MD5 = {};

    Next you can define your export list.

      Digest.MD5.EXPORT_OK   = [  'md5', 'md5Hex', 'md5Base64' ];
      Digest.MD5.EXPORT_TAGS = { ':all': Digest.MD5.EXPORT_OK };

    Now you may go on to define your functions. They must be fully qualified
    just like the "EXPORT_OK" and "EXPORT_TAGS" variables.

      Digest.MD5.md5 = function (str) {
          // Do stuff.
      }

      Digest.MD5.md5Hex = function (str) {
          // Do stuff.
      }

      Digest.MD5.md5Base64 = function (str) {
          // Do stuff.
      }

    At this point your library may have dependences. If that's the case you
    can use "JSAN" to try and import them.

      if (typeof JSAN != 'undefined') {
          JSAN.use('Some.Dependency');
      } else {
          if (Digest.MD5.DEBUG == true
              && typeof Some.Dependency == 'undefined') {
              throw new Error("Some.Dependency not loaded.");
          }
      }

SEE ALSO
    JavaScript Namespaces,
    <http://justatheory.com/computers/programming/javascript/emulating_names
    paces.html>.

    Original JSAN Brainstorming,
    <http://use.perl.org/~schwern/journal/24112>.

    OpenJSAN, <http://openjsan.org>.

    Signed JavaScript,
    <http://www.mozilla.org/projects/security/components/jssec.html>.

AUTHOR
    Current maintainer: John Cappiello, <jcap@openjsan.org>.
    Original author: Casey West, <casey@geeknest.com>.

COPYRIGHT
      Copyright (c) 2005 Casey West.  All rights reserved.
      This module is free software; you can redistribute it and/or modify it
      under the terms of the Artistic license.

Something went wrong with that request. Please try again.