Beans: Rubygems for Javascript

December 8, 2009
Javascript does not generally natively allow loading dependencies. This tends to mean that Javascript development is less modular than it could/should be. Code is ‘copied and pasted’ rather than ‘required’, which leads to code drift.
Beans is a development tool that attempts to fix this, by bringing Rubygems-like functionality to Javascript development, using a local (beans) server to act as the equivalent binary (e.g. gem), in particular Beans:
  • can be used in any environment (Ruby, Python, HTML).
  • has automatic dependency resolution, both global and relative
  • can be accessed from any page or server, even a vanilla HTML page
  • scripts are included simply by using <script> tag
  • javascripts are provided either as
    • a single concatenated script (e.g. for production)
    • multiple separate scripts (e.g. for debugging in development)
  • Entirely cross browser and works well with tools such as Firebug

Interacting with Bean Server

A Sinatra server (perhaps it should be a Node server :-) acts as a system wide provider for the javascript.

I tend to run the server under Passenger, and have it associated with http://beans/

http://beans/

  • Returns HTML page listing each file in the repos

http://beans/?.js

  • Returns HTML page showing each file who’s path matches “.js”

http://beans/path/to/my_file.ext

  • Finds a file with path /path/to/my_file.ext and returns it inline
  • This can be js, css, jpg or any file
  • No dependency resolution will occur
  • If there’s more than one repo that matches, it will return the first it finds

http://beans/=lib_a.js,lib_b.js

  • Searches the repo for two files, who’s paths matches lib_a.js and lib_b.js
  • If the files are javascripts, it will resolve dependencies (see below).
  • In this instance, let’s say that
    • lib_a depends on dep1, dep2
    • lib_b depends on dep1, dep3
  • Therefore the final scripts to load in order will be
    • dep1, dep2, lib_a, dep3, lib_b
  • There are multiple scripts to return, it will return a single script that writes out inclusion via document.write:
  • <script src=’http://beans/path/to/dep1.js’ ></script>
  • <script src=’http://beans/path/to/dep2.js’ ></script>
  • <script src=’http://beans/path/to/lib_a.js’ ></script>
  • <script src=’http://beans/path/to/dep3.js’ ></script>
  • <script src=’http://beans/path/to/lib_b.js’ ></script>

http://beans/=lib_a.js,lib_b.js?concat=true

  • If the option concat=true is passed, the bean-server will return the scripts as a single concatenated script.

http://beans/=lib_a.js,lib_b.js?paths=/abs/path,/abs/another/path

  • The paths option allows multiple temporary (absolute) load path

Dependencies

The syntax for declaring dependencies is the similar as Sprockets, ie they are entered within inline comments.
A slight difference is that the comments must be placed at the top of the file, before any code. This is because of the way Beans can provide each script separately and also speeds up the script parsing as the server can break as soon as a non-code line is reached.

//= require <my_lib>

This will do a global search in all load paths for a file matching my_lib.js and include it before this script

//= require “relative/path/to/my_file”

This will look for a file relatively to the current script.

Installation

git clone git://github.com/weepy/bean-server.git
cd bean-server
ruby app.rb

point browser at http://localhost:4567/test-beanz.html

Config

Currently there’s a simple settings.rb file that only contains the location of various repos

Javascript, CSS and HTML

The beans server is designed for serving particular javascript, however it can also search for and server css and HTML. E.g. http://beans/qunit/lib/test-suite.css will server up the Qunit test suite css. This is useful, among other things for writing and running tests in HTML to be bundled along with the source.

Comparison with other systems

Sprockets tries to achieve similar but not identical goals:

  • Beans uses a similar dependancy syntax as Sprockets
  • Beans is not tied to any language or framework, whereas Sprockets is invoked from Ruby
  • Sprockets includes the Javascript by concatenating into one single file. Beans can do this or optionally include each script as a separate file for ease of debugging.
  • Beans doesn’t (yet?) support providing assets from javascripts, although the server can search and return any other type of file
CommonJS
  • CommonJS provides a framework using require and exports
  • It is functionally different from Beans as it inserts the files into a closure, where as Beans evaluates everything in the global scope
  • CommonJS is suited more to server side development, whereas Beans is aimed at client side development (tho it can be used server side e.g. I’m using it on ChessTwit)

Project

Github: http://github.com/weepy/bean-server

Todo

Potential features that are not yet addressed:

  • Versioning, ownership
  • Canonical external resource (e.g. rubyforge, gemcutter)
  • minification

Node Eval: Evaluate Javascript using V8

December 6, 2009

Just realeased “Node Eval”, whiche allows arbitrary javascript to be evaluated using V8.

This is mostly useful for other servers to evaluate javascript, without needing a direct bridge. I’m using it in Ruby instead of Johnson (which seems to have problems with GC) which provides a nice degree of separation.

Use:

/eval?js=12*12 => {“success”:true,”result”:144}

/eval?js=12*a => {“success”:false,”exception”:”ReferenceError: a is not defined”}

Context is maintained

/eval?js=this.a=9 => {“success”:true,”result”:null}

/eval?js=12*a => {“success”:true,”result”:108}

It’s also possible to supply a source file on disk and a context name:

/eval?js=func()&file=/abs/path/to/file => {“success”:true,”result”: “func output ok”}

Note that to be able to call functions, you’ll need to expose them using the CommonJS “exports” declaration.

Github Page

http://github.com/weepy/node_eval


CSS in your face (only IE need to apply)

November 12, 2009

Download: http://github.com/weepy/cssie

Plugin for jQuery providing native support for missing CSS in IE. Currently provides:

  • E > F (direct descendant)
  • :hover (normally only available to a tags)
  • E + F (sibling)
  • [rel=attr] (attribute selection)
  • :first-child and any other selectors containing : and supported by jQuery
  • :focus
  • plus others

How it works

  • parses the stylesheets for rules that match a regex
  • replaces selectors that match with corresponding rules with an internal class .cssie-x (x is an integer)
  • add the class cssie-x using the original selector using jQuery
  • for :hover and :focus, automatically setup up jQuery events to add/remove the .cssie-x class upon hover/focus

Usage

  • include ‘cssie.js’ in your page after ‘jquery.js’
  • $.cssie() on the jQuery.ready event
  • You can cause the same behaviour on non MSIE browsers with: $.cssie(true)

UPDATE: it also handlers multiple class selectors (e.g .class_a.class_b)


chesstwit: using serverside javascript

November 12, 2009

After a week or two of beta testing and bug squashing, we’ve launched ChessTwit.

See it here => www.chesstwit.com

Picture 1

It’s goal is simple: make it easy to play chess online with your twit friends and I’m pretty pleased with the result. You can login without typing your password (OAuth) and your opponent is sent a Direct Message to inform them. Now we just need to hit critical mass.

From a technical perspective, it’s a fairly straight forward Rails project running on Passenger, with UI written in jQuery.

Where it gets interesting is that chess logic is written in Javascript, which means it can be used on both the UI and the server side validation. The fantastic ruby gem Johnson is then used server side to validate the moves.

I’m a big fan of this technique, so the Johnson gem is a god send. The alternative would be to write the logic twice in both ruby and javascript, something we did on 64squar.es. It works, but it’s a pain if you want to change the rules and great discipline is needed to keep the code bases in sync architecturally. So it worked ok for Chess, but any game where the rules are still in development, or if you want to produce many games it would be difficult.

We’ve got quite a few games apps planned for the future using this technique, so keep any eye out!


find_or_create

November 12, 2009

Perhaps I’m missing something here, but here’s a method that I often add into my Rails models

def self.find_or_create opts
  first(:conditions => opts) || create(opts)
end

It’s use is simple:

 Membership.find_or_create :channel_id, :user_id

Now there is a dynamic finder self.find_or_create_by_XXX, but it isn’t useful in the same way.

Is there a reason why something like that method isn’t in AR core ?


Growlesque plugin in 20 lines of code

October 23, 2009

Introducing Vanilla Notify !

After Playing around with _lots_ Growl style plugins for jQuery, I came to the impression that whilst they mostly looked nice, they all were very bloated and difficult to customize.

So – of course – I rolled my own! Only this one is different.It doesn’t have curvy corners, or callbacks, or other distractions. It’s solid, works well, looks pretty decent and – oh – it’s only _20_ lines of code!

Being simple means it’s very easy to understand and easy to change to your own tastes.

Screeny
Screeny

Installation

  • include vanilla-notify.js
  • depends on jQuery (1.3.2 tested)
  • include the relevant CSS somewhere

Examples

 $.notify('Hello')
 $.notify('<h1>Hello</h1><p>Hi there</p>')
 $.notify('With class: error', {klass: 'error' })
 $.notify("I'll be here for 7610.4 years!", {delay: 1e10 })

Links

Compatibility

Tested in

  • Firefox 3.5
  • Safari 4

Crazy worm bookmarklet

October 8, 2009

Can you handle the crazy worm ?



If you think you can go =>=>here <=<=


jQuery Sprite Factory

October 7, 2009

A jQuery factory for creating sprites from images, including transparent PNG’s in IE

Features

  • Works from a rectangluar grid of sprites.
  • Fast, good for rendering large numbers of similar sprites
  • Preloading CSS for large images (will add the ‘loading’ class to the element until the image has been loaded)
  • Can use transparent PNGS for IE6 and IE7
  • Light mode, using half the number of elements (only suitable for non-transparent images)
  • Easy to update sprite to a different index – useful for animation

Example of use

$().ready( function() {
  var options = {
                  src: "http://..." ,
                  width: 60,
                  height: 60,
                  index: [2,6],
                  light: true
                }
  var factory = new SpriteFactory(options)
  $("#mydiv")
    .append(factory.generate([1,2]))
    .append(factory.generate([1,3]))
})

Also see Demo

Options

  • ‘src’ => location of source image
  • ‘width’ => width of sprite
  • ‘height’ => height of sprite
  • ‘index’ => location of required sprite on image
  • ‘light’ => Only use one element (no good for IE6, IE7)

Links

Compatibility

Tested in

  • Firefox 3.5
  • Safari 4
  • IE 6, 7, 8

Bezier Curves and Arcs in jQuery

September 22, 2009

The animation engine in jQuery is focussed on single dimensional animation – hence it’s difficult to animate two variables along a path.

jQuery.path provides a method of multidimensional animation, and in particular provides a method for animating along bezier curves and arcs.

Bezier

Example: animate along a bezier path. See demo

var bezier_params = {
    start: {
      x: 185,
      y: 185,
      angle: 10
    },
    end: {
      x:540,
      y:110,
      angle: -10,
      length: 0.25
    }
  }

$("my_elem").animate({path : new $.path.bezier(bezier_params)})

Bezier curves are made form a start point, an end point each with a control point

  • start is starting point
  • end is the final point
  • x,y indicate the coordinates at that point. Required
  • angle is the angle of the control point from the line joining the start and end. Optional, default is 0
  • length is the distance from the point to it’s control point as a ratio of the distance from start to end. Optional, default is 1/3

Arc

Exampe: animate along an arc. See demo

var arc_params = {
    center: [285,185],
        radius: 100,
        start: 30,
        end: 200,
        dir: -1
  }

$("my_elem").animate({path : new $.path.arc(arc_params)})
  • center is the coords of the centre of an imaginary circle that contains the start and end point
  • radius is the radius of this circle
  • start is the angle of the start point. 0 is “North”, measured clockwise
  • end is the angle of the start point. 0 is “North”, measured clockwise
  • dir is the direction to move in. Only required if not obvious from start and end (e.g. if start is 100, end is 30, but you want to animate clockwise)

Other Paths

It is trivial to create other paths, or even animate other parameters. E.g:

var SineWave = function() {
  this.css = function(p) {
    var s = Math.sin(p*20)
    var x = 500 - p * 300
    var y = s * 50 + 150
    var o = ((s+2)/4+0.1)
    return {top: y + "px", left: x + "px", opacity: o}
  }
};

$("my_elem").animate({path : new SineWave})

Links


Hello world!

September 10, 2009

Welcome to our new blog. Focus will be on Javascript, jQuery, Ruby, Rails, perhaps some C#


Follow

Get every new post delivered to your Inbox.