Hello all, I''ve just released a bit of code I''m calling ''Reiterate'' that aims to allow you to use strings, arrays and hashes where you''d normally use iterator functions in Enumerable methods. Think of what ''pluck'' and ''invoke'' do, but applied to lots of other methods. It works by defining a #toFunction instance method on String, Array and Hash and using those to create iterator functions from those data types. Some examples: [''FOO'', ''BAR'', ''BAZ''].map(''toLowerCase.toArray'') // -> [[''f'', ''o'', ''o''], [''b'', ''a'', ''r''], [''b'', ''a'', ''z'']] var divs = someDivs.findAll({hasClassName: ''myClass'', visible: true}); [''apples'', ''oranges'', ''plums''].sortBy([''replace'', /^(..)(.)/, ''$2$1'']) // -> ["oranges", "apples", "plums"] Those are fairly contrived, I know, but they illustrate things fairly well. More info here: http://blog.jcoglan.com/reiterate/ -- I''d really appreciate some feedback on how useful this is; it''s cleaned things up for me in a few places. Also, I''d like to see this go into the core if people think it''s worth it. I think it sits quite well with Prototype''s aim of easing development, and it provides a nice mirror of Symbol#to_proc and Methodphitamine (to some extend) for those of us into Ruby. See the ticket and consider giving a +1 if you like it: http://dev.rubyonrails.org/ticket/9611. --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
jcoglan wrote:> Hello all, > > I''ve just released a bit of code I''m calling ''Reiterate'' that aims to > allow you to use strings, arrays and hashes where you''d normally use > iterator functions in Enumerable methods. Think of what ''pluck'' and > ''invoke'' do, but applied to lots of other methods. > > ... > http://dev.rubyonrails.org/ticket/9611.This is totally sweet. I''ve often fleetingly wondered if it would be possible to create iterators from strings. This is really creative and intuitive. I''m not from the Ruby world, but I love it! My only suggestion would be to require an explicit call #toFunction() so that it would be more obvious that it is an iterator function and not require an extra line be added to the Enumerable functions. (if (iterator) iterator = Function.from(iterator); ) So, for example: [''FOO'', ''BAR'', ''BAZ''].map(''toLowerCase.toArray''.toFunction()); var divs = someDivs.findAll($H({hasClassName: ''myClass'', visible: true}).toFunction()); [''apples'', ''oranges'', ''plums''].sortBy([''replace'', /^(..)(.)/, ''$2$1''].toFunction()); What do you think? - Ken Snyder --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
pre{background:#eef;padding:5px} Ha, enumerable on steroids! Ok, CSS3 selectors partially accomplish this so instead of: $$(''.register input'').findAll(function(el){return el.checked}) we do $$(''.register input:checked'') Selectors, of course, are quite limited and are not fully supported as of now (while :empty, :enabled and :disabled work, :contains doesn''t). Besides, thinking about all the prototype''s Element.Methods which would be possible to use, this looks pretty sweet. Your example: [''FOO'', ''BAR'', ''BAZ''].map(''toLowerCase.toArray'') can now be done easily with invoke (though a little more verbose): [''FOO'', ''BAR'', ''BAZ''].invoke(''toLowerCase'').invoke(''toArray''); As far as syntax, I think parameters should not be passed as an array: someDivs.findAll([''hasClassName'', ''myClass'']); following invoke''s philosophy it should be simply: someDivs.findAll(''hasClassName'', ''myClass''); // just like someDivs.invoke(''addClassName'', ''myClass''); Thinking further, there are 65 Element.Methods. The passive ones are only 5: visible, match, hasClassName, empty, descendantOf All the rest are either action methods (addClassName, toggle, identify - we have invoke for these), DOM traversal ones (up, next, ancestors - those are usually invoked on a single element) and property related (getHeight, getStyle, getOpacity). The latter ones can be collected either way: someCollection.map(Element.Methods.getWidth) //or someCollection.collect(function(el){return el.getStyle(''opacity'')}) Just trying to figure out if it really makes sense to have it in a core. Best, http://thinkweb2.com/projects/prototype/ kangax -- View this message in context: http://www.nabble.com/Extension-for-writing-concise%2C-expressive-code-tf4497907.html#a12831702 Sent from the RubyOnRails Spinoffs mailing list archive at Nabble.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 -~----------~----~----~----~------~----~------~--~---
> My only suggestion would be to require an explicit call #toFunction() so > that it would be more obvious that it is an iterator functionPart of the rationale for this is that I''d like to avoid the cruft associated with writing ''function(foo) { return ...'' all the time, so I''d like to hide the conversion to a function behind the scenes. Especially in the case of hashes - you shouldn''t extend Object.prototype so you''d need to write $H({hasClassName: ''foo''}).toFunction() rather than just {hasClassName: ''foo''}, and this isn''t really a great saving over using regular functions. This is another reason why this isn''t possible:> someDivs.findAll([''hasClassName'', ''myClass'']); > following invoke''s philosophy it should be simply: > someDivs.findAll(''hasClassName'', ''myClass'');In 1.6.0, the second argument is the context to bind the iterator to, so I want to keep the first argument only for making iterator functions. How do we know whether that second argument should be a context for the iterator or an argument for it? Really, Arrays are only in there because they can be neater to use for functions with more than one argument. I''d tend to favour using a hash for this example. someDivs.findAll({hasClassName: ''myClass''}) ''invoke'' definately has its place and can be really neat, but I wanted to improve the readability of all the other Enumerable methods. Regarding CSS selectors: yes they are very useful, but my collection of DOM nodes may consist of some array pieced together from lots of different sources. Their properties may have changed, they may no longer be in the document, etc. Hence needing useful array methods to work with them. Also, I wasn''t just thinking of DOM nodes while writing this, I was thinking of just plain JavaScript as a language - objects, properties, methods etc and how good it would be to improve things like ''findAll'' and ''sortBy''. There''s no end to how complicated your own objects can get. Also, Prototype is moving towards having more interesting language features - stuff like Function#curry and the like. One last thing regarding these:> someCollection.map(Element.Methods.getWidth) > //or > someCollection.collect(function(el){return el.getStyle(''opacity'')})Yes, they will work, but neither is particularly elegant or intuitive. Especially the first one, which exposes Prototype''s ''internal'' implementation of a function rather than directly accessing an object''s own properties. Maybe I''ve been spoiled by Ruby, but I''d rather do this: someCollection.map(''getWidth'') //or someCollection.collect({getStyle: ''opacity''}) I do appreciate the input though, so thanks for chiming in. Best, James --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Nicolás Sanguinetti
2007-Sep-22 08:54 UTC
Re: Extension for writing concise, expressive code
I love this :) Specially the hashes for findAll, writing function(r) { return r.something == someOtherThing } gets tiring fast, and AR''s conditions hash was possibly one of the sexiest pieces of codes added to rails in the last few months. I''m not so sure about the chained.string.calls though, but it''s probably more of an aesthetic disagreement than anything else. I''ll test this out and give you my +1 if I find it doesn''t break anything -Nicolas On 9/21/07, jcoglan <jcoglan-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:> > > My only suggestion would be to require an explicit call #toFunction() so > > that it would be more obvious that it is an iterator function > > Part of the rationale for this is that I''d like to avoid the cruft > associated with writing ''function(foo) { return ...'' all the time, so > I''d like to hide the conversion to a function behind the scenes. > Especially in the case of hashes - you shouldn''t extend > Object.prototype so you''d need to write $H({hasClassName: > ''foo''}).toFunction() rather than just {hasClassName: ''foo''}, and this > isn''t really a great saving over using regular functions. This is > another reason why this isn''t possible: > > > someDivs.findAll([''hasClassName'', ''myClass'']); > > following invoke''s philosophy it should be simply: > > someDivs.findAll(''hasClassName'', ''myClass''); > > In 1.6.0, the second argument is the context to bind the iterator to, > so I want to keep the first argument only for making iterator > functions. How do we know whether that second argument should be a > context for the iterator or an argument for it? Really, Arrays are > only in there because they can be neater to use for functions with > more than one argument. I''d tend to favour using a hash for this > example. > > someDivs.findAll({hasClassName: ''myClass''}) > > ''invoke'' definately has its place and can be really neat, but I wanted > to improve the readability of all the other Enumerable methods. > > Regarding CSS selectors: yes they are very useful, but my collection > of DOM nodes may consist of some array pieced together from lots of > different sources. Their properties may have changed, they may no > longer be in the document, etc. Hence needing useful array methods to > work with them. Also, I wasn''t just thinking of DOM nodes while > writing this, I was thinking of just plain JavaScript as a language - > objects, properties, methods etc and how good it would be to improve > things like ''findAll'' and ''sortBy''. There''s no end to how complicated > your own objects can get. Also, Prototype is moving towards having > more interesting language features - stuff like Function#curry and the > like. > > One last thing regarding these: > > > someCollection.map(Element.Methods.getWidth) > > //or > > someCollection.collect(function(el){return el.getStyle(''opacity'')}) > > Yes, they will work, but neither is particularly elegant or intuitive. > Especially the first one, which exposes Prototype''s ''internal'' > implementation of a function rather than directly accessing an > object''s own properties. Maybe I''ve been spoiled by Ruby, but I''d > rather do this: > > someCollection.map(''getWidth'') > //or > someCollection.collect({getStyle: ''opacity''}) > > I do appreciate the input though, so thanks for chiming in. > > Best, > James > > > > >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Quick update: I''m working on allowing you to use operators as well, so you can do stuff like... // Find numbers divisible by 3... $R(1,10).reject([''%'', 3]) // -> [3, 6, 9] // Other crazy stuff someRandomJunk.findAll({''instanceof'': Number, ''>='': 4}) I''ve not released it yet, but source code is here: http://svn.jcoglan.com/reiterate/trunk. My guess is that the code required to make that happen is big enough to make it a questionable candidate for the core, but I''ll see what others think. James On Sep 22, 9:54 am, "Nicolás Sanguinetti" <godf...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I love this :) > > Specially the hashes for findAll, writing function(r) { return > r.something == someOtherThing } gets tiring fast, and AR''s conditions > hash was possibly one of the sexiest pieces of codes added to rails in > the last few months. > > I''m not so sure about the chained.string.calls though, but it''s > probably more of an aesthetic disagreement than anything else. > > I''ll test this out and give you my +1 if I find it doesn''t break anything > -Nicolas > > On 9/21/07, jcoglan <jcog...-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: > > > > > > My only suggestion would be to require an explicit call #toFunction() so > > > that it would be more obvious that it is an iterator function > > > Part of the rationale for this is that I''d like to avoid the cruft > > associated with writing ''function(foo) { return ...'' all the time, so > > I''d like to hide the conversion to a function behind the scenes. > > Especially in the case of hashes - you shouldn''t extend > > Object.prototype so you''d need to write $H({hasClassName: > > ''foo''}).toFunction() rather than just {hasClassName: ''foo''}, and this > > isn''t really a great saving over using regular functions. This is > > another reason why this isn''t possible: > > > > someDivs.findAll([''hasClassName'', ''myClass'']); > > > following invoke''s philosophy it should be simply: > > > someDivs.findAll(''hasClassName'', ''myClass''); > > > In 1.6.0, the second argument is the context to bind the iterator to, > > so I want to keep the first argument only for making iterator > > functions. How do we know whether that second argument should be a > > context for the iterator or an argument for it? Really, Arrays are > > only in there because they can be neater to use for functions with > > more than one argument. I''d tend to favour using a hash for this > > example. > > > someDivs.findAll({hasClassName: ''myClass''}) > > > ''invoke'' definately has its place and can be really neat, but I wanted > > to improve the readability of all the other Enumerable methods. > > > Regarding CSS selectors: yes they are very useful, but my collection > > of DOM nodes may consist of some array pieced together from lots of > > different sources. Their properties may have changed, they may no > > longer be in the document, etc. Hence needing useful array methods to > > work with them. Also, I wasn''t just thinking of DOM nodes while > > writing this, I was thinking of just plain JavaScript as a language - > > objects, properties, methods etc and how good it would be to improve > > things like ''findAll'' and ''sortBy''. There''s no end to how complicated > > your own objects can get. Also, Prototype is moving towards having > > more interesting language features - stuff like Function#curry and the > > like. > > > One last thing regarding these: > > > > someCollection.map(Element.Methods.getWidth) > > > //or > > > someCollection.collect(function(el){return el.getStyle(''opacity'')}) > > > Yes, they will work, but neither is particularly elegant or intuitive. > > Especially the first one, which exposes Prototype''s ''internal'' > > implementation of a function rather than directly accessing an > > object''s own properties. Maybe I''ve been spoiled by Ruby, but I''d > > rather do this: > > > someCollection.map(''getWidth'') > > //or > > someCollection.collect({getStyle: ''opacity''}) > > > I do appreciate the input though, so thanks for chiming in. > > > Best, > > James--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---