<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-790672720914657075</id><updated>2024-10-04T22:12:18.416-07:00</updated><category term="javascript"/><category term="AJAX"/><category term="API design"/><category term="REST"/><category term="canvas"/><category term="frameworks"/><category term="iPhone"/><category term="prototype"/><category term="random"/><category term="tips"/><title type='text'>Stark Raving Coder</title><subtitle type='html'>The nearly lucid thoughts of a web developer.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-790672720914657075.post-3148822487726665831</id><published>2009-01-02T08:01:00.000-08:00</published><updated>2009-01-02T08:13:44.207-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="API design"/><category scheme="http://www.blogger.com/atom/ns#" term="frameworks"/><category scheme="http://www.blogger.com/atom/ns#" term="REST"/><title type='text'>Where are the REST frameworks?</title><content type='html'>&lt;p&gt;I like REST. I&amp;#8217;ll admit that I didn&amp;#8217;t understand all of &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm&quot;&gt;Dr. Roy Fielding&amp;#8217;s Dissertation&lt;/a&gt; (he is, after all writing to experts in the field of &lt;em&gt;API design&lt;/em&gt;) but I think that I&amp;#8217;ve managed to understand enough of it that Rails&amp;#8217; implementation of REST leaves a lot to be desired. Rails is not alone, many services are releasing APIs that they are calling REST. Dr. Fielding recently addressed this &lt;a href=&quot;http://roy.gbiv.com/untangled/2008/REST-apis-must-be-hypertext-driven&quot;&gt;in a post on his site&lt;/a&gt;. Like his thesis, he is talking to API designers, not to Joe and Jane Developer who needs to get the latest web site off the ground. Perhaps more practically,  Subbu Allamaraju gave the issue of REST and hyperlinking a &lt;a href=&quot;http://www.infoq.com/articles/subbu-allamaraju-rest&quot;&gt;thorough exfoliation over at InfoQ&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you read Subbu&amp;#8217;s article and compare it to the standard Rails 2.x web application you will quickly see that difference. In a rails application, if you &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; a &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; representation of our quintessential blog all you are going to be told is that the owner_id is 1232; your code has to know that Owners are Users and that they can be retrieved from http://api.example.com/users/{user_id}. This is like putting an &lt;code&gt;&amp;lt;img img_id=123&amp;gt;&lt;/code&gt; in your html and expect the browser to know to retrieve the file from http://www.example/resources/images/123.&lt;/p&gt;
&lt;p&gt;There is the comparison that most people who think they are writing REST APIs are forgetting; &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;. If you are writing a REST API then you are writing something &lt;span class=&quot;caps&quot;&gt;VERY&lt;/span&gt; much like &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt;. None of us are likely to need to create a REST API. I work for a financial institution and we &lt;em&gt;might&lt;/em&gt; have a need to create a REST API like &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; that is geared towards exchanging financial transactions between internal systems, our partners and our clients, but I suspect that would be unnecessary.&lt;/p&gt;
&lt;p&gt;No most of us have no need for creating a new REST API. What we should be talking about is publishing RESTful &lt;strong&gt;media types&lt;/strong&gt;. If I&amp;#8217;m going to build the archetypical Blog application, then I need media types for a Blog, a Post, a Comment, a Tag, an Author and what ever else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Note:&lt;/strong&gt; I&amp;#8217;m making a distinction that I don&amp;#8217;t think Dr. Fielding would make. Dr. Fielding makes it clear that the linking mechanism is central to a REST API, and since &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; leaves much of the linking mechanism (but certainly not all) up to the user agent, a true REST API requires a media types. However, the vast majority of the work that we do is over &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; so we have no need, in general, to worry about that half of a REST API. I think it &lt;strong&gt;greatly&lt;/strong&gt; clarifies things if we simply talk about creating &lt;strong&gt;REST Media Types&lt;/strong&gt; rather than APIs. I just noticed that &lt;a href=&quot;http://www.25hoursaday.com/weblog/2008/10/24/RESTAPIDesignInventMediaTypesNotProtocolsAndUnderstandTheImportanceOfHyperlinks.aspx&quot;&gt;I&amp;#8217;m not the first one to realize this&lt;/a&gt; (after Dr. Fielding of course).&lt;/p&gt;
&lt;h2&gt;What about the Frameworks&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve been trying to find a Ruby framework that can handle REST Media Types right out of the gate. &lt;a href=&quot;http://rubywaves.com/&quot;&gt;Waves&lt;/a&gt;, which its resource oriented architecture seems like a good place to start. They are right at the start of putting together what they call foundations for REST services. I&amp;#8217;m writing this article in part to influence how they go about that process.&lt;/p&gt;
&lt;h2&gt;REST &amp;#8800; MVC&lt;/h2&gt;
&lt;p&gt;One of the biggest problems is that people are trying to bolt REST onto &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; frameworks. The problem is it is probably the &lt;em&gt;wrong&lt;/em&gt; programming model to use. The controller for a REST service is absolutely trivial; you can only call a maximum of 4 methods on any given resource, and they are always handled the same, so the controller is completely anemic and should fall into the framework itself. Views are also the wrong paradigm since they only deal with out going representations; you really need some mechanism for specifying the transformation of a resources into a representation (that is its media type), &lt;strong&gt;and back&lt;/strong&gt;. All that you really have left are the resources (assuming they&amp;#8217;re like models) and the transformations.&lt;/p&gt;
&lt;h2&gt;REST and Your Web Application&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m probably going to annoy a lot of people with this. A web browser (as they are currently implemented) is &lt;span class=&quot;caps&quot;&gt;NOT&lt;/span&gt; a RESTful client. You can use &lt;span class=&quot;caps&quot;&gt;XHR&lt;/span&gt; object supplied by a browser&amp;#8217;s JavaScript engine as a REST client, but the browser itself interacting with plain old HTML cannot act RESTfully. In part, its because your browser won&amp;#8217;t make &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; requests (you have to fake it with extra parameters on a &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;). Mostly its a matter of usability.&lt;/p&gt;
&lt;p&gt;For a non-trivial use case, you are going to want to something wizard like. That means you are going to have to create a number of intermediate, transient representations to maintain that state. Its an affectation in this case. The transient representations serve no purpose but to maintain this fiction that its REST.&lt;/p&gt;
&lt;p&gt;I honestly think that you should really simply leave the your REST API as an API and build a separate application to act as your User Interface. You&amp;#8217;ll make it easier on yourself in the end&lt;/p&gt;
&lt;h2&gt;REST and MVC&lt;/h2&gt;
&lt;p&gt;Like I said earlier, &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; is not &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt;. But that doesn&amp;#8217;t mean that its not related to &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt;. MVC is very well suited to building a User Interface. As I said earlier, you should build a separate application for your User Interface. Well, there is &lt;strong&gt;no&lt;/strong&gt; reason why you can&amp;#8217;t use a Resource as the Model in your &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; application. Rails already does this; ActiveResource allows you to use a &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; Resource instead of a database table for your model.&lt;/p&gt;
&lt;p&gt;This is where things get &lt;strong&gt;really&lt;/strong&gt; interesting.&lt;/p&gt;
&lt;p&gt;If you are already using resource representations for the models in your &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; user interface, why limit yourself to a single domain? There is no reason why you couldn&amp;#8217;t use multiple domains. This allows for what I call &lt;span class=&quot;caps&quot;&gt;DMVC&lt;/span&gt;: &lt;strong&gt;Distributed&lt;/strong&gt; Model View Controller. By distributing your models over a number of applications (via &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; media types) you can get get some great &lt;em&gt;long term&lt;/em&gt; efficiencies by the serendipitous, and unplanned, reuse of &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; APIs.&lt;/p&gt;
&lt;p&gt;For example, if you have a non-trivial content management system, you are going to want to move your content changes from the author to an editor to perhaps a legal reviewer and maybe finally to a marketing manager before those changes are &amp;#8220;live&amp;#8221;. At the same time, you may have defect tracking system where defects move from reported, through any number of stages to completed. Traditionally, you would include something like &lt;code&gt;acts_as_statemachine&lt;/code&gt; in each of your rails apps to get this functionality.&lt;/p&gt;
&lt;p&gt;But if you apply the &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; architectural style, you can create 3 independent applications: Content Management, Defect Management, Workflow. The Workflow applciation would have something like a State resource which would be associated with some other resource without knowing anything about that resource. If the business logic was sufficiently complex (for instance, a change in the State resource would change the associated resource) you could create another application that combined a State resource with a (let&amp;#8217;s say) Defect resource to expose StatefulDefect resources.&lt;/p&gt;
&lt;p&gt;Also, because you have decoupled your the workflow from both your &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; and your defect tracking, you can reuse both to create a project management application where the content is not work flowed but managed wiki style and defects are not workflowed rather raised and closed since you have hourly builds to the project server (or what ever).&lt;/p&gt;
&lt;p&gt;We already know how to optimize and scale web servers, and the same can be done here. Or, if this is a purely internal set of services (or even largely) you could create a more efficient connection mechanisms/schemes than &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; (I&amp;#8217;m not sure what those would be). Or you might try more efficient media types (for example using &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; or even a binary format).&lt;/p&gt;
&lt;h2&gt;REST, Associations &amp;#38; ORM&lt;/h2&gt;
&lt;p&gt;One of the more valuable parts of Rails is the ActiveRecord &lt;span class=&quot;caps&quot;&gt;ORM&lt;/span&gt;. It allows you to say that a Blog belongs_to a User and a User has_many blogs. Associations between these objects are by ID as they refer to other records in the database.&lt;/p&gt;
&lt;p&gt;But &lt;span class=&quot;caps&quot;&gt;REST&lt;/span&gt; blows that apart. Your Blog and your User are no longer stored in the same database. We refer to every unique resource by a &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; so it may live somewhere totally unaccessible to us. If I have blogs and you have users, I can say that my blog belongs to a user, but I cannot expect your users will know anything about my blogs. Now perhaps the representation of the user that you give me includes a list of blogs that the user owns, in which case I can &lt;span class=&quot;caps&quot;&gt;PUT&lt;/span&gt; back a representation that includes the &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; of my Blog, but my code cannot rely on that information being known.&lt;/p&gt;
&lt;p&gt;You also get some interesting behaviours.&lt;/p&gt;
&lt;p&gt;All you have is a &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt;. You have NO idea what that resource is. As a result, its conceivable that I might try to create a blog that is &amp;#8220;owned&amp;#8221; by an image. Or the &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; point to a resource that is a legitimate owner of the blog but its media types are not those that the blog application understands. For the most part, that&amp;#8217;s OK because the blog application is really just an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, its not our User Interface. The User Interface application will need to have coping mechanisms for this but I&amp;#8217;m not sure that&amp;#8217;s a problem. If all you&amp;#8217;re producing is an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, then its not even your problem.&lt;/p&gt;
&lt;p&gt;More importantly, you get all sorts of strangely compelling polymorphism. Its liberating not to know what you&amp;#8217;re associated with since it guarantees that you&amp;#8217;ll become associated with all sorts of unexpected things.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/3148822487726665831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://starkravingcoder.blogspot.com/2009/01/where-are-rest-frameworks.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/3148822487726665831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/3148822487726665831'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/2009/01/where-are-rest-frameworks.html' title='Where are the REST frameworks?'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-790672720914657075.post-2103356383407024256</id><published>2007-10-25T15:46:00.000-07:00</published><updated>2007-10-25T16:26:36.751-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="random"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Random Strings</title><content type='html'>Today I created what is possibly the most efficient way to create a random string:

&lt;pre class=&quot;JavaScript script code&quot;&gt;&lt;code&gt;&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; randomString(length){
    &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; max = &lt;span class=&quot;literal string&quot;&gt;&quot;&quot;&lt;/span&gt;;
    &lt;span class=&quot;statement keyword&quot;&gt;for&lt;/span&gt; (i=&lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;;i&amp;lt;length; i++){
        max += &lt;span class=&quot;literal string&quot;&gt;&quot;z&quot;&lt;/span&gt;;
    }
    &lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;global builtin&quot;&gt;Math&lt;/span&gt;.round(&lt;span class=&quot;global builtin&quot;&gt;Math&lt;/span&gt;.random() * &lt;span class=&quot;function builtin&quot;&gt;parseInt&lt;/span&gt;(max, &lt;span class=&quot;literal number decimal&quot;&gt;36&lt;/span&gt;)).toString(&lt;span class=&quot;literal number decimal&quot;&gt;36&lt;/span&gt;).toUpperCase();
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So how, you ask, does it work? Well, it uses the fact that you can encode a number with any radix up to 36 which uses 0-9a-z. Perfect for creating a random string. SWe take the number of characters that we want and create our maximum encoded value (by repeating Z as often as necessary), and convert that into an integer. We then take that integer and use it as the upper bounds for a random number generator. We then convert that random number to a string using a radix of 36 and convert it to upper case for fun. &lt;/p&gt;

&lt;p&gt;I&#39;m not really thrilled about looping to create my max string but what can you do?&lt;/p&gt;

&lt;p&gt;It would be possible to create strings without numbers by using a radix of 26 and mapping numbers to letters after the fact, but that&#39;s a lot of extra work.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/2103356383407024256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://starkravingcoder.blogspot.com/2007/10/random-strings.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/2103356383407024256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/2103356383407024256'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/2007/10/random-strings.html' title='Random Strings'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-790672720914657075.post-212599191228042116</id><published>2007-10-04T09:00:00.000-07:00</published><updated>2007-10-04T09:28:52.712-07:00</updated><title type='text'>Things I&#39;d like to see in JavaScript</title><content type='html'>&lt;span style=&quot;font-weight:bold;&quot;&gt;&lt;/span&gt;&lt;p&gt;Recently, someone asked me what features I&#39;d like to see added to JavaScript. In the week or so since then I&#39;ve had some time to think about it. Here are some of my thoughts:&lt;/p&gt;
&lt;h4&gt;Code inclusion&lt;/h4&gt;
&lt;p&gt; Right now, when we want to dynamically includes some javascript on the fly (for instance to ensure that we only load the features that we need) we have to resort to document.writing a script tag. This is exceptionally inefficient. I would be nicer if we could explicitly include javascript files using something like: &lt;code&gt;includeScript(&#39;/scripts/myScript.js&#39;)&lt;/code&gt;. It might be nice to allow a call back function to be passed along too. &lt;/p&gt;
&lt;h4&gt;Site persistent JavaScript&lt;/h4&gt;
&lt;p&gt;Currently, every time you unload a page, the compiled javascript is tossed out the door and new javascript is compiled when the next page loads. I don&#39;t know about you, but 80% of my code doesn&#39;t change page by page. It would be great if we had a way to &quot;save&quot; our compiled JavaScript and simply reuse it on each page. This way, I can load my libraries once and never have to worry about it again. It would also be necessary to identify some code that lasts only for a single session and some that lasts &quot;forever&quot; (same idea as with persistent cookies)&lt;/p&gt;
&lt;h4&gt;Native set objects&lt;/h4&gt;
&lt;p&gt;In the past I&#39;ve run into confusion with some of the new Array methods that are being introduced by Mozilla. Specifically, it turns out that &lt;code&gt;[].any(function (){return true;}) !== [].all(function (){return true;});&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I chatted with some of the Mozilla guys about this they said that this has to do with set math. That got me to thinking about sets in general. There are some things that one can do with sets that are generally useful.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can intersect, union, difference sets. Calculating the intersection of two sets (lets say sets of DOM Nodes) can be exceptionally useful. &lt;/li&gt;
&lt;li&gt;Every member of a set is unique. Again this is a useful feature for working with collection of DOM Nodes. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are other features of sets that I would like to be able to use. I could build a JavaScript implementation of a set but its MUCH slower than a native implementation would be. Since its generally useful, its worth adding to the language&lt;/p&gt;
&lt;h4&gt;Date Literals&lt;/h4&gt;
&lt;p&gt;Since strict JSON only allows literal notation, there is currently no way to include real dates in a JSON construct. Dates are one of the most useful objects we have in JavaScript and having a literal for it would be wonderful. &lt;/p&gt;
&lt;p&gt;Those are my ideas. What do you think would be a good addition?&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/212599191228042116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://starkravingcoder.blogspot.com/2007/10/things-id-like-to-see-in-javascript.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/212599191228042116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/212599191228042116'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/2007/10/things-id-like-to-see-in-javascript.html' title='Things I&#39;d like to see in JavaScript'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-790672720914657075.post-3744453602941692270</id><published>2007-09-27T21:13:00.000-07:00</published><updated>2007-09-27T22:44:14.720-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AJAX"/><category scheme="http://www.blogger.com/atom/ns#" term="canvas"/><category scheme="http://www.blogger.com/atom/ns#" term="iPhone"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Canvas Loading Indicator</title><content type='html'>If any of you have been writing Web 2.0 apps for the iPhone, you will have realized by now that it doesn&#39;t allow you to use animated gifs. This is a bit of a problem since you want to provide some sort of feedback to the user if you&#39;re waiting for some data to load. Normally you would show something like what you find at http://www.ajaxload.info/.

The other thing you might know is that you can use the canvas with the iPhone. Clearly the solution to the problem is to use the canvas to draw your indicator. I looked and couldn&#39;t find anyone who had built one.

So I wrote one. Turns out, if you keep things simple, its relatively easy to write your basic spinner.
&lt;pre class=&quot;JavaScript script code&quot;&gt;&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; getLoading(context, bars, center, innerRadius, size, color) {
&lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; animating = &lt;span class=&quot;literal boolean keyword&quot;&gt;true&lt;/span&gt;,
    currentOffset = &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;;

&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; makeRGBA(){
    &lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;literal string&quot;&gt;&quot;rgba(&quot;&lt;/span&gt; + [].slice.call(&lt;span class=&quot;local builtin&quot;&gt;arguments&lt;/span&gt;, &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;).join(&lt;span class=&quot;literal string&quot;&gt;&quot;,&quot;&lt;/span&gt;) + &lt;span class=&quot;literal string&quot;&gt;&quot;)&quot;&lt;/span&gt;;
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; drawBlock(ctx, barNo){
    ctx.fillStyle = makeRGBA(color.red, color.green, color.blue, (bars+&lt;span class=&quot;literal number decimal&quot;&gt;1&lt;/span&gt;-barNo)/(bars+&lt;span class=&quot;literal number decimal&quot;&gt;1&lt;/span&gt;));
    ctx.fillRect(-size.width/&lt;span class=&quot;literal number decimal&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;, size.width, size.height);
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; calculateAngle(barNo){
    &lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;literal number decimal&quot;&gt;2&lt;/span&gt; * barNo * &lt;span class=&quot;global builtin&quot;&gt;Math&lt;/span&gt;.PI / bars;
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; calculatePosition(barNo){
    angle = calculateAngle(barNo);
    &lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt; {
        y: (innerRadius * &lt;span class=&quot;global builtin&quot;&gt;Math&lt;/span&gt;.cos(-angle)),
        x: (innerRadius * &lt;span class=&quot;global builtin&quot;&gt;Math&lt;/span&gt;.sin(-angle)),
        angle: angle
    };
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; draw(ctx, offset) {
    clearFrame(ctx);
    ctx.save();
    ctx.translate(center.x, center.y);
    &lt;span class=&quot;statement keyword&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;; i&amp;lt;bars; i++){
        &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; curbar = (offset+i) % bars,
            pos = calculatePosition(curbar);
        ctx.save();
        ctx.translate(pos.x, pos.y);
        ctx.rotate(pos.angle);
        drawBlock(context, i);
        ctx.restore();
    }
    ctx.restore();
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; clearFrame(ctx) {
    ctx.clearRect(&lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
}
&lt;span class=&quot;statement keyword declaration&quot;&gt;function&lt;/span&gt; nextAnimation(){
    &lt;span class=&quot;statement keyword&quot;&gt;if&lt;/span&gt; (!animating) {
        &lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt;;
    };
    currentOffset = (currentOffset + &lt;span class=&quot;literal number decimal&quot;&gt;1&lt;/span&gt;) % bars;
    draw(context, currentOffset);
    setTimeout(nextAnimation, &lt;span class=&quot;literal number decimal&quot;&gt;50&lt;/span&gt;);
}
nextAnimation(&lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;);
&lt;span class=&quot;statement keyword&quot;&gt;return&lt;/span&gt; {
    stop: &lt;span class=&quot;operator keyword&quot;&gt;function&lt;/span&gt; (){
        animating = &lt;span class=&quot;literal boolean keyword&quot;&gt;false&lt;/span&gt;;
        clearFrame(context);
    },
    start: &lt;span class=&quot;operator keyword&quot;&gt;function&lt;/span&gt; (){
        animating = &lt;span class=&quot;literal boolean keyword&quot;&gt;true&lt;/span&gt;;
        nextAnimation(&lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;);
    }
};
}&lt;/pre&gt;This is a fair chunk of code but its not entirely clear how you use it. Its actually quite simple. Assuming you have a canvas to work with, All you do is call
&lt;pre class=&quot;JavaScript script code&quot;&gt;&lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; controller = getLoading(canvas.getContext(&lt;span class=&quot;literal string&quot;&gt;&quot;2d&quot;&lt;/span&gt;), &lt;span class=&quot;literal number decimal&quot;&gt;9&lt;/span&gt;, {x:&lt;span class=&quot;literal number decimal&quot;&gt;100&lt;/span&gt;, y:&lt;span class=&quot;literal number decimal&quot;&gt;100&lt;/span&gt;}, &lt;span class=&quot;literal number decimal&quot;&gt;10&lt;/span&gt;, {width: &lt;span class=&quot;literal number decimal&quot;&gt;2&lt;/span&gt;, height:&lt;span class=&quot;literal number decimal&quot;&gt;10&lt;/span&gt;}, {red: &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;, green: &lt;span class=&quot;literal number decimal&quot;&gt;17&lt;/span&gt;, blue: &lt;span class=&quot;literal number decimal&quot;&gt;58&lt;/span&gt;});&lt;/pre&gt;The getLoading function takes a 2d context, the number of bars that you want your indicator to use, the X and Y coordinates of the center of the indicator, the radius of the inner portion of the indicator the height and width of each of the bars of the indicator and, finally, the color you want to use for the indicator. We ask for the components of the color separately because each spoke of the indicator gets a progressively smaller alpha value.

The function returns a simple object with two methods, &lt;code&gt;start()&lt;/code&gt; and &lt;code&gt;stop()&lt;/code&gt;. The indicator is created spinning.

If you wanted a more fancy set of spokes, all you would really have to do is rewrite the &lt;code&gt;drawBlock&lt;/code&gt; function.

Blogger seems to strip out script tags so there&#39;s no real way to provide a test (expect maybe a honkin huge bookmarklet) so if you want to try it out, copy the script and he following:

&lt;pre class=&quot;JavaScript script code&quot;&gt;&lt;span class=&quot;operator keyword&quot;&gt;function&lt;/span&gt; (){
  &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; canvas = &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.createElement(&lt;span class=&quot;literal string&quot;&gt;&quot;canvas&quot;&lt;/span&gt;);
  canvas.width= &lt;span class=&quot;literal number decimal&quot;&gt;200&lt;/span&gt;;
  canvas.height = &lt;span class=&quot;literal number decimal&quot;&gt;200&lt;/span&gt;;
  canvas.style.cssText=&lt;span class=&quot;literal string&quot;&gt;&quot;position:absolute; top:100px; left:100px; background:#transparent; border: 3px solid red&quot;&lt;/span&gt;;
  &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.body.appendChild(canvas);
  &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; controller = getLoading(canvas.getContext(&lt;span class=&quot;literal string&quot;&gt;&quot;2d&quot;&lt;/span&gt;), &lt;span class=&quot;literal number decimal&quot;&gt;9&lt;/span&gt;, {x:&lt;span class=&quot;literal number decimal&quot;&gt;100&lt;/span&gt;, y:&lt;span class=&quot;literal number decimal&quot;&gt;100&lt;/span&gt;}, &lt;span class=&quot;literal number decimal&quot;&gt;10&lt;/span&gt;, {width: &lt;span class=&quot;literal number decimal&quot;&gt;2&lt;/span&gt;, height:&lt;span class=&quot;literal number decimal&quot;&gt;10&lt;/span&gt;}, {red: &lt;span class=&quot;literal number decimal&quot;&gt;0&lt;/span&gt;, green: &lt;span class=&quot;literal number decimal&quot;&gt;17&lt;/span&gt;, blue: &lt;span class=&quot;literal number decimal&quot;&gt;58&lt;/span&gt;});

  &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; button1 = &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.createElement(&lt;span class=&quot;literal string&quot;&gt;&quot;input&quot;&lt;/span&gt;);
  button1.value=&lt;span class=&quot;literal string&quot;&gt;&quot;stop&quot;&lt;/span&gt;;
  button1.type=&lt;span class=&quot;literal string&quot;&gt;&quot;button&quot;&lt;/span&gt;;
  button1.onclick = &lt;span class=&quot;operator keyword&quot;&gt;function&lt;/span&gt; (){
      controller.stop();
  };
  &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.body.appendChild(button1);

  &lt;span class=&quot;statement keyword declaration&quot;&gt;var&lt;/span&gt; button2 = &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.createElement(&lt;span class=&quot;literal string&quot;&gt;&quot;input&quot;&lt;/span&gt;);
  button2.value=&lt;span class=&quot;literal string&quot;&gt;&quot;start&quot;&lt;/span&gt;;
  button2.type = &lt;span class=&quot;literal string&quot;&gt;&quot;button&quot;&lt;/span&gt;;
  button2.onclick = &lt;span class=&quot;operator keyword&quot;&gt;function&lt;/span&gt; (){
      controller.start();
  };
  &lt;span class=&quot;global builtin host&quot;&gt;document&lt;/span&gt;.body.appendChild(button2);
})();&lt;/pre&gt;

in firebug and it should be fine.</content><link rel='replies' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/3744453602941692270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://starkravingcoder.blogspot.com/2007/09/canvas-loading-indicator.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/3744453602941692270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/3744453602941692270'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/2007/09/canvas-loading-indicator.html' title='Canvas Loading Indicator'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-790672720914657075.post-5038491076374151372</id><published>2007-08-23T22:28:00.000-07:00</published><updated>2007-08-24T08:22:27.140-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="prototype"/><title type='text'>Curried What Now?</title><content type='html'>&lt;p&gt;With the release of Prototype 1.6.0 release candidate, we now have a new way to do things. We can now write curried functions.&lt;/p&gt;&lt;p&gt;Show of hands, how many of you know what a curried function is? I thought so. I first encountered currying about a year ago via &lt;a href=&quot;http://javascript.crockford.com/&quot;&gt;Doug &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;Crockfords&lt;/span&gt; site&lt;/a&gt; which brought me to &lt;a href=&quot;http://www.svendtofte.com/code/curried_javascript/&quot;&gt;Svend &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;Tofte&lt;/span&gt;’s article on it&lt;/a&gt;. Perhaps its because I’m stark raving mad, but I immediately fell in love with the technique and tried to find ways to use it. &lt;/p&gt;&lt;p&gt;I&#39;ve shown the article to others but few have really seen the potential as I have. I think its hard to get your head around it without examples. &lt;/p&gt;&lt;h2&gt;The &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;canonical&lt;/span&gt; example&lt;/h2&gt;&lt;p&gt;It seems that every description of curried functions starts with something like the following, which &lt;a href=&quot;http://www.prototypejs.org/2007/8/15/prototype-1-6-0-release-candidate&quot;&gt;Sam Stephenson used to announce the release of Prototype 1.6.0 &lt;span class=&quot;caps&quot;&gt;RC1&lt;/span&gt;&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function sum(a, b) {
return a + b;
}
sum(10, 5) // 15
var &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;addTen&lt;/span&gt; = sum.curry(10);
&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;addTen&lt;/span&gt;(5)  // 15
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The explanation is that you can write some function, and call it with some of the arguments defined, and then call it later with the rest of the arguments. That is all well and good but how on earth would you want to use it in a real situation?&lt;/p&gt;&lt;h2&gt;Real uses for curry&lt;/h2&gt;&lt;p&gt;Curried functions are all about not repeating yourself more than you have to. Don’t think of it as calling some function many times with some of the same arguments. Think of it as creating a specific function out of a more general function. That is probably not any more enlightening so a less trivial example might be illustrative.&lt;/p&gt;&lt;h3&gt;Alerting buttons&lt;/h3&gt;&lt;p&gt;This is probably not a much more complex example, but I think it starts providing an explanation. What we are going to do is have a page with 5 buttons. When the button is clicked, we are going to alert a number which is randomly assigned to that button (each button will have 1 random number assigned to it). We might right this as follows:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;alertMessageEventHandler&lt;/span&gt;(&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;evt&lt;/span&gt;){
alert(this._message);
}

$$(&quot;#&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_7&quot;&gt;ButtonList&lt;/span&gt; button&quot;).each(function (button){
button._message = &quot;Your random number is:\n&quot; + Math.round(100 * Math.random());
button.observe(&quot;click&quot;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_8&quot;&gt;alertMessageEventHandler&lt;/span&gt;);
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is going to work just fine but lets see how we can rewrite it using curry:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_9&quot;&gt;alertMessageEventHandler&lt;/span&gt;(&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_10&quot;&gt;msg&lt;/span&gt;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_11&quot;&gt;evt&lt;/span&gt;){
alert(&quot;curried&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_12&quot;&gt;msg&lt;/span&gt;);
}

$$(&quot;#&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_13&quot;&gt;ButtonList&lt;/span&gt; button&quot;).each(function (button){
var message = &quot;Your random number is:\n&quot; + Math.round(100 * Math.random());
button.observe(&quot;click&quot;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_14&quot;&gt;alertMessageEventHandler&lt;/span&gt;.curry(message));
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is obviously almost as trivial as our sum function above but it gets the point across. &lt;/p&gt;&lt;h3&gt;Validation&lt;/h3&gt;&lt;p&gt;While its all well and good to provide trivial example, sometimes its more illustrative if we have a robust example. So lets see what we can come up with. &lt;/p&gt;&lt;p&gt;Imagine that we want to build a validation system for forms. We know that we want to define, for any given field, a series of tests to which a value is subjected and we want to get back a list of the tests that failed so that we can display error messages. &lt;/p&gt;&lt;p&gt;Lets start with a simple validation function. It will take the value to be tested and an array of testing objects. It will return an array of failed testing objects (which would be further used to produce the error message). &lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_15&quot;&gt;isValid&lt;/span&gt; (value, tests) {
return tests.reject(function (&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_16&quot;&gt;aTest&lt;/span&gt;){
return &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_17&quot;&gt;aTest&lt;/span&gt;.test(value);
});
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a really small function but I think we can all see what it does. We loop through each element in tests and call its &quot;test&quot; function passing in the value to test in. If the test function returns true, then we know that the value passed that test and we boot it out of our array. We can use our new function by creating an array of tests:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_18&quot;&gt;isLessThanSeven&lt;/span&gt;(val) {
return val &lt;&gt; 2;
}
function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_19&quot;&gt;isMultiplOfThree&lt;/span&gt;(val) {
return (val % 3) == 0;
}
var test1 = [
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_20&quot;&gt;isLessThanSeven&lt;/span&gt;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_21&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be less than 7&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_22&quot;&gt;isGreaterThanTwo&lt;/span&gt;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_23&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be greater than 2&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_24&quot;&gt;isMultiplOfThree&lt;/span&gt;, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_25&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be a multiple of 3&quot;}
];
console.debug(&quot;3:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_26&quot;&gt;isValid&lt;/span&gt;(3, test1).length)
console.debug(&quot;10:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_27&quot;&gt;isValid&lt;/span&gt;(10, test1).length)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a rather simple test. In the first test we should pass all the tests (thus have a length of 0) and in the second we should fail 2 test. &lt;/p&gt;&lt;p&gt;The problem with this sort of thing is that we end up repeating ourselves with all our little test functions. This is where curry comes in. If we get a little more generic we can reuse some code easily:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_28&quot;&gt;isLessThan&lt;/span&gt;(comparison, val){
return (val &lt;&gt; comparison );
}
function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_29&quot;&gt;isMultiple&lt;/span&gt;(divisor, val){
return (val % divisor) == 0;
}
var test2 = [
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_30&quot;&gt;isLessThan&lt;/span&gt;.curry(7), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_31&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be less than 7&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_32&quot;&gt;isGreaterThan&lt;/span&gt;.curry(2), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_33&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be greater than 2&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_34&quot;&gt;isMultiple&lt;/span&gt;.curry(3), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_35&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be a multiple of 3&quot;}
];

console.debug(&quot;3:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_36&quot;&gt;isValid&lt;/span&gt;(3, test2).length)
console.debug(&quot;10:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_37&quot;&gt;isValid&lt;/span&gt;(10, test2).length)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can now reuse our &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_38&quot;&gt;isLessThan&lt;/span&gt; and other functions in many places and never repeat ourselves.&lt;/p&gt;&lt;h2&gt;Coding&lt;/h2&gt;&lt;p&gt;The question that remains is where and when to use curried functions. There are a few things to look for. The first is a function that you are calling frequently with the similar collections of arguments. In this case, set things up so that you curry the function with your common arguments and save the result and call it later (like in the canonical example). The second is somewhat simpler. Look for situations where you are storing some value on an element so that you can use it in an event handler (like in the alerting buttons example). Finally (and this is the hard one) you need to find combinations of functions that are fundamentally similar and consolidate them into functions that you curry as needed. &lt;/p&gt;&lt;p&gt;The easiest way to write a function for currying is to reverse the order of your arguments. Its &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_39&quot;&gt;counter intuitive&lt;/span&gt; but if you think about, we typically put the most important arguments first. Often those are also the ones that are most likely to change between calls. So if we put it at the end then we can more easily use curry. &lt;/p&gt;&lt;p&gt;In fact if we reorder the &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_40&quot;&gt;arguments&lt;/span&gt; of our &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_41&quot;&gt;isValid&lt;/span&gt; function, we can curry it and simplify things. &lt;/p&gt;&lt;pre&gt;&lt;code&gt;
function &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_42&quot;&gt;isValidCurry&lt;/span&gt; (tests, value) {
//we assume that tests is an array of objects which look like:
//{
//    test: function (value){return true;},
//    error: 120
//}
return tests.reject(function (&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_43&quot;&gt;aTest&lt;/span&gt;){
   return &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_44&quot;&gt;aTest&lt;/span&gt;.test(value);
});
}

var test3 = [
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_45&quot;&gt;isLessThan&lt;/span&gt;.curry(7), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_46&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be less than 7&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_47&quot;&gt;isGreaterThan&lt;/span&gt;.curry(2), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_48&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be greater than 2&quot;},
{test: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_49&quot;&gt;isMultiple&lt;/span&gt;.curry(3), &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_50&quot;&gt;errorMessage&lt;/span&gt;: &quot;Must be a multiple of 3&quot;}
];

var &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_51&quot;&gt;validateTestThree&lt;/span&gt; = &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_52&quot;&gt;isValidCurry&lt;/span&gt;.curry(test3);
console.debug(&quot;3:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_53&quot;&gt;validateTestThree&lt;/span&gt;(3).length);
console.debug(&quot;10:&quot; + &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_54&quot;&gt;validateTestThree&lt;/span&gt;(10).length);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So how do you like your curry?&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://starkravingcoder.blogspot.com/feeds/5038491076374151372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://starkravingcoder.blogspot.com/2007/08/curried-what-now.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/5038491076374151372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/790672720914657075/posts/default/5038491076374151372'/><link rel='alternate' type='text/html' href='http://starkravingcoder.blogspot.com/2007/08/curried-what-now.html' title='Curried What Now?'/><author><name>Adam</name><uri>http://www.blogger.com/profile/01904288989952968498</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2nd6cripVzGKbQ5J9I2WzoJcCLVxebj-zvGMGp-_Q2RmExE98bOVWwFHyCEzFmwqOVuM4PVVYRekL88Aqe37FNXGOdCMJ3Qw10HTfn-VelUTh5lRXZ54YKWIkzs9mPA/s1600-r/7dffff02e30a251f0eec8f22940726a4?s=80'/></author><thr:total>1</thr:total></entry></feed>