I agree with John -- I also prefer the first style Paul presented (which I 
believe is also the most prevalent style in Shindig currently).

With respect to the issues that Michael raised about building up a namespace 
from across different files -- this got me thinking about a little namespace 
utility a colleague of mine wrote a while back.  That utility just took a 
target namespace like "shindig.util.foo", created an empty object in it 
(without clobbering any parts of the target namespace that may have already 
existed) and returned it -- so you could then do something like 
shindig.util.foo.x = ... directly without needing to create each piece of the 
namespace manually.

And with some (well, a lot) of tweaking I was able to turn that function into a 
more general purpose namespacing function that takes an optional object to 
place into the target namespace -- and if the target namespace already exists 
it takes the properties of the optional object and appends them to the existing 
namespace.

So I think if enough people preferred the first style Paul presented, something 
like this could be used to work around the issues Michael raised.  Here is the 
function and some sample usages (with the caveat that I haven’t actually used 
this for anything real so there could be some bugs in it):

var shindig = shindig || (function() {
    var namespace = function(targetNamespace, optObject) {
        //get a reference to the global window object
        var object = window;

        //if no object was provided to put into the namespace create an empty 
one
        optObject = optObject || {};

        //split the namespace into its parts
        var namespaces = targetNamespace.split(".");

        //for each part of the namespace
        for (var i = 0; i < namespaces.length; i++) {
            //see if this part is already defined
            if (typeof object[namespaces[i]] === "undefined") {
                //if its not defined already -- put an object into it
                //if we're at the end of the targetNamespace, put the new 
object into it,
                //otherwise drop in an empty object as a placeholder
                object[namespaces[i]] = (i + 1) == namespaces.length ? 
optObject : {};
            } else {
                //there is already something here -- see if we're at the end of 
the targetNamespace
                if ((i + 1) == namespaces.length) {
                    //make sure its an object we can append to
                    if (typeof object[namespaces[i]] === "object") {
                        //go ahead and add all the public properties on 
optObject to the target namespace
                        for (var property in optObject) {
                            object[namespaces[i]][property] = 
optObject[property];
                        }
                    } else {
                        throw "Cannot append new properties to object of type " 
+ typeof object[namespaces[i]];
                    }
                }
            }

            object = object[namespaces[i]];
        }

        return object;
    };

    return {
        namespace: namespace
    };
})();

//could be from foo-utils.js
shindig.namespace("shindig.util", (function() {
    var privateData = "this is private";

    var privateFunction = function() {
        console.log(privateData);
    };

    var calculateFoo = function() {
        privateFunction();
    };

    var doAlotOfFoo = function() {
        //do alot of foo
    };

    return {
        calculateFoo: calculateFoo,
        doAlotOfFoo: doAlotOfFoo
    };
})());

//could be from bar-utils.js
shindig.namespace("shindig.util", (function() {
    var privateFunction = function() {
        console.log("calculateBar called");
    };

    var calculateBar = function() {
        privateFunction();
    };

    return {
        publicData: "this is public",
        calculateBar: calculateBar
    };
})());

shindig.namespace("shindig.some.emptyNamespace");
shindig.some.emptyNamespace.xyz = "ABC";

>-----Original Message-----
>From: Michael Hermanto [mailto:mherma...@gmail.com]
>Sent: Tuesday, July 26, 2011 6:15 PM
>To: dev@shindig.apache.org
>Subject: Re: javascript readability..
>
>What didn't work for me with --
>   shindig.foo = function() {
>     return { 'bar': ... };
>   }();
>... is that methods in the same namespace have to be all
>defined/implemented
>in one file.
>
>ie: it's fine if all gadgets.rpc.* is implemented in a file rpc.js, but not
>fine when gadgets.util.* are implemented across different files/features
>across core.util.dom, core.util.string, etc. When feature core.util pulls
>all these files in, it will effectively stomp all the previously-defined
>core.util.*.
>
>The tendency has been to make libraries smaller and more focussed to what
>they do, ie: this means breaking up features into sub-features. To do so, I
>had to convert more-focussed core.util.[dom|string|...] to fully-defined
>names. Unless the above style (with shindig.foo) doesn't have this
>limitation (ie: can incrementally define more methods on top what has been
>defined), I personally prefer the fully-defined names, for consistency.
>
>
>
>2011/7/26 ๏̯͡๏ Jasvir Nagra <jas...@google.com>
>
>> I don't have a strong preference either way although it's nice when
>> reviewing code to have all the exported things exported once when they
>> share
>> a scope full of private helpers and other state.  It also helps convey when
>> the setup of a particular part of the object graph is done.
>> Eg.
>>
>> shindig.foo = (function() {
>>  // ... all the helper functions and shared state ...
>>  ...
>>  return { bar: bar, baz: baz };
>> }();
>> // at this point I know from convention that shindig.foo is done being
>> setup
>> and will have just "bar" and "baz"
>>
>> vs.
>>
>> shindig.foo.bar = function() { ... }
>> /// ... a lot of code later
>> shindig.foo.baz = function() { ... }
>>
>> If the amount of code between shindig.foo and the return is long, I'd
>> suggest another alternative that I think has the advantage of both:
>>
>> (function() {
>>  // ... all the helper functions and shared state ...
>>
>>  shindig.foo = {
>>    bar: bar,
>>    baz: baz
>>  }
>> })();
>>
>> On Tue, Jul 26, 2011 at 2:19 PM, John Hjelmstad <fa...@google.com>
>wrote:
>>
>> > With the model we're using with exportJs, you actually can't as easily do
>> > that or wrap "singleton"/namespaced items, unless you . exportJs(...) is
>> > injected after the closure.
>> >
>> > function() {
>> >  foo.bar.baz = function() { }
>> > }();
>> > exportJs("foo.bar", [foo,foo.bar], {baz:"baz"});
>> >
>> > Of course, you can if you also update the style guide to prepend window:
>> >
>> > function() {
>> >  window.foo.bar.baz = function() { }
>> > }();
>> >
>> > ...though that requirement seems a little awkward and verbose to me.
>> >
>> > --j
>> >
>> > On Tue, Jul 26, 2011 at 2:12 PM, Dan Dumont <ddum...@us.ibm.com>
>wrote:
>> >
>> > > As mentioned by Paul before you can define:
>> > >
>> > > function(){
>> > >   FooClass.prototype.method = function() { }
>> > >  FooClass.prototype.method2 = function() { }
>> > > }();
>> > >
>> > > to get a local scope.
>> > >
>> > > I think this makes it easier to audit what must be included in an
>> export.
>> > > And when you come up for air soon, maybe we can talk about AMD
>format
>> and
>> > > what that brings to the table.  :)
>> > >
>> > >
>> > >
>> > > From:   John Hjelmstad <fa...@google.com>
>> > > To:     dev@shindig.apache.org,
>> > > Date:   07/26/2011 04:43 PM
>> > > Subject:        Re: javascript readability..
>> > >
>> > >
>> > >
>> > > I still prefer status quo, as it reads more like a proper class to me,
>> > > while
>> > > being less verbose and centralizing the exported method definitions in
>> a
>> > > single place.
>> > >
>> > > As well, this question's corollary is whether to convert all
>> instantiable
>> > > objects to the form:
>> > >
>> > > FooClass.prototype.method = function() { }
>> > > FooClass.prototype.method2 = function() { }
>> > >
>> > > ...from:
>> > > FooClass = function() {
>> > >  // private state
>> > >  function method() { }
>> > >  function method2() { }
>> > >  return {
>> > >    method: method,
>> > >    method2: method2
>> > >  };
>> > > };
>> > >
>> > > On this note, I'm conflicted. I like having actual private state, but
>> > > prototype-style is more efficient.
>> > >
>> > > Enough people have complained over time about each of the existing
>> idioms
>> > > though that I suppose I could go the other direction, if it's causing
>> > > development trouble.
>> > >
>> > > --j
>> > >
>> > > On Tue, Jul 26, 2011 at 6:17 AM, Ryan J Baxter <rjbax...@us.ibm.com>
>> > > wrote:
>> > >
>> > > > +1 As well, I think its easier to read.
>> > > >
>> > > > -Ryan
>> > > >
>> > > > Email: rjbax...@us.ibm.com
>> > > > Phone: 978-899-3041
>> > > > developerWorks Profile
>> > > >
>> > > >
>> > > >
>> > > > From:   Dan Dumont/Westford/IBM@Lotus
>> > > > To:     dev@shindig.apache.org,
>> > > > Date:   07/26/2011 09:00 AM
>> > > > Subject:        Re: javascript readability..
>> > > >
>> > > >
>> > > >
>> > > > +1
>> > > >
>> > > >
>> > > >
>> > > > From:   Paul Lindner <lind...@inuus.com>
>> > > > To:     dev@shindig.apache.org,
>> > > > Date:   07/26/2011 02:51 AM
>> > > > Subject:        javascript readability..
>> > > >
>> > > >
>> > > >
>> > > > Hi,
>> > > >
>> > > > I'm curious to know what people think about some of the idioms in the
>> > JS
>> > > > code you find in shindig.  There's an awful lot of stuff like this:
>> > > >
>> > > > shindig.foo = function(){
>> > > >  //...
>> > > >  var myFunction = function() {
>> > > >     }
>> > > >
>> > > >  return {'foo': myFunction,
>> > > >            'bar': function() {
>> > > >               return 'bar';
>> > > >            }};
>> > > > }();
>> > > >
>> > > >
>> > > > Just search for @member to see the various places.
>> > > >
>> > > > What would people think if we moved to fully defined names for
>> > > > function/method definitions instead?
>> > > >
>> > > > You could still wrap this inside a closure if you wanted local scope:
>> > > >
>> > > > function() {
>> > > >  shindig.foo.foo = function() {
>> > > >     ...
>> > > >  }
>> > > >  shindig.foo.bar = function() {
>> > > >     ...
>> > > >  }
>> > > > }();
>> > > >
>> > > > --
>> > > > Paul Lindner -- lind...@inuus.com -- linkedin.com/in/plindner
>> > > >
>> > > >
>> > > >
>> > > >
>> > > >
>> > > >
>> > > >
>> > >
>> > >
>> > >
>> > >
>> >
>>

Reply via email to