SassyLists moving to 2.x

Almost a year ago, I created a new GitHub repository called SassyLists to host a fancy library I was building back then. A few months later, the great folks at Team-Sass suggested I move the repo to their organisation so it gains some visibility. Agreed.

After almost 200 commits, SassyLists has known a version 1.x and recently moved to 2.x. It’s actually already in 2.2.3! Looking back at this project, I have to say I am quite proud with what I have came up with, so I would like to share the journey with you guys.

What’s SassyLists anyway?

SassyLists is a toolbox providing almost 40 functions to help working with Sass lists. You are probably not without knowing that lists are like arrays in Sass. Meanwhile, the default list API is very light therefore you might need some extra functions, especially if you are building a Sass framework or a robust grid system.

So you could tell SassyLists is basically a collection of functions that you can import and then use in your projects. It has absolutely no dependency except for Sass 3.3, and will work seemlessly.

While lists are not the Sass feature you could not live without, they are still cool. I have recently written about what you could do with a Sass list, so if you feel a little bit lost, be sure to have a look. In computer science, arrays are everywhere so it’s no surprise we can make use of them (under the name of lists) in Sass too!

Imagine a world without arrays!
— Me.

Thus here comes SassyLists. It aims at saving you from writing custom (and possibly complicated) Sass code when all you need are medium to advanced list functions for your project.

Tired of repeating nth($list, 1) and nth($list, -1) over and over again? Use first() and last(). Want to add a new value at first index in list? Here comes prepend()! Need a way to sort a list? sort() is there, using QuickSort algorithm. Have to slice a list between two indexes? slice() got you covered.

And here are just a few cases where SassyLists can help. With close to 40 functions, I am pretty sure you’ll find whatever you need and if you don’t, feel free to ask for a new feature! I’d be glad to implement it for you.

Note: actually all functions are prefixed with sl-* so it would be sl-first and sl-last for instance. This is meant to answer a feature request in which some users where suffering from naming conflicts with SassyLists.

No moar Compass

Version 2 brought quite a lot of changes! The biggest of all is probably the fact that it doesn’t rely on Compass anymore. The thing is SassyLists wasn’t using Compass at all, except for the extension manager so I adopted the same pattern as frameworks like Susy and Singularity: use Compass if it exists, else use Sass environment path.

extension_path   = File.expand_path(File.join(File.dirname(__FILE__), '..'))
stylesheets_path = File.join(extension_path, 'stylesheets')

if (defined? Compass)
  Compass::Frameworks.register('SassyLists', :path => extension_path)
  # compass not found, register on the Sass path via the environment.
  if ENV.has_key?("SASS_PATH")
    ENV["SASS_PATH"] = ENV["SASS_PATH"] + File::PATH_SEPARATOR + stylesheets_path
    ENV["SASS_PATH"] = stylesheets_path

This is a great step forward making SassyLists compatible with LibSass. As of today, SassyLists is not fully supported by LibSass because functions to-map and count-values both rely on maps which are not available yet. That being said, the chances are good that maps will be supported anytime soon, so ditching Compass was an important step on making SassyLists available on all platforms.

New functions

If there is one thing I really like, it’s building new functions in Sass. Version 2 added 5 functions, including some pretty nifty ones. For instance, some and every, like in JavaScript or any other programming language, to test whether some or all items from list pass the given test. Unfortunately, we cannot define anonymous functions in Sass, but we can use a mix of function-exists and call functions to make things work.

Also, someone asked for a is-empty function. I am not sure how I could forget to add such an obvious function for the past 9 months, but I suppose I somewhat stuck to length($list) == 0 during all this time! I took this as an opportunity to add a couple of helpers like has-values, has-multiple-values and is-single, so you can stop performing length check everywhere.

Last but not least, SassyLists v2 brought the to-map function (aliased as enumerate) from Andrey “Lolmaus” Mikhaylov which allow you to loop over a list while having access to indexes. Let me explain. Perhaps, you ever wanted to do this:

$list: a, b, c, d;

@each $index, $value in $list {
  // You want:
  // $index is 1, 2, 3, 4
  // $value is a, b, c, d

  // You have:
  // $index is a, b, c, d
  // $value is null, null, null, null

Unfortunately, this is not possible. A well known work around is to use a @for loop instead:

$list: a, b, c, d;

@for $index from 1 through length($list) {
  $value: nth($list, $i);

  // You have:
  // $index is 1, 2, 3, 4
  // $value is a, b, c, d

Not very elegant I suppose… Thanks to Andrey’s function, you can now do:

$list: a, b, c, d;

@each $index, $value in enumerate($list) {
  // You have:
  // $index is 1, 2, 3, 4
  // $value is a, b, c, d

It’s so simple yet very clever. All the enumerate function does is converting the list into a map where keys are indexes and values are items from list. Then, we loop over it like we do as a regular map with the @each $key, $value in $map syntax from Sass 3.3. How cool is that?

A dependency checker

I will not go too deep in this feature because it was the topic of a whole article at Tuts+.

To put it very simply, some functions depend on other functions. To prevent the compiler from crashing without appearant reason, those functions now start with this line:

@if missing-dependencies(the-required-function) { @return null; }

And the missing-dependencies function also outputs a warning message in the console explaining what’s going on. It’s not much, especially since SassyLists is likely to be used as a whole (in which case there can’t be any missing function), but that’s part of the little things that are nice having.

A SassDoc powered documentation

One thing I was really looking forward to do in version 2 was making SassyLists’s code documenting itself. After some days working on SassDoc project, I can finally tell SassyLists documentation is fully powered with it.

If you want to know more about SassDoc, I recently wrote an introduction to it here at SitePoint.

I am so glad because it was getting hard to keep the docs up to date with the code. There are about 40 files in the lib, with some cross-dependencies and keeping track of all the tiny fixes and updates was really annoying. Having the documentation generated from the comments is a bless.

Final thoughts

And there you have it guys: a standalone Sass library plugging on Compass if enabled, tested with Bootcamp and documented with SassDoc. Can’t recommand this workflow enough if you are building a library/framework in Sass.

Any feedback on SassyLists would be very much appreciated, and be sure to ask for new features if you think some things would be worth adding. Cheers!