# selectn

[![Build Status](https://travis-ci.org/wilmoore/selectn.png?branch=master)](https://travis-ci.org/wilmoore/selectn)
[![Build Status](https://david-dm.org/wilmoore/selectn.png)](https://david-dm.org/wilmoore/selectn)
[![NPM version](https://badge.fury.io/js/selectn.png)](http://badge.fury.io/js/selectn)
[![frozen](http://hughsk.github.io/stability-badges/dist/frozen.svg)](http://nodejs.org/api/documentation.html#documentation_stability_index)

  Resolves deeply-nested object properties via dot or bracket-notation for [Node.js][] and the browser.

#### So you can do:

    selectn('info.name.full', person)

#### instead of:

    person && person.info && person.info.name && person.info.name.full

## Features

  - Avoids `if (obj && obj.a && obj.a.b && obj.a.b.c) { return obj.a.b.c; }`.
  - Supports multiple levels of array nesting (i.e. `group[0].section.a.seat[3]`).
  - Supports dashed key access (i.e. `stats.temperature-today`).
  - Partial application supported.
  - Functions generated by `selectn` can be passed to applicative functors like [Array.prototype.map][map] and [Array.prototype.filter][filter].
  - Works where [typeof][] fails (i.e. deeply nested properties).
  - ES5 and non-ES5 compatible.
  - CommonJS, AMD, and legacy-global compatible.
  - Provides access to global object if no object reference is given.

## Non-Features

  - No `eval` and [friends][Function].

## Installation

[component](http://component.io/wilmoore/selectn)

    $ component install wilmoore/selectn

[bower](http://sindresorhus.com/bower-components/)

    $ bower install selectn

[npm](https://npmjs.org/package/selectn)

[![NPM](https://nodei.co/npm/selectn.png?downloads=true)](https://nodei.co/npm/selectn/)

[jam](http://jamjs.org/packages/#/details/selectn)

    $ jam install selectn

[volo](http://volojs.org)

    $ volo add wilmoore/selectn

[global][]

    <script src="https://raw.github.com/wilmoore/selectn/master/selectn.min.js"></script>

## Examples

- [Nested property access](#nested-property-access)
- [Dashed keys](#dashed-keys)
- [Iterator](#iterator)
- [Predicate](#predicate)
- [Callback](#callback)

### Nested property access

Given the following object:

    var talk = {
      info: { name: 'Go Ahead, Make a Mess' }
    };

Apply the `selectn` function to the `path` and `object` parameters for error-free access to deeply nested properties.

    selectn('info.name', talk);
    // => 'Go Ahead, Make a Mess'

### Dashed keys

Given the following object:

    var talk = {
      info: { 'attendee-count': 200 }
    };

Apply the `selectn` function to the `path` and `object` parameters for error-free access to deeply nested properties.

    selectn('info.attendee-count', talk);
    // => 200

### Iterator

Given the following list:

    var talks  = [
      { info: { name: 'Go Ahead, Make a Mess' }},
      { info: { name: 'Silex Anatomy' }},
      { info: { name: 'Unit Testing in Python' }},
      { info: { name: 'Setting the Stage' }}
    ];

The generated function can be used as a predicate for [map][]:

    var query = selectn('info.name');
    //=> [Function]

    talks.map(query);
    // => [ 'Go Ahead, Make a Mess', 'Silex Anatomy', 'Unit Testing in Python', 'Setting the Stage' ]

### Predicate

Given the following object of language strings:

    var language = [
      { strings: { en: { name: 'english' } }},
      { strings: { es: { name: 'spanish' } }},
      { strings: { km: { name: 'khmer'   } }},
      { strings: { es: { name: 'spanish' } }},
    ];

The generated function can be used as a predicate for [filter][]:

    var spanish = selectn('strings.es');
    //=> [Function]

    language.filter(spanish).length;
    //=> 2

### Callback

You expect the following JSON data from an XMLHttpRequest:

    var data = { Client: { Message: { id: d50afb80-a6be-11e2-9e96-0800200c9a66 } } };

Access the `Client.Message.id` property and log the result to the console (using [promises][]):

    $.ajax({...})
      .then(selectn('Client.Message.id'))
      .then(console.log.bind(console));

    //=> d50afb80-a6be-11e2-9e96-0800200c9a66

**NOTE**: Even if you don't use this methodology in production code, it can be a handy timesaver in terms of quick debugging.

## Rationale

In larger, data-driven applications, there tends to be a need to do a lot of deep object access which can quickly lead to code like this:

    var name;

    if (contact && contact.info && contact.info.name) {
      name = contact.info.name.full || 'unknown';
    }

The following is much more concise:

    var name = selectn('info.name.full')(contact) || 'unknown';

## Neckbeard Info

In case you care about this sort of thing, we are able to do normal function application as well as partially apply when that is convenient due to `currying`.

- `selectn('info.name.full', contact)` (normal function application)
- `selectn('info.name.full')(contact)` (partial application without a `partial` helper like `Function.prototype.bind`)

Since `selectn` is a 2-ary function, we don't need to use an external library for currying as the algorithm is simple.

## Alternatives

- You can use [typeof][]; however, [typeof][] only "appears" to work due to the way the global scope is _implied_.
- Other solutions involve [eval][] and/or [Function][] ([`eval`][note] in disguise).

## Inspiration

- [to-function][]
- [reach][]
- [dref][]

## License

  MIT



[to-function]: https://github.com/component/to-function
[reach]:       https://github.com/spumko/hoek#reachobj-chain
[dref]:        https://github.com/crcn/dref.js
[Function]:    https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function
[eval]:        https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/eval
[note]:        https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Member_Operators#Note_on_eval
[typeof]:      https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/typeof
[promises]:    http://promises-aplus.github.io/promises-spec/
[map]:         https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
[filter]:      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
[global]:      http://yuiblog.com/blog/2006/06/01/global-domination/
[Node.js]:     http://nodejs.org

