====
What is Luc?
Luc is a lightweight JavaScript framework that is built from the ground up targeting all browsers and Node.js. Luc provides a class system that can add compositions, mixins and statics functionality to any class without messing up the inheritance chain. Luc comes with over 40 utility Array/Object/Function methods along with over 150 Array utility methods that follow the same API and grammar. It also comes with the ability to add EventEmiter and Plugin functionality to any pre existing class. Luc has zero dependencies and currently sits at less than 650 SLOC and it is less than 7.5Kb minified and gzipped.
Node
npm install luc
Browser
Download the latest zip or check out the hosted build files luc, luc-es5-shim. Source maps come packaged with the non minified versions.
Supported Browsers
- IE8 - latest with tentative support for IE6/7 (Our tests currently pass in them now)
- FF3 - latest
- Chrome
- Opera
- Safari 5.1 - latest
- Tentative support for mobile (Our tests pass for the platforms that we are testing)
Examples/Code
For in depth examples and API documentation check out our docs.
Class System
Simple define
Luc.define just takes the passed in config and puts the properties on the prototype and returns a Constructor.
var C = Luc;var c = ;c;>1ca = 45;c;>45cdoLog = false;c; >1
Simple super class
{ thiscount = 0; }; Counterprototype = { return thiscount; } { thiscount++; } var C = Luc; var c = c instanceof Counter>truec;c;>1ccount>1
Call a super's method:
var C = Luc;
It can also be done this way:
var C = Luc;
var c = ; c; ccount >3
Compositions
Compositions allow the ability to add functionality to any class without changing or messing up the inheritance chain. They are more powerful than mixins because they don't have to worry about putting a state on classes using them or have to know that they may be a mixin or a standalone class.
var C = Luc; var c = ; c; c; >1 2 3 "a" c instanceof LucEventEmitter >false
Default Compositions
Luc comes with two default composition objects.
Luc.compositionEnums.EventEmitter
Luc.EventEmitter is preferred as a composition over a mixin because it adds a state "_events" to the this instance when on is called.
var C = Luc; var c = ; c; c; >1 2 3 "a" c instanceof LucEventEmitter >false c_events >undefined
Luc.compositionEnums.PluginManager
The PluginManager adds a plugin functionality to any Class. Check out the methods that get added to the instance and more info in the docs
A plugin follows the following life-cycle:
plugin is added to the instance -> plugin is created -> plugin init is called with instance -> if needed destroy called by instance -> destroy called on plugin
Here is the most basic example using the default plugin.
var C = Luc; var c = plugins: { console } myCoolName: 'cool' ; >im getting initted c instanceof LucPlugin > true
Plugins can be of any class and can be added with addPlugin
{} var C = Luc; var c = ; c; //getPlugin takes a Constructor or match object c instanceof MyPlugin >true c >false
Plugins can also be destroyed individually or all of them at once.
var C = Luc; var c = plugins: { console } { console } name: '1' { console } { console } name: '2' ; >im getting initted 1 >im getting initted 2 c; >destroyed : 1 >Plugin ; >false c.destroyAllPlugins(); >destroyed : 2
Mixins
Mixins are a way to add functionality to a class that should not add state to the instance unknowingly. Mixins can be either objects or Constructors.
{} Loggerprototype { console } var C = Luc; var c = ; c >12 c >34
Statics
Statics are good for defining default configs.
var C = Luc; var c = ; cnumber >undefined Cnumber >1
Using statics prevent subclasses and instances from unknowingly modifying all instances.
var C = Luc; var c = ; ccfga >1 ccfga = 5 cfga >5
$class
Every class defined with Luc.define will get a reference to the instance's own constructor.
var C = Luc var c = c$class === C >true
There are some really good use cases to have a reference to it's
own constructor.
Add functionality to an instance in a simple
and generic way:
var C = Luc; //Luc.Base applies first //arg to the instance var c = { return this$classprototypeadd + c; } ; c >6 >3
Or have a simple generic clone method :
var C = Luc; var c = a:1b:2c:3; cd = 4; var clone = c; clone === c >false clonea >1 cloneb >2 clonec >3 cloned >4
Luc.Base
Luc.Base is the default class of for define. It is a simple class that by default applies the first argument to the instance and then calls Luc.Base.init, init is just an emptyFn which is meant to be overwritten by the defining class.
var b = a: 1 { console }ba>hey>1
We found that most of our classes do this so we made it the default. Having a config object as the first and only param keeps a clean api as well.
var C = Luc; var c = items: 123;>1>2>3var d = items: 'A';>'A'var e = ;
If you don't like the applying of the config to the instance it can always be "disabled"
var NoApply = Luc; var c = items: 123;
Array, Object, Function and other utility functions
Luc.is*
- Luc.isArguments
- Luc.isArray
- Luc.isDate
- Luc.isEmpty
- Luc.isFalsy
- Luc.isNumber
- Luc.isObject
- Luc.isRegExp
- Luc.isString
- Luc.isFunction
Luc.isFalsy
Return true if the object is falsy but not zero.
Luc >true Luc >false
Luc.isEmpty
Return true if the object is empty. {}, [], '',false, null, undefined, NaN are all treated as empty.
Luc>falseLuc>true
The native js type methods work as you think they should.
Luc>falseLuc>true
You can see that we don't have an isNull isUndefined or isNaN. We prefer to use:
obj === nullobj === undefined
Luc.Object
Luc.Object.apply / Luc.apply
Apply the properties from fromObject to the toObject. fromObject will overwrite any shared keys. It can also be used as a simple shallow clone.
var to = a:1 c:1 from = a:2 b:2LucObject>Object a: 2 c: 1 b: 2to === to>truevar clone = LucObject>undefinedclone>Object a: 2 b: 2clone === from>false
No null checks are needed.
Luc>a:1Luc>a:1
Luc.Object.mix / Luc.mix
Similar to Luc.Object.apply except that the fromObject will NOT overwrite the keys of the toObject if they are defined.
Luc>a: 1 b: 2 c: 5
No null checks are needed.
Luc>a:1Luc>a:1
Luc.Object.each
Iterate over an objects properties as key value "pairs" with the passed in function.
var thisArg = val:'c';LucObject>"Luc"
Luc.Object.filter
Return key value pairs from the object if the filterFn returns a truthy value.
LucObject>key: 'a' value: false key: 'b' value: true LucObject>'a' 'b'
Luc.Array
Luc is optionally packaged with es5 shim so you can write es5 code in non es5 browsers. It comes with your favorite Array methods such as Array.forEach, Array.filter, Array.some, Array.every Array.reduceRight ..
Luc.Array.toArray
Take an object and turn it into an array if it isn't one.
LucArray > LucArray > LucArray >1 LucArray >1 2
Luc.Array.forEach
Runs an Array.forEach after calling Luc.Array.toArray on the item. It is very useful for setting up flexible API's that can handle none one or many.
LucArray; vs ifArray thisitems else ifthisitems !== undefined this;
Luc.Array.pluck
Flatten out an array of objects based of their value for the passed in key. This also takes account for null/undefined values.
LucArray>undefined 2 3 4
Luc.Array.insert
Insert or append the second array/arguments into the first array/arguments. This method does not alter the passed in array/arguments.
LucArray;>0 1 2 3 4LucArray;>0 4 1 2 3LucArray;>1 2 3 0 4
Luc.Array.last
Return the last item of the array
var myLongArrayNameForThingsThatIWantToKeepTrackOf = 123 LucArray;vsmyLongArrayNameForThingsThatIWantToKeepTrackOfmyLongArrayNameForThingsThatIWantToKeepTrackOflength -1
Luc.Array.removeAtIndex
Remove an item from the passed in arr from the index.
var arr = 123;LucArray;>2arr;>13
Luc.Array.fromIndex
Return the items in between the passed in index and the end of the array.
LucArray>2 3 4 5
Iterator and Matching functions
- Luc.Array.findAll
- Luc.Array.findAllNot
- Luc.Array.findFirst
- Luc.Array.findFirstNot
- Luc.Array.findLast
- Luc.Array.findLastNot
- Luc.Array.removeAll
- Luc.Array.removeAllNot
- Luc.Array.removeFirst
- Luc.Array.removeFirstNot
- Luc.Array.removeLast
- Luc.Array.removeLastNot
All remove* / find* methods follow the same api. *All functions will return an array of removed or found items. The items will be added to the array in the order they are found. *First functions will return the first item and stop iterating after that, if none is found false is returned. remove* functions will directly change the passed in array. *Not functions only do the following actions if the comparison is not true. All remove* / find* take the following api: array, objectToCompareOrIterator, compareConfigOrThisArg
for example:
//most common use caseLucArray;>Object {} //pass in optional config for a strict === comparisonLucArray;>false //pass in an iterator and thisArgLucArray;>1 //you can see remove modifies the passed in array.var arr = 12a:11 a:1;LucArray>a:1arr;>1 2 1 a:1LucArray>1arr;>12 a:1 LucArray> 123 a:1b:2//show how not works with an iteratorLucArray>
The Array functions are also combined with the Luc.is* functions. There are over 150 matching functions. Almost every public method of Luc.is* is available it uses the following grammar Luc.Array["methodName""isMethodName"] These functions have a consistent api that should make sense what they do from the function name. Docs
//compact like functionLucArray > true 0 1 //Or remove all empty items var arr = '' 0 a:1 true {} 1 LucArray >'' {} arr >0 a:1 true 1 LucArray >1 var arr = 123'5'; LucArray; >123 arr >"5"
As of right now there are two function sets which differ from the is api.
InstanceOf
LucArray>date {} >LucArray1 2
In
LucArray>1 2LucArray>1 //defaults to loose comparisonLucArray> 1 a:1b:2 LucArray>1
Luc.Function
Most of these functions follow the same api: function or function[], relevant args ... with an optional config to Luc.Function.createAutmenter as the last argument.
Luc.Function.createAugmenter
Augment the passed in function's thisArg and or arguments object based on the passed in config. Read the docs to understand all of the config options.
{ console console} //Luc.Array.insert([4], [1,2,3], 0)LucFunction4 >Object configedThisArg: true>1 2 3 4 //Luc.Array.insert([1,2,3], [4], 0)LucFunction4 >Object configedThisArg: true>4 1 2 3 LucArrayvar f = LucFunction; f >Object config: false>4 1 2 3
Luc.Function.createThrottled
Create a throttled function from the passed in function that will only get called once the number of milliseconds have been exceeded. Read the docs to understand all of the config options.
var { console}; var a = LucFunction; forvar i = 0; i < 100; ++i ; >1 2 3>1>2
Luc.Function.createRelayer
Return a functions that runs the passed in functions the result of each function will be the the call args for the next function. The value of the last function return will be returned. Read the docs to understand all of the config options.
LucFunction'a' >"abcd"
Luc.Function.createSequence
Return a function that runs the passed in functions and returns the result of the last function called. Read the docs to understand all of the config options.
LucFunction>1>2>3>finished logging>4
Luc.Function.createSequenceIf
Return a function that runs the passed in functions if one of the functions returns false the rest of the functions won't run and false will be returned. Read the docs to understand all of the config options.
LucFunction >1>2>3>finished logging>false
Luc.Function.createDeferred
Defer a function's execution for the passed in milliseconds. Read the docs to understand all of the config options.
Luc.Function.emptyFn / Luc.emptyFn
A reusable empty function
Luc.Function.abstractFn / Luc.abstractFn
A function that throws an error when called. Useful when defining abstract like classes
Luc.compare
Return true if the values are equal to each other. By default a deep comparison is done on arrays, dates and objects and a strict comparison is done on other types. Pass in 'shallow' for a shallow comparison, 'deep' (default) for a deep comparison 'strict' for a strict === comparison for all objects or 'loose' for a loose comparison on objects. A loose comparison will compare the keys and values of val1 to val2 and does not check if keys from val2 are equal to the keys in val1.
Luc>falseLuc>trueLuc>falseLuc>trueLuc>falseLuc>falseLuc>trueLuc>trueLuc>trueLuc>falseLuc>trueLuc>false
Luc.id
Return a unique id. A prefix is an optional argument
Lucid >"luc-0" Lucid >"luc-1" Lucid'my-prefix' >"my-prefix0" Lucid'' >"0"
Where does Luc sit now?
Luc is now in its first official release. It still sits at version 0.* and follows the http://semver.org/ versioning spec. We want to get input on what the community thinks about the API and functionality Luc provides. Luc will officially release an unchanging API after taking account for everyone's input. Once input has been gathered a 1.* version will be released.
The future
Right now Luc provides the the building blocks for small and large scale applications. It does not have any dom or html building functionality. We want to add this functionality as a submodule down the road. For the most part Luc's core API should be pretty set now. Any functionality that we want to add down the road will be done through submodules.
Issues/Discussion
Log issues with the appropriate tag. For discussions about the API or documentation use the discussion tag. Please read the known caveats of es5-shim.
FAQ
- How does Luc support Node and IE6?
- Luc uses es5-shim and browserify to write pure node code with all of its es5 goodness and it just works on all browsers.
- Can I run the tests and see code coverage?
- Why do some tests show failing in testling
- Not sure we are talking to them for support. There are currently only two failure but they are timing out or all the tests pass but they show as failed.
- How do you pronounce Luc?
- It is pronounced like the name Luke
- What is Luc named after?
- Everyone's favorite former Milwaukee Bucks Forward and Cameroonian Prince Luc Richard Mbah a Moute