Code Monkey home page Code Monkey logo

fairmont's People

Contributors

automatthew avatar dyoder avatar f1337 avatar gilesbowkett avatar lancelakey avatar maheshyellai avatar pseudomammal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fairmont's Issues

Recursive extend/include/merge?

The merge function is not recursive—nested objects will be included in the resulting object. Similarly, include is not recursive. In some cases, this may not be what you want. We could offer a recursive variant of these functions, like Underscore does.

Add a reactive systems example?

Since Mutual/ng provides a simple event emitter interface for Redis-based messaging, we can set up a flow to implement a synchronized counter quite trivially.

Client

In the following code ,messages is a Mutual event-emitter.

go [
  events "update", messages
  map (counter) -> data.counter = counter
]
Server
go [
  observe data.counter
  map ({counter}) -> messages.emit "update", counter
]

Cannot `require` fairmont from REPL

I'm getting an error whenever I try to require fairmont (1.0.0-alpha-04) from the CoffeeScript REPL, or any code that requires fairmont. See example:

$ coffee --nodejs --harmony

coffee> require "fairmont"
/Users/chris/Code/temp/node_modules/fairmont/lib/helpers.js:7
  if (script.match(/test.litcoffee$/)) {
            ^
TypeError: Cannot read property 'match' of undefined
  at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/helpers.js:7:13)
  at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/helpers.js:27:4)
  at Module._compile (module.js:460:26)
  at Object.Module._extensions..js (module.js:478:10)
  at Module.load (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
  at Function.Module._load (module.js:310:12)
  at Module.require (module.js:365:17)
  at require (module.js:384:17)
  at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/index.js:5:10)
  at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/index.js:105:4)
  at Module._compile (module.js:460:26)
  at Object.Module._extensions..js (module.js:478:10)
  at Module.load (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
  at Function.Module._load (module.js:310:12)
  at Module.require (module.js:365:17)
  at require (module.js:384:17)
  at repl:1:5
  at Object.exports.runInThisContext (vm.js:74:17)
  at REPLServer.replDefaults.eval (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/repl.js:46:42)
  at bound (domain.js:254:14)
  at REPLServer.runBound [as eval] (domain.js:267:12)
  at repl.js:279:12
  at REPLServer.<anonymous> (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/repl.js:79:9)
  at REPLServer.emit (events.js:129:20)
  at REPLServer.Interface._onLine (readline.js:214:10)
  at REPLServer.Interface._line (readline.js:553:8)
  at REPLServer.Interface._ttyWrite (readline.js:830:14)
  at ReadStream.onkeypress (readline.js:109:10)
  at ReadStream.emit (events.js:129:20)
  at readline.js:1175:14
  at Array.forEach (native)
  at emitKeys (readline.js:993:10)
  at ReadStream.onData (readline.js:910:14)
  at ReadStream.emit (events.js:107:17)
  at readableAddChunk (_stream_readable.js:163:16)
  at ReadStream.Readable.push (_stream_readable.js:126:10)
  at TTY.onread (net.js:529:20)

Same thing happens from the node REPL:

$ node --harmony
> require("fairmont")
TypeError: Cannot read property 'match' of undefined
    at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/helpers.js:7:13)
    at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/helpers.js:27:4)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/index.js:5:10)
    at Object.<anonymous> (/Users/chris/Code/temp/node_modules/fairmont/lib/index.js:105:4)

Here's my version of lib/helpers.js:

// Generated by CoffeeScript 1.8.0
(function() {
  var Amen, assert, script;

  script = process.argv[1];

  if (script.match(/test.litcoffee$/)) {
    assert = require("assert");
    Amen = require("amen");
    module.exports = {
      assert: assert,
      describe: function() {
        return Amen.describe.apply(Amen, arguments);
      }
    };
  } else {
    module.exports = {
      assert: function() {},
      describe: function(string, fn) {
        return fn({
          test: function() {}
        });
      }
    };
  }

}).call(this);

It looks like script = process.argv[1] is not being tested for undefined, despite helpers.litcoffee showing script?.match.

Perhaps republishing will fix this?

Should some array functions be generalized?

Many of Underscore's array functions work on objects, too. This is modeled after Ruby's Enumerable, where anything that provides a basic iteration interface can be used with the collection functions. Should we do this in Fairmont?

bash

I'm not sure how much of a faux pas it is to use third party libraries here, but it would be nice to have a handy function for executing arbitrary bash commands. ShellJS's "exec" can run asynchronously and I find myself writing this function repeatedly, haha. I should be better about writing more refined error handling, though. @dyoder, could you consider adding this function to the File System Functions, please?

{exec} = require "shelljs"
{promise} = require "when"

bash = (command) ->
  promise (resolve, reject) ->
    exec command, (code, output) ->
      if code == 0
        resolve output
      else
        reject output

One thing to note is that ShellJS has admitted to inefficiencies for long lived processes. They promise to address this in the future.

where() and array_equal()

@dyoder, there is a function in underscore that I think is very handy, called where(). Provided an array of objects and a query object, where() returns an array with only those objects that contain the query object as a subset.

I liked it so much that when we switched the Huxley CLI over to Fairmont, I re-implemented it. However, I went back and thought about the style I've been trying to practice. I think the version below is much closer to something that could be included in Fairmont, so I'd like to submit it to you.

There are a couple questions of scope, however. It currently only works on an array of objects and accepts only one query object.

  • Should we generalize it to accept an array of strings, numbers, etc....
  • Should we generalize it to accept multiple queries for matching?

I toyed with the idea of making an awesome, overloaded filter function but there are so many edge cases it was like wrangling cats, haha.

Object Filter Draft, where()

# Filters an array of objects against a single "query" object.  If no objects match, an empty array is returned.
{async, collect, deep_equal, partial, select, _} = require "fairmont"
where = async (query, array) ->
  match = (a, b) ->
    intersect = (a, b) -> key for key in Object.keys(b) when (deep_equal a[key], b[key])
    if intersect(a, b).length == Object.keys(a).length then true else false

    collect yield select (partial match, query, _), array

During testing, I realized that not only does the == operator fail to compare arrays, so does deep_equal. I wrote a draft of a function that performs a comparison on arrays and recurses to ensure a deep comparison. Since this could possibly be expensive, it tries to escape and return false whenever it confirms a difference. Maybe we can work this into deep_equal eventually. (after removing the deep_equal usage, haha.)

Deep Array Comparison Draft, array_equal()

# Performs deep comparison of two arrays.  Returns true or false.
{type, deep_equal} = require "fairmont"
array_equal = (a, b) ->
  throw "\"array_equal\" accepts only arrays." unless type(a) == "array" && type(b) == "array"
  return false unless a.length == b.length

  compare = (a, b) ->
    for i in [0..a.length - 1]
      if (type(a[i]) == "array") && (type(b[i]) == "array")
        throw false unless  (a.length == b.length) && (compare a[i], b[i])
      else
        throw false unless deep_equal a[i], b[i]
    true

  try
    compare a, b
  catch e
    false
assert array_equal [[1, 2, 3], 2, 3], [[1, 2, 3], 2, 3]
assert !array_equal [[1, 2, 30], 2, 3], [[1, 2, 3], 2, 3]
assert array_equal [[[{one: {two:2, three:3}}, 2, 3], 2, 3], 2, 3], [[[{one: {two:2, three:3}}, 2, 3], 2, 3], 2, 3]

NPM Module Version Check

@dyoder, when I run npm install fairmont in a test directory, I do not get the latest version of Fairmont. I get one that appears to have been released around the beginning of 2015. Is this intentional?

David:test David$ npm install fairmont
npm WARN package.json [email protected] No description
npm WARN package.json [email protected] No repository field.
npm WARN package.json [email protected] No README data
[email protected] node_modules/fairmont
David:test David$ npm install [email protected]
npm WARN package.json [email protected] No description
npm WARN package.json [email protected] No repository field.
npm WARN package.json [email protected] No README data
[email protected] node_modules/fairmont
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected])

stringify

@dyoder, this was a function you mentioned earlier today. This provides JSON stringification with a null replacer and a tabstop of 2 whitespaces. Hopefully this is straight-forward enough even I can get it, haha. Though, I'm not sure if it should be considered a "string" function or an "object" function.

# Provide JSON object stringification with a `null` replacer and a tabstop of 2 whitespaces. 
stringify = (object) ->  JSON.stringify object, null, 2 

Compiled version tries to import from coffeescript path

> require('fairmont')
Error: Cannot find module '../src/index'
    at Function.Module._resolveFilename (module.js:336:15)
    at Function.Module._load (module.js:278:25)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at /home/lacrymology/workspace/panda/photokharma/photokharma-fre-node/node_modules/fairmont/lib/iterator.js:280:12
    at module.exports.describe (/home/lacrymology/workspace/panda/photokharma/photokharma-fre-node/node_modules/fairmont/lib/helpers.js:20:16)
    at Object.<anonymous> (/home/lacrymology/workspace/panda/photokharma/photokharma-fre-node/node_modules/fairmont/lib/iterator.js:20:3)
    at Object.<anonymous> (/home/lacrymology/workspace/panda/photokharma/photokharma-fre-node/node_modules/fairmont/lib/iterator.js:474:4)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)

A quick look at the tree shows that at ../src there're the coffeescript files, and the javascript files live in ../lib.

I don't know the correct solution for this, I'm new to coffee

Ignoring Rejected Promises

Hey @dyoder, I have another proposal. Sometimes we don't care if a promise is rejected, we just need to wait for it to be done one way or another. I propose a function that accepts an input promise, p, but always resolves "true".

I had a specific and legitimate use-case when I wrote the original version, but I was unsure about abstracting it to submit this to you for Fairmont.

  1. On one hand, it can be handy to have a function that grants a kind of idempotence to an arbitrary function, but
  2. This is a dangerous function because you end up losing state and errors could be hard to catch.

I try to be mindful of Crockford's advice to avoid dangerous styles, so please know I don't submit this lightly. I'd understand if you have misgivings and I'd really like your opinion.

source

force = (p, args...) ->
  {partial} = require "./core"
  {promise} = require "when"

  # Compose the promise that was passed in.
  p = partial p, args...

  # Evaluate the promise to achieve its side effects, but always resolve true.
  promise (resolve, reject) ->
    p.catch resolve true
    call -> yield p()
    resolve true

example

# The affected function is passed into "force", with its arguments following it instead of being passed directly. 
call ->
  # This one fails out if the alias is not present.
  yield shell "git remote rm  #{argv[0]}"

  # This one will quietly continue to the next line.
  yield force shell, "git remote rm  #{argv[0]}"

Wrap of NodeJS Functions

I'm still not clear on the boundaries of Fairmont, so forgive me if this is outside the intended scope. Would it be okay to provide a list of NodeJS functions that are wrapped in ES6 promises? Where is the boundary between usefulness and the bludgeon problem?

For example, in panda-cluster we make use of these two functions:

# Promise wrapper around Node's https module. Turns GET calls into promises.
https_get = (url) ->
  {https} = require "https"
  {promise} = require "when"

  promise (resolve, reject) ->
    https.get url
    .on "response", (response) ->
      resolve response
    .on "error", (error) ->
      reject error

# Promise wrapper around response events that read "data" from the response's body.
get_body = (response, encoding) ->
  {promise} = require "when"
  promise (resolve, reject) ->
    data = ""
    format = encoding || "utf8"

    response.setEncoding format
    .on "data", (chunk) ->
      data = data + chunk
    .on "end", ->
      resolve data
    .on "error", (error) ->
      reject error

is_null

I'm not sure I really want this one, but I'm also not sure how to define it. What I really want is simply the negation of is_value. I'd prefer to be able to do away with worrying about null versus `undefined.

Maybe is_void?

integrate ES6 Set

We could probably speed up the implementation of set-related operations quite a bit.

curry doesn't work with async

curry relies on Function.length to to determine the number of arguments it needs to handle. async returns a proxying function with length 0.

Proposal to fix this: record the arglength of the function passed to async as a property on the function it returns.

In fairmont-helpers:

async = (g) ->

  if !(isGeneratorFunction g)
    throw new TypeError "#{g} is not a generator function"

  fn = (args...) ->
    self = this
    promise (resolve, reject) ->
      i = g.apply self, args
      f = -> i.next()
      do step = (f) ->
        try
          {done, value} = f()
        catch error
          reject error

        if done
          resolve value
        else
          follow value
          .then (value) -> step -> i.next value
          .catch (error) -> step -> i.throw error
  fn.asyncArgs = g.length
  fn

In fairmont-core:

curry = (f) ->
  g = (ax...) ->
    arglength = f.length || f.asyncArgs
    if ax.length >= arglength
      f ax...
    else
      switch arglength - ax.length
        when 1
          (x) -> f ax..., x
        when 2
          binary curry (x,y) -> f ax..., x, y
        when 3
          ternary curry (x,y,z) -> f ax..., x, y, z
        else (bx...) -> g ax..., bx...

`clone` fails with "ReferenceError: $ is not defined"

Example:

{clone} = require "fairmont"
clone foo: "bar"

Result

fairmont/lib/object.js:67
        clone[key] = $.clone(object[key]);
                     ^
ReferenceError: $ is not defined
  at clone (fairmont/lib/object.js:67:22)
  at repl:1:5

It appears that the clone method is referencing $.clone, which does not exist.

Also there are no tests for clone.

Logical functions

I'm not sure there's much value in have a function that just negates a value, whereas having a function that negates another function is pretty interesting.

The same is true for and, or, equal, and not_equal. The thing is, I've defined these currently with f_ prefixes (except for negate, which was f_not). Is that really necessary, given that we don't have functions for logically dealing with values.

The reason I don't think the value-oriented functions are useful is that it's already easy to write boolean expressions, but you can't easily do the same thing with functions.

At any rate, this is mostly a reminder to revisit this issue and perhaps rename those functions. Of course, the other problem is that and, or, and so on are reserved words in CoffeeScript.

Regexp functions

We don't have an easy way to integrate regexp operations into functional expressions. For example, simply checking whether something matches an regexp:

find_plurals = map match /s$/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.