npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lell

v1.2.5

Published

Living entities and lists, easy observables, (almost) no boilerplate

Downloads

51

Readme

lell - Build Status Latest Stable Version NPM Downloads Build Status Code Climate License

Make all your data observable without changing the way you do anything

Very small learning curve, enormous power.

Quick Use

Pop a model, subclassing Le is better but unnecessary

// model.js
import {Le, Ll} from 'lell'


var livingPerson = new Le({name:'z', power_level:9000})
// or
var livingPerson = new Person({name:'z',power_level:9000}) // if person extends Le


module.exports = {
  person:livingPerson
}

Read and subscribe!

// components/person.js
var model = require('./model.js')

class Person extends React.Component {
  constructor(props) {
    super(props)
    this.state = {person:model.person}
  }
  componentDidMount() {
    model.person.subscribe((person) => this.setState({person:person}))
  }
  tapIncreasePowerLevel() {
    model.person.power_level++
    // auto updates view
  }
  render() {
    var person = model.person
    return <div>
    <span>{person.name}</span> - {person.power_level}
    <button onClick={this.tapIncreasePowerLevel} />
    </div>
  }
}

Installation

Via npm:

npm install --save lell

Then require/import:

import {Le, Ll} from 'lell'
//or
var Le = require('lell').Le
var Ll = require('lell').Ll

Usage

Objects/Classes

Quick Living Entity

Just instantiate an Le with a payload

The only keys that cause events are the ones passed into the constructor

import {Le} from 'lell'

var aPerson = {name:'z',power_level:9000}

var aLivingPerson = new Le(aPerson)

aLivingPerson.subscribe((p) => console.log(p.power_level))

aLivingPerson.power_level++
// console output: 9001
An observable class

Extending an Le is only necessary if you can't init with all your properties or you just want convenience methods (like ajax requests) The living properties are only the ones we initialize with, so we have have to make sure our initial state holds all keys we wish to cause updates which is set in the _defaults method

import {Le} from 'lell'
import _ from 'lodash'

class Person extends Le {
  _defaults() {
    // having defaults makes these fields observable even if you haven't initialized with them
    return {name:'', power_level:0}
  }
  doSomeAsyncWork() {
    superagent
      .post('/increase_powerlevel')
      .send(this)
      .end((err, data) => {
        this.power_level++
    })
  }
}

var aLivingPerson = new Person()

aLivingPerson.subscribe((p) => console.log(p.name))

aLivingPerson.name = 'z'
// z

aLivingPerson.doSomeAsyncWork()
// z
Entity Mapping

Provide a map in your Le subclass so that an initial payload is initialized with Le's

class Person extends Le {
  _map() {
    return {friends:[Person], bestFriend:Person}
  }
}

var friendlyPerson = new Person({
  name:'z',
  bestFriend:{
    name:'s',
    power_level:9000
  },
  friends:[
    {
      name:'b',
      power_level:9001
    },
    {
      name:'n',
      power_level:9002
    }
  ]
})
// subscribe to bestFriend changes
friendlyPerson.bestFriend.subscribe((bf) => console.log(bf.power_level))
friendlyPerson.friends[0].subscribe((f) => console.log(f.power_level))
Some state information

Le's have state information you can use to help your web interfaces, ie, agnostic new/edit react views

var p = new Person()
console.log(p._state)
//new
p.power_level = 9000
console.log(p._state)
//new
console.log(p._updates)
// ["power_level"]
p._commit()
console.log(p._state)
// original
console.log(p._updates)
// []

var ep = new Person({name:'z', power_level:9000})
console.log(ep._state)
// original
ep.power_level++
console.log(ep._state)
// updated
ep.power_level--
console.log(ep._state)
// original
ep.power_level++
console.log(ep._state)
// updated
ep._commit()
console.log(ep._state)
// original
console.log(ep._updates)
// []
Rx.Observable available

The Rx observable subject is made available to you:

aLivingPerson.subject.pluck('power_level').subscribe((power_level) => console.log(power_level))

aLivingPerson.power_level = 9000
// 9000
Silent Updates

Update your instance without kicking off an update

aLivingPerson.subscribe((p) => console.log(p))

aLivingPerson.silentUpdate('power_level', 8999)
// no events

Lists

You can easily create living lists (Ll) that send notifications when the underlying array changes

You need to make changes through the array through the Lls methods addItems, removeItems, setItems

Quick list

We can make a simple living list

import {Ll} from 'lell'
//or
var Ll = require('lell').Ll

var abe = ...
var bush = ...
var people = [abe, bush]

var livingPeople = new Ll({people}) // this means {people: people}

livingPeople.subscribe((people) => console.log(people.length))

var kennedy = ...

livingPeople.addItems(kennedy)
// 3
livingPeople.removeItems([abe, bush])
// 1
livingPeople.setItems([abe, kennedy])
// 2
Sorted List

This is where Lls start getting good, you can supply a sort key/func to your Ll and your list will be sorted (borrows lodash _.sortBy)


var people = [{name:'z', power_level:9001}, {name:'y', power_level:9000}]
var livingPeople = new Ll({people, sort:'power_level'})

livingPeople.subscribe((people) => console.log(people[0].name))

livingPeople.addItems({name:'x', power_level:8999})
// x
Meant for Le's

Okay, that wasn't that cool, but Ll's are best when holding Le's

var livingPersonZ = new Person({name:'z',power_level:8999})
var livingPersonY = new Person({name:'y',power_level:9000})

var livingPeople = new Ll({
  people:[livingPersonZ, livingPersonY],
  sort:'power_level'
  })

console.log(livingPeople.people[1].name)
// y

livingPeople.subscribe((people) => console.log(people[1].name))

livingPersonZ.power_level = 9001
// z

Cool, huh? We have a reactive list

Subscribe each

You can listen to all of the items in a list, so when any Le in an Ll changes, you can be notified with that Le


livingPeople.subscribeEach((aPerson) => console.log(aPerson.power_level))

livingPersonZ.power_level++
// 9002
Rx.Observable availability

The observables are available to you, one for the list, subject, and one for the subscribeEach, itemChangeSubject

// note, you need to pluck people, because the root subject signals with the Le {people, sort}
livingPeople.subject.pluck('people').map(doSomething).subscribe(listen)

livingPeople.subject.pluck('power_level').average().subscribe(useAverage)
Subclassing is favorable

It really makes things convenient

import {Ll} from 'lell'
import _ from 'lodash'

var defaultState = {
  people:[personA, personB],
  sort:'power_level'
}

class People extends Ll {
  constructor(state) {
    state = state ? _.defaults(state, defaultState) : Object.assign({}, defaultState)
    super(state)
  }
}

var initialState = {people:[personA, personC, personX]}
var livingPeople = new People(people)

livingPeople.subscribe()

Future

  • Auto Hydrate/Serialize entire Le/Ll store between server/client
  • Le actions

License

The MIT License (MIT)

Copyright (c) 2016 ark

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.