Source: lib/index.js

// Copyright (c) 2014 Quildreen Motta
//
// 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.

/**
 * Provides JS operators as curried functions.
 *
 * @module lib/index
 */

// -- Dependencies -----------------------------------------------------
var curry = require('core.lambda').curry
var flip  = require('core.lambda').flip


// -- Aliases ----------------------------------------------------------
var internalToString = Function.call.bind(Object.prototype.toString)

// -- Helpers ----------------------------------------------------------

/*
 * Tests if something is an object
 *
 * @summary α → Boolean
 */
function isObject(a) {
  return Object(a) === a
}


// -- Arithmetic -------------------------------------------------------

/**
 * Addition.
 *
 * @example
 *   add(2)(3)          // => 2 + 3 => 5
 *
 * @method
 * @summary Number → Number → Number
 */
exports.add = curry(2, add)
function add(a, b) {
  return a + b
}

/**
 * Subtraction.
 *
 * @example
 *   subtract(2)(3)     // => 2 - 3 => -1
 *
 * @method
 * @summary Number → Number → Number
 */
exports.subtract = curry(2, subtract)
function subtract(a, b) {
  return a - b
}

/**
 * Division.
 *
 * @example
 *   divide(4)(2)       // => 4 / 2 => 2
 *
 * @method
 * @summary Number → Number → Number
 */
exports.divide = curry(2, divide)
function divide(a, b) {
  return a / b
}

/**
 * Multiplication.
 *
 * @example
 *   multiply(2)(3)     // => 2 * 3 => 6
 *
 * @method
 * @summary Number → Number → Number
 */
exports.multiply = curry(2, multiply)
function multiply(a, b) {
  return a * b
}

/**
 * Modulus.
 *
 * @example
 *   modulus(3)(2)      // => 3 % 2 => 1
 *
 * @method
 * @summary Number → Number → Number
 */
exports.modulus = curry(2, modulus)
function modulus(a, b) {
  return a % b
}

/**
 * Negation.
 *
 * @example
 *   negate(1)          // => -1
 *
 * @method
 * @summary Number → Number
 */
exports.negate = negate
function negate(a) {
  return -a
}

/**
 * Increment.
 *
 * @example
 *   increment(1)       // => 2
 *
 * @method
 * @summary Number → Number
 */
exports.increment = exports.add(1)

/**
 * Decrement.
 *
 * @example
 *   decrement(2)       // => 1
 *
 * @method
 * @summary Number → Number
 */
exports.decrement = flip(exports.subtract)(1)




// -- Logical ----------------------------------------------------------

/**
 * Logical negation.
 *
 * @example
 *   not(false)         // => !false => true
 *
 * @method
 * @summary Boolean → Boolean
 */
exports.not = not
function not(a) {
  return !a
}

/**
 * Logical conjunction.
 *
 * @example
 *   and(true, false)           // => true && false => false
 *   and(true, true)            // => true && true => true
 *
 * @method
 * @summary Boolean → Boolean → Boolean
 */
exports.and = curry(2, and)
function and(a, b) {
  return a && b
}

/**
 * Logical disjunction.
 *
 * @example
 *   or(true, false)            // => true || false => true
 *   or(false, false)           // => false || false => false
 *
 * @method
 * @summary Boolean → Boolean → Boolean
 */
exports.or = curry(2, or)
function or(a, b) {
  return a || b
}


// -- Bitwise ----------------------------------------------------------

/**
 * Bitwise negation.
 *
 * @example
 *   bitNot(0b110)      // => ~0b110 => -0b111
 *
 * @method
 * @summary Int → Int
 */
exports.bitNot = bitNot
function bitNot(a) {
  return ~a
}

/**
 * Bitwise conjunction.
 *
 * @example
 *   bitAnd(0b110, 0b101)       // => 0b110 & 0b101 => 0b100
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitAnd = curry(2, bitAnd)
function bitAnd(a, b) {
  return a & b
}

/**
 * Bitwise disjunction.
 *
 * @example
 *   bitOr(0b110, 0b101)        // => 0b110 | 0b101 => 0b111
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitOr = curry(2, bitOr)
function bitOr(a, b) {
  return a | b
}

/**
 * Bitwise exclusive disjunction.
 *
 * @example
 *   bitXor(0b1000, 0b0110)     // => 0b1000 ^ 0b0110 => 0b1110
 *   bitXor(0b110, 0b101)       // => 0b110 ^ 0b101 => 0b011
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitXor = curry(2, bitXor)
function bitXor(a, b) {
  return a ^ b
}

/**
 * Bitwise left shift.
 *
 * @example
 *   bitShiftLeft(0b10, 2)    // => 0b10 << 2   => 0b1000
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitShiftLeft = curry(2, bitShiftLeft)
function bitShiftLeft(a, b) {
  return a << b
}

/**
 * Sign-propagating bitwise right shift.
 *
 * @example
 *   bitShiftRight(0b1000, 2)   // => 0b1000 >> 2    => 0b10
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitShiftRight = curry(2, bitShiftRight)
function bitShiftRight(a, b) {
  return a >> b
}

/**
 * Zero-fill bitwise right shift.
 *
 * @example
 *   bitUnsignedShiftRight(-0b1001, 2)  // => -0b1001 >>> 2     => 0b111111111111111111111111111101
 *
 * @method
 * @summary Int → Int → Int
 */
exports.bitUnsignedShiftRight = curry(2, bitUnsignedShiftRight)
function bitUnsignedShiftRight(a, b) {
  return a >>> b
}


// -- Relational -------------------------------------------------------

/**
 * Strict equality.
 *
 * @example
 *   equal(1, '1')     // => 1 === '1' => false
 *   equal(1, 1)       // => 1 === 1   => true
 *
 * @method
 * @summary α → α → Boolean
 */
exports.equal = curry(2, equal)
function equal(a, b) {
  return a === b
}

/**
 * Strict inequality.
 *
 * @example
 *   notEqual(1, '1')  // => 1 !== '1' => true
 *   notEqual(1, 1)    // => 1 !== 1   => false
 *
 * @method
 * @summary α → α → Boolean
 */
exports.notEqual = curry(2, notEqual)
function notEqual(a, b) {
  return a !== b
}

/**
 * Greater than.
 *
 * @example
 *   greaterThan(2, 3)  // => 2 > 3 => false
 *
 * @method
 * @summary Number → Number → Boolean
 */
exports.greaterThan = curry(2, greaterThan)
function greaterThan(a, b) {
  return a > b
}

/**
 * Greater or equal to.
 *
 * @example
 *   greaterOrEqualTo(2, 2)     // => 2 >= 2 => true
 *
 * @method
 * @summary Number → Number → Boolean
 */
exports.greaterOrEqualTo = curry(2, greaterOrEqualTo)
function greaterOrEqualTo(a, b) {
  return a >= b
}

/**
 * Less than.
 *
 * @example
 *   lessThan(2, 3)             // => 2 < 3 => true
 *
 * @method
 * @summary Number → Number → Boolean
 */
exports.lessThan = curry(2, lessThan)
function lessThan(a, b) {
  return a < b
}

/**
 * Less or equal to.
 *
 * @example
 *   lessOrEqualTo(2, 3)        // => 2 <= 3 => true
 *
 * @method
 * @summary Number → Number → Boolean
 */
exports.lessOrEqualTo = curry(2, lessOrEqualTo)
function lessOrEqualTo(a, b) {
  return a <= b
}


// -- Special ----------------------------------------------------------

/**
 * Property accessor.
 *
 * @example
 *   get('foo', { foo: 1 })     // => ({ foo: 1 })['foo'] => 1
 *
 * @method
 * @summary String → Object → α | Void
 */
exports.get = curry(2, get)
function get(key, object) {
  return object[key]
}

/**
 * Tests the existence of a property in an object.
 *
 * @example
 *   has('foo', { foo: 1 })  // => 'foo' in { foo: 1 } => true
 *
 * @method
 * @summary String → Object → Boolean
 */
exports.has = curry(2, has)
function has(key, object) {
  return key in object
}

/**
 * Instance check.
 *
 * @example
 *   isInstance(Array, [1])     // => [1] instanceof Array => true
 *
 * @method
 * @summary Function → Object → Boolean
 */
exports.isInstance = curry(2, isInstance)
function isInstance(constructor, a) {
  return a instanceof constructor
}

/**
 * Constructs new objects.
 *
 * @example
 *   create(Array, 'foo')       // => new Array('foo')  => ['foo']
 *
 * @method
 * @summary (new(α₁, α₂, ..., αₙ) → β) → (α₁, α₂, ..., αₙ) → β
 */
exports.create = create
function create(constructor) {
  return function() {
           var a = Object.create(constructor.prototype)
           var b = constructor.apply(a, arguments)
           return isObject(b)?     b
           :      /* otherwise */  a }
}

/**
 * Returns the internal type of the object.
 *
 * @example
 *   typeOf('foo')        // => typeof 'foo' => 'string'
 *
 * @method
 * @summary α → String
 */
exports.typeOf = typeOf
function typeOf(a) {
  return typeof a
}

/**
 * Returns the internal `[[Class]]` of the object.
 *
 * @example
 *   classOf('foo')     // => {}.toString.call('foo') => 'String'
 *
 * @method
 * @summary α → String
 */
exports.classOf = classOf
function classOf(a) {
  return a === undefined?  'Undefined'
  :      a === null?       'Null'
  :      /* otherwise */   internalToString(a).slice(8, -1)
}