Hi, is it possible to define class methods/variables in prototype? I am migrating a bunch of classes to the prototype Class.create(); syntax, and some of them are implemented as a singleton, so they need to define a class method: MyClass.getInstance() How do I do that with prototyope? Thanks! Ingo --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Hey Ingo, ingo a écrit :> is it possible to define class methods/variables in prototype? I am > migrating a bunch of classes to the prototype Class.create(); syntax, > and some of them are implemented as a singleton, so they need to > define a class method:It''s unrelated to Prototype, actually, it''s raw JS. Just put your methods at the object (i.e. class, in classical OOP thinking) level, not at the constructor''s prototype level: var MyClass = Class.create(); Object.extend(MyClass, { // "static" stuff }); Object.extend(MyClass.prototype, { // "instance" stuff }); -- Christophe Porteneuve a.k.a. TDD "[They] did not know it was impossible, so they did it." --Mark Twain Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
It is opposite of what you described here. Object.extend(MyClass, { // "instance" stuff }); Object.extend(MyClass.prototype, { // "static" stuff }); The properties added to prototype is shared by all the instance object, so it is static. On Jan 28, 6:22 am, Christophe Porteneuve <t...-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org> wrote:> Hey Ingo, > > ingo a écrit : > > > is it possible to define class methods/variables in prototype? I am > > migrating a bunch of classes to the prototypeClass.create(); syntax, > > and some of them are implemented as a singleton, so they need to > > define a class method: > > It''s unrelated to Prototype, actually, it''s raw JS. Just put your > methods at the object (i.e. class, in classical OOP thinking) level, not > at the constructor''s prototype level: > > var MyClass =Class.create(); > > Object.extend(MyClass, { > // "static" stuff > > }); > > Object.extend(MyClass.prototype, { > // "instance" stuff > > }); > > -- > Christophe Porteneuve a.k.a. TDD > "[They] did not know it was impossible, so they did it." --Mark Twain > Email: t...-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
kerdosa a écrit :> It is opposite of what you described here.No it''s not.> The properties added to prototype is shared by all the instance > object, so it is static.You misunderstood how the prototype mechanism works. Properties defined at the prototype level are not *shared* by all instances: they''re *copied* over to all instances. Big, big difference. Demonstration: var MyClass = Class.create(); Object.extend(MyClass, { staticField: 42 }); Object.extend(MyClass.prototype, { instanceField1: 21, initialize(if2) { this.instanceField2 = if2; }); }); var mo1 = new MyClass(7); // => mo1: Object instanceField1=21 instanceField2=7 var mo2 = new MyClass(6); // => mo1: Object instanceField1=21 instanceField2=6 mo1.staticField // => undefined property "staticField" MyClass.staticField // => 42 mo1.instanceField1 = 100 mo2.instanceField1 // => 21 See? For tons of additional examples, just see *Prototype''s source code*... -- Christophe Porteneuve a.k.a. TDD "[They] did not know it was impossible, so they did it." --Mark Twain Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Christophe is right. Here is an example of how I would right a class that has private variables, public properties, private & public instance methods, and public static methods (where applicable I will highlight multiple ways to achieve the same thing). Note: by placing the definition of public properties and methods within the class''s constructor, you guarantee that those are instance level members. myClass = Class.create(); myClass.prototype = { // public static members publicStaticProperty1: "this is a public static property", publicStaticMethod: function () { alert("this is a public static method"); }, // constructor initialize: function (initProp1, initProp2) { // private variables var someVar = "this is private"; // private methods function privateFunction() { alert("private method"); } // public instance properties this.publicInstanceProperty1 = "this property is public and only available to instances"; // public instance methods (obviously has access to all private members) this.publicInstanceMethod = function() { alert(someVar); privateFunction(); alert(this.publicInstanceProperty1); } } } --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Oops, slightly wrong for the static members... in my example you can access the static members like this: myClass.prototype.publicStaticMethod(); BUT, this is probably not what most people would like to write. So just use two declarations (one for static members, and the other for the class level stuff) Using Cristophe''s example: Object.extend(myClass, { publicStaticProperty: "this is public & static", publicStaticMethod: function() { alert("public static method"); } }); And then my way if you''d like to use truly private / public paradigm for the class level stuff: myClass.prototype = { initialize: function() { // ... what I put in here in my first post ... } } On 3/12/07, Ryan Gahl <ryan.gahl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Christophe is right. Here is an example of how I would right a class that > has private variables, public properties, private & public instance methods, > and public static methods (where applicable I will highlight multiple ways > to achieve the same thing). Note: by placing the definition of public > properties and methods within the class''s constructor, you guarantee that > those are instance level members. > > myClass = Class.create(); > myClass.prototype = { > > // public static members > publicStaticProperty1: "this is a public static property", > publicStaticMethod: function () { alert("this is a public static method"); > }, > > // constructor > initialize: function (initProp1, initProp2) { > > // private variables > var someVar = "this is private"; > > // private methods > function privateFunction() { alert("private method"); } > > // public instance properties > this.publicInstanceProperty1 = "this property is public and only available > to instances"; > > // public instance methods (obviously has access to all private members) > this.publicInstanceMethod = function() { > alert(someVar); > privateFunction(); > alert(this.publicInstanceProperty1 ); > } > } > } >-- Ryan Gahl Application Development Consultant Athena Group, Inc. Inquire: 1-920-955-1457 Blog: http://www.someElement.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
On Jan 28, 2:06 pm, "ingo" <ingowe...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, > > is it possible to define class methods/variables in prototype? I am > migrating a bunch of classes to the prototype Class.create(); syntax, > and some of them are implemented as a singleton, so they need to > define a class method: > > MyClass.getInstance() > > How do I do that with prototyope?The following might help you to understand the underlying language: <URL: http://www.crockford.com/javascript/private.html > <URL: http://www.litotes.demon.co.uk/js_info/private_static.html > -- Rob --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks very much, I was wrong and I deleted my posting, I understand better now. One remaining question is inheriting array member, if a parent has array member in prototype, is it possible to subclass it without any issue? I did simple testing using "Extending anonymous instances described in Encytemedia, it shows that the array object is shared by two different child instances. Is there any way to get around this? var Shape = Class.create(); Shape.prototype = { initialize: function() { this.options = "parent"; this.array = new Array("hj", "jenny"); } } var Square = Class.create(); Square.prototype = Object.extend(new Shape(), { initialize: function() { this.foo = ''I am foo''; } }); var sq1= new Square(); var sq2= new Square(); sq1.array.push("third"); console.log(sq1.array); //prints ["hj", "jenny", "third"] console.log(sq2.array); //prints ["hj", "jenny", "third"]> >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Hey there,> Square.prototype = Object.extend(new Shape(), {OK, this is trouble in our case. Justin told so in his article already. Doing this, basically, has problems. This is because code executed by the constructor (including code in initialize, if your constructor is provided by Class.create) will happen right there and then, in your new Shape. The dependency scheme here goes: o = new Shape() => { options: ''parent'', array: [''hj'', ''jenny''] } | refs copied to (that''s what Object.extend *does*...) | +-- Square.prototype => { options: o.option, array: o.array } | +-- sq1 => { options: o.option, array: o.array, foo: ''I am foo'' } | +-- sq2 => { options: o.option, array: o.array, foo: ''I am foo'' } The array is created once, by new Shape(), and the reference is copied over to Square.prototype. The properties are then copied over (as refs, as always...) to the instances sq1 and sq2. Nominal behavior, although undesirable. Not to mention you create a Shape from the start. You *will* find Object.extend(new X, {...}) in Prototype (for Insertions, Event- and TimedObservers, and Ajax requesters), but if you look carefully, the constructor functions for the base objects do not call initialize, nor do they initialize any container field where ref-copy would be a problem: - they''re either empty (Ajax.Base, Abstract.TimedObserver, Abstract.EventObserver) - or innocuous (Abstract.Insertion, which just defines adjacency, then used by the child objects'' initialize function). Indeed, this scheme is the main problem in Prototype''s current inheritance system. Core is keeping an eye on Dean Edwards'' Base paradigm and may decide to move Prototype''s system to it for 2.0, but that''s a long time from now (at the very, very least by late 2007). In the meantime, here''s a suggested fix. WARNING: this certainly works, but I haven''t tested AT ALL whether this breaks anything in Prototype (which it may well do, although I kinda intuit it doesn''t). It relies on: 1) redefining Class.create to accept a "parent" class argument 2) not using Object.extend anymore: just define your child class prototypes like you would the parent class. Check this out: Class.create = function(base) { return function() { if ((base) && base.prototype.initialize) base.prototype.initialize.apply(this, arguments); this.initialize.apply(this, arguments); } }; var Parent = Class.create(); Parent.prototype = { initialize: function() { this.arr = [''hj'', ''jenny'']; } }; var Child = Class.create(Parent); Child.prototype = { initialize: function(name) { this.name = name; } }; var c1 = new Child(''john''); var c2 = new Child(''mary''); c1.name // => ''john'' c2.name // => ''mary'' c1.arr.push(''hey!''); c1.arr // => [''hj'', ''jenny'', ''hey!''] c2.arr // => [''hj'', ''jenny'', ''hey!''] -- Christophe Porteneuve a.k.a. TDD "[They] did not know it was impossible, so they did it." --Mark Twain Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Christophe Porteneuve a écrit :> c1.arr // => [''hj'', ''jenny'', ''hey!''] > c2.arr // => [''hj'', ''jenny'', ''hey!'']My bad! Copy-paste haste. Of course, the second should read: c2.arr // => [''hj'', ''jenny''] Otherwise, what is it good for? :-) -- Christophe Porteneuve a.k.a. TDD "[They] did not know it was impossible, so they did it." --Mark Twain Email: tdd-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
On 13 mar, 17:10, Christophe Porteneuve <t...-x+CfDp/qHev2eFz/2MeuCQ@public.gmane.org> wrote: [snip]> > Check this out: > > Class.create = function(base) { > return function() { > if ((base) && base.prototype.initialize) > base.prototype.initialize.apply(this, arguments); > this.initialize.apply(this, arguments); > } > > }; >This sounds good, in theory, but only if everything is declared inside the inditialize function. I came across this thread looking for a way to accomplish a basic inheritance in JS (instead of doing Object.extend({}, base)). This example is also untested, but would this conception cause issues ? Class.create = function(base) { return function() { if ((base) && base.prototype.initialize) { for (property in base.prototype) { this.prototype[property] = base.prototype[property]; } base.prototype.initialize.apply(this, arguments); } this.initialize.apply(this, arguments); } }; --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
> > This sounds good, in theory, but only if everything is declared inside > the inditialize function.Which is as it should be if your are really talking about class methods (i.e. instance only members). See my blog post on this subject, which offers up a nice, prototype-y inheritance model and leave Object.extend alone (because it is useful as is for bulk object property copying in other places besides inheritance): http://www.someelement.com/2007/03/multiple-inheritance-with-prototypejs.html I also speak to the whole "true" class level member issue and address the bad habit of tacking said members statically onto the object''s prototype. The first part of the post does give examples using that way, just because I know that''s what people are used to. Give it a read. Object.inherit is very useful. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
On 2 avr, 11:42, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > This sounds good, in theory, but only if everything is declared inside > > the inditialize function. > > Which is as it should be if your are really talking about class methods (i.e. > instance only members). > > See my blog post on this subject, which offers up a nice, prototype-y > inheritance model and leave Object.extend alone (because it is useful as is > for bulk object property copying in other places besides inheritance): > > http://www.someelement.com/2007/03/multiple-inheritance-with-prototyp... > > I also speak to the whole "true" class level member issue and address the > bad habit of tacking said members statically onto the object''s prototype. > The first part of the post does give examples using that way, just because I > know that''s what people are used to. > > Give it a read. Object.inherit is very useful.Yes, I just tried it, and it works nicely. I wrote some Observable/ Observer generic classes that other classes may extend to benefit from an Observer pattern to test the functionality (java-like). Though, I was wondering the possibility to write some sort of Class.create(); with parameters.... something like : var Class1 = Class.create( baseClass /* , baseFuncName */ ); for single inheritance, or : var Class1 = Class.create( [ { baseClass: baseClass /*, baseName: baseFuncName */ }, ... ] ); for multiple inheritance. Perhaps even add, as last parameter, an object to set as prototype, and yet get rid of every Object.extend(). Such as : Class.create( prototype ); // for no inheritance Class.create( baseClass, prototype ); // or Class.create( baseClass, baseName, prototype ); and Class.create( baseClassArray, prototype ); (Is that going too far ?) I''m asking before throwing myself in anything, as you probably had thought about it. Thanks though for the article, it was very instructive. -yanick --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Javascript is an expressive language. You can achieve what you are asking without baking it into the method like that, you just have to stop trying so hard to do things in one function call (it''s ok to have 2 function calls to achieve something that is a composite of two simpler steps). And by leaving our illustrious lower-level prototype functions as they are, it supports comfy use for those cases where the extra functionality is not needed (i.e. where only that first function call is required). Once you use prototype for about a year you will learn to like the fact the the core functions are left simple. So while I''d love to see my version of Object.inherit included in the core, I would not want Object.extend to change, nor would I want Class.create() to change. As for the Observable/Observer thing, did you check out my other blog post on EventPublisher? If you need that functionality, you may that interesting as well: http://www.someelement.com/2007/03/eventpublisher-custom-events-la-pubsub.html On 4/2/07, Yanick <yanick.rochon-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > > On 2 avr, 11:42, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > This sounds good, in theory, but only if everything is declared inside > > > the inditialize function. > > > > Which is as it should be if your are really talking about class methods > (i.e. > > instance only members). > > > > See my blog post on this subject, which offers up a nice, prototype-y > > inheritance model and leave Object.extend alone (because it is useful as > is > > for bulk object property copying in other places besides inheritance): > > > > http://www.someelement.com/2007/03/multiple-inheritance-with-prototyp... > > > > I also speak to the whole "true" class level member issue and address > the > > bad habit of tacking said members statically onto the object''s > prototype. > > The first part of the post does give examples using that way, just > because I > > know that''s what people are used to. > > > > Give it a read. Object.inherit is very useful. > > > Yes, I just tried it, and it works nicely. I wrote some Observable/ > Observer generic classes that other classes may extend to benefit from > an Observer pattern to test the functionality (java-like). > > Though, I was wondering the possibility to write some sort of > Class.create(); with parameters.... something like : > > var Class1 = Class.create( baseClass /* , baseFuncName */ ); > > for single inheritance, or : > > var Class1 = Class.create( [ { baseClass: baseClass /*, baseName: > baseFuncName */ }, ... ] ); > > for multiple inheritance. > > Perhaps even add, as last parameter, an object to set as prototype, > and yet get rid of every Object.extend(). Such as : > > Class.create( prototype ); // for no inheritance > Class.create( baseClass, prototype ); // or Class.create( baseClass, > baseName, prototype ); > and > Class.create( baseClassArray, prototype ); > > (Is that going too far ?) > > I''m asking before throwing myself in anything, as you probably had > thought about it. Thanks though for the article, it was very > instructive. > > -yanick > > > > >-- Ryan Gahl Application Development Consultant Athena Group, Inc. Inquire: 1-920-955-1457 Blog: http://www.someElement.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
On 2 avr, 22:41, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Javascript is an expressive language. You can achieve what you are asking > without baking it into the method like that, you just have to stop trying so > hard to do things in one function call (it''s ok to have 2 function calls to > achieve something that is a composite of two simpler steps). And by leaving > our illustrious lower-level prototype functions as they are, it supports > comfy use for those cases where the extra functionality is not needed (i.e. > where only that first function call is required). Once you use prototype for > about a year you will learn to like the fact the the core functions are left > simple. So while I''d love to see my version of Object.inherit included in > the core, I would not want Object.extend to change, nor would I want > Class.create() to change. >Yeah, I know what you mean. Thanks for the tip though.> As for the Observable/Observer thing, did you check out my other blog post > on EventPublisher? If you need that functionality, you may that interesting > as well:http://www.someelement.com/2007/03/eventpublisher-custom-events-la-pu... >Well, it''s not quite what I had in mind. I have already seen something similar in "Ajax in action", and I already implemented an EventQueue system (which works fine, using async calls with Rico support), but I wanted to create objects that could interact with each other directly withouth having to implement system hooks every time. Here''s what I wrote (in about 15 minutes) : // -------------- begin ---------------------------- /** * Observable * * This object encapsulate the Obserable part of the Observer pattern. * * @see Object.inherit() for more info on how to inherit this object */ Observable = Class.create(); Observable.prototype = { /** * Constructor : build a new instance */ initialize: function() { this.observers = []; this.hasChanged = false; this._timer = null; }, /** * Add a new observer to the observers list * * @see Observer * * @param observer an object that implements the Observer */ addObserver: function(observer) { this.observers.push(observer); }, /** * Notify all observers if the Observable has changed. If a delay is * provided, the observers will only be notified when * * @see Observable.setChanged() * * @param message a message to send to the observers * @param delay (optional) a delay in millis (0 or null notify now) */ notifyObservers: function( message, asyncDelay ) { if ( this.hasChanged ) { var _notifyFn = function() { for (var i=0, len=this.observers.length; i<len; i++) { this.observers[i].update(this, message); } this.hasChanged = false; }.bind(this); // if notifications are waiting for a delay, clear this delay now if ( this._timer ) { clearTimeout(this._timer); } if ( asyncDelay && asyncDelay > 0 ) { this._timer = setTimeout( _notifyFn, asyncDelay ); } else { _notifyFn(); } } }, /** * Remove an observer */ removeObserver: function(observer) { this.observers = this.observers.without(observer); }, /** * Set the Observable as "modified". Any subsequent call to * notifyObservers() will notify them. */ setChanged: function() { this.hasChanged = true; } }; /** * Observer * * An Observer implementation of the Observer pattern. Objects that inherits * this object must override the methode update(observable, message) * * @see Object.inherit() to see how to inherit from this object */ Observer = Class.create(); Observer.prototype = { initialize: function() {}, /** * ** Must be implemented ** * * This method is called by the Observable object to warn this observer about * changes. * * @param observable the caller object (Observable) * @param message any message from the Observable */ update: function(observable, message) { throw "NotImplmentedException: Observer.update"; } }; // test code // observer test var TestObserver = Class.create(); Object.inherit(TestObserver, Observer); Object.extend(TestObserver.prototype, { initialize: function() { this.base(); }, update: function(observable, message) { alert( observable + " = " + message ); } } ); var TestObservable = Class.create(); Object.inherit(TestObservable, Observable); Object.extend(TestObservable.prototype, { doTest: function(message) { this.setChanged(); this.notifyObservers(message, 3000); } } ); var observable = new TestObservable(); observable.addObserver( new TestObserver() ); observable.doTest( "test 123" ); // alert "[object] = test 123", 3 seconds later // ------------- end ------------------------- I won''t say that it is well optimized, but this simple test is quite positive. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Ah ok. Just a slightly different approach. I would argue that the EventPublisher model seems a bit less cumbersome. For instance, the only class in my model that needs to extend from EventPublisher is the class that is to fire events (subscribers need not extend themselves). The subscribers can then simply register a method (any method) to listen for a specific event (any event). So mine is more method-centric where your implementation is centered on registering entire object (which must have a specific method defined to be valid). I''m sure there are pros and cons to both approaches though. On 4/2/07, Yanick <yanick.rochon-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > > On 2 avr, 22:41, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Javascript is an expressive language. You can achieve what you are > asking > > without baking it into the method like that, you just have to stop > trying so > > hard to do things in one function call (it''s ok to have 2 function calls > to > > achieve something that is a composite of two simpler steps). And by > leaving > > our illustrious lower-level prototype functions as they are, it supports > > comfy use for those cases where the extra functionality is not needed ( > i.e. > > where only that first function call is required). Once you use prototype > for > > about a year you will learn to like the fact the the core functions are > left > > simple. So while I''d love to see my version of Object.inherit included > in > > the core, I would not want Object.extend to change, nor would I want > > Class.create() to change. > > > > Yeah, I know what you mean. Thanks for the tip though. > > > > As for the Observable/Observer thing, did you check out my other blog > post > > on EventPublisher? If you need that functionality, you may that > interesting > > as well: > http://www.someelement.com/2007/03/eventpublisher-custom-events-la-pu... > > > > > Well, it''s not quite what I had in mind. I have already seen something > similar in "Ajax in action", and I already implemented an EventQueue > system (which works fine, using async calls with Rico support), but I > wanted to create objects that could interact with each other directly > withouth having to implement system hooks every time. Here''s what I > wrote (in about 15 minutes) : > > // -------------- begin ---------------------------- > > /** > * Observable > * > * This object encapsulate the Obserable part of the Observer pattern. > * > * @see Object.inherit() for more info on how to inherit this object > */ > Observable = Class.create(); > > Observable.prototype = { > > /** > * Constructor : build a new instance > */ > initialize: function() { > this.observers = []; > this.hasChanged = false; > this._timer = null; > }, > > /** > * Add a new observer to the observers list > * > * @see Observer > * > * @param observer an object that implements the Observer > */ > addObserver: function(observer) { > this.observers.push(observer); > }, > > /** > * Notify all observers if the Observable has changed. If a delay is > * provided, the observers will only be notified when > * > * @see Observable.setChanged() > * > * @param message a message to send to the observers > * @param delay (optional) a delay in millis (0 or null > notify now) > */ > notifyObservers: function( message, asyncDelay ) { > if ( this.hasChanged ) { > var _notifyFn = function() { > for (var i=0, len=this.observers.length; i<len; i++) { > this.observers[i].update(this, message); > } > > this.hasChanged = false; > }.bind(this); > > // if notifications are waiting for a delay, clear this delay > now > if ( this._timer ) { > clearTimeout(this._timer); > } > > if ( asyncDelay && asyncDelay > 0 ) { > this._timer = setTimeout( _notifyFn, asyncDelay ); > } else { > _notifyFn(); > } > } > }, > > /** > * Remove an observer > */ > removeObserver: function(observer) { > this.observers = this.observers.without(observer); > }, > > /** > * Set the Observable as "modified". Any subsequent call to > * notifyObservers() will notify them. > */ > setChanged: function() { > this.hasChanged = true; > } > > }; > > > /** > * Observer > * > * An Observer implementation of the Observer pattern. Objects that > inherits > * this object must override the methode update(observable, message) > * > * @see Object.inherit() to see how to inherit from this object > */ > Observer = Class.create(); > > Observer.prototype = { > > initialize: function() {}, > > /** > * ** Must be implemented ** > * > * This method is called by the Observable object to warn this > observer about > * changes. > * > * @param observable the caller object (Observable) > * @param message any message from the Observable > */ > update: function(observable, message) { > throw "NotImplmentedException: Observer.update"; > } > > }; > > > // test code > > // observer test > var TestObserver = Class.create(); > Object.inherit(TestObserver, Observer); > Object.extend(TestObserver.prototype, { > initialize: function() { > this.base(); > }, > update: function(observable, message) { > alert( observable + " = " + message ); > } > } ); > > var TestObservable = Class.create(); > Object.inherit(TestObservable, Observable); > Object.extend(TestObservable.prototype, { > > doTest: function(message) { > this.setChanged(); > this.notifyObservers(message, 3000); > } > > } ); > > var observable = new TestObservable(); > observable.addObserver( new TestObserver() ); > > observable.doTest( "test 123" ); // alert "[object] = test 123", 3 > seconds later > > > // ------------- end ------------------------- > > > I won''t say that it is well optimized, but this simple test is quite > positive. > > > > >-- Ryan Gahl Application Development Consultant Athena Group, Inc. Inquire: 1-920-955-1457 Blog: http://www.someElement.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
On 3 avr, 00:16, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Ah ok. Just a slightly different approach. I would argue that the > EventPublisher model seems a bit less cumbersome. For instance, the only > class in my model that needs to extend from EventPublisher is the class that > is to fire events (subscribers need not extend themselves). The subscribers > can then simply register a method (any method) to listen for a specific > event (any event). So mine is more method-centric where your implementation > is centered on registering entire object (which must have a specific method > defined to be valid). > > I''m sure there are pros and cons to both approaches though. >And I can see the benefit of your approach. If I understand it well, EventPublisher may be used as global event dispatcher or a base class for an observable object (am I right ?) In any case, the later may be used both ways. Though, if I may, I would suggest modifying the attachEventHandler''s third parameter to be either boolean or numeric ; this way, one could specify the async delay to wait before fireing the method of the handler. In my implementation, I cancelled any pending notifications because I need to have a system that can support multiple modifications from user input without notifying observers multiple times (for a list selection system that syncs with the server). (Perhaps adding a fourth parameter to flag multiple delayed notifications or not.) But I think we fall off-topic now. I appreciate the comments and suggestions your proposed, and even if you think that Object.inherit (or perhaps Class.inherit ?) should not be part of Prototype, I would think that I will add this feature to a script called prototype- extra.js that I use in my project for the moment. That is if you don''t mind of course. -yanick --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Don''t mind a bit. Enjoy. As a final note: I will consider the addition of a numeric value for the delay, however, that could just as easily be accomplished by the registering method itself (i.e. the listener is itself a setTimeout with a specific delay). Also, I would not mind a bit if Object.inherit were included into Prototype, but was just stating that it should not cause any of the existing methods to change. Good discussion, this. On 4/3/07, Yanick <yanick.rochon-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > > On 3 avr, 00:16, "Ryan Gahl" <ryan.g...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Ah ok. Just a slightly different approach. I would argue that the > > EventPublisher model seems a bit less cumbersome. For instance, the only > > class in my model that needs to extend from EventPublisher is the class > that > > is to fire events (subscribers need not extend themselves). The > subscribers > > can then simply register a method (any method) to listen for a specific > > event (any event). So mine is more method-centric where your > implementation > > is centered on registering entire object (which must have a specific > method > > defined to be valid). > > > > I''m sure there are pros and cons to both approaches though. > > > > And I can see the benefit of your approach. If I understand it well, > EventPublisher may be used as global event dispatcher or a base class > for an observable object (am I right ?) In any case, the later may be > used both ways. > > Though, if I may, I would suggest modifying the attachEventHandler''s > third parameter to be either boolean or numeric ; this way, one could > specify the async delay to wait before fireing the method of the > handler. In my implementation, I cancelled any pending notifications > because I need to have a system that can support multiple > modifications from user input without notifying observers multiple > times (for a list selection system that syncs with the server). > (Perhaps adding a fourth parameter to flag multiple delayed > notifications or not.) > > But I think we fall off-topic now. I appreciate the comments and > suggestions your proposed, and even if you think that Object.inherit > (or perhaps Class.inherit ?) should not be part of Prototype, I would > think that I will add this feature to a script called prototype- > extra.js that I use in my project for the moment. That is if you don''t > mind of course. > > -yanick > > > > >-- Ryan Gahl Application Development Consultant Athena Group, Inc. Inquire: 1-920-955-1457 Blog: http://www.someElement.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---