| ephemeris.coffee | |
|---|---|
| Gaia    = require("upon").Home
which   = require("which")
_       = require("massagist")._
Massage = require("massagist").Massage
points  = require("./points")
phase   = require("./phase")
class Ephemeris | |
| The defaults-overriding options will become part of
the help command, the man-pages / docs and the gh-pages.
For example the  
 |   defaults:
    "root": "#{__dirname}/../"
    "out": "json"
    "time": null
    "geo": {"lat": null, "lon": null}
    "stuff": [ [0, 1, 2, 3]
             , [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15, 17, 18, 19, 20]
             , [5145, 7066, 20000, 28978, 38628, 50000, 90377, 90482, 136108, 136199, 136472]
             ]
    "houses": "W" | 
| Configure ephemeris specifics, this is valid precious input. |   configure: (specifics, cb) ->
    @specifics = specifics if specifics?
    @settings = _.allFurther @defaults, @specifics
    unless @settings.data?.match /^\// | 
| If not absolute, then relative (to eden) ephemeris data path. |       @settings.data = "#{@settings.root}#{@settings.data}" | 
| The @settings.ut and @settings.geo - being reset. |     @gaia = new Gaia @settings["geo"], @settings["time"]
    @settings.geo = {}
    @settings.geo.lat = @gaia.lat
    @settings.geo.lon = @gaia.lon
    @settings.ut = @gaia.ut | 
| The @ephemeris is a function that implements precious json - input & output conforming to the spec. It is optional, as we may just want to use this class for generating ephemeris input - the output results being deferred for later perhaps. It's only set once, as it isn't expected to change. |     unless @ephemeris?
      if _.isString @settings.precious
        @ephemeris = require(@settings.precious).ephemeris | 
| This can be called in various contexts.  Example: the callback can be used
when the ephemeris paths are not immediately known (a global precious).
It's passed via the  |     cb() if cb?
    @ | 
| Because precious is not a dependency, nor is gravity, get the paths from a global precious install. |   preciousPaths: (cb) ->
    which "precious", (er, thing) =>
      if er? | 
| TODO: handle precious not installed |         console.error(er.message)
        @defaults.precious = null
      else
        apath = thing.substring 0, thing.lastIndexOf '/'
        apath += '/../lib/node_modules/precious/'
        @defaults.data = apath + 'node_modules/gravity/data/'
        @defaults.prep = apath + 'bin/'
        @defaults.precious = apath + 'index.js'
        cb() | 
| Pass a callback if you need to call @run immediately, or something... |   constructor: (specifics = {}, cb) ->
    switch specifics.precious | 
| We don't want to call precious and don't care where may be installed. Nothing special to do here. This is how we use eden to get json input configuration for perhaps later calling precious with. |       when false then ; | 
| Precious manually installed locally in  |       when true
        apath = './node_modules/'
        @defaults.data = 'precious/node_modules/gravity/data/'
        @defaults.prep = '.bin/'
        @defaults.precious = 'precious/index.js'
        specifics.precious = undefined # so that the default takes | 
| Undefined may become null. Unknown what the paths are. Expecting a global precious install. There may be none, which is null. Null is bad - because undefined implies intent to use precious. |       when undefined
        return @preciousPaths => @configure specifics, cb | 
| Unless all the paths have been given as specifics, throw an error. Of-course, it's assumed that the paths are valid. More about completeness than intended use. |       else
        unless _.isString specifics.precious
          throw "Invalid precious specifics!"
    return @configure specifics, cb | 
| A way to change just the output format, with possible method-chaining. |   out: (treats) ->
    @settings.out = treats
    @ | 
| Just for processing points output as json (at this point). It also sets up the points json for phase. |   pre: (stream) ->
    process = true
    the_points = "points"
    becoming = "json" | 
| This is so that the_points can be passed as JSON to  |     if _.isArray(@settings.out) and @settings.out[0] is the_points
      [process, @settings.out[0]] = [the_points, becoming] | 
| Only the data changes for the following,  |     else if _.include [the_points, "phase"], @settings.out
      process = the_points | 
| Specific processing (e.g. points), or else return the same stream without changing anything at all. |     if process is the_points
      points stream
    else
      stream | 
| This is the reason  |   run: (stream) -> | 
| However, Ephemeris can't always be  |     if @settings.precious is false | 
| Note: this isn't fit for rerun as  |       if _.isString(@settings.out) and @settings.out isnt "json"
        @settings.out = ["json", @settings.out] | 
| Clean-up the  |       delete @settings[key] for key in ['root', 'data', 'precious']
      if _.isArray @settings.out
        massage = new Massage @settings.out
        massage.write   JSON.stringify(@settings), stream
      else stream.write JSON.stringify(@settings)
      return
    else unless _.isFunction @ephemeris
      throw "No ephemeris to run!"
    else
      ephemeris = @ephemeris @settings | 
| An array of massage steps.  Expected to be something valid that
Massage can handle.  The  |     if _.isArray @settings.out
      streamin = @pre ephemeris
      massage = new Massage @settings.out
      massage.pipe streamin, stream | 
| The rest of these are special cases or else straight output of whatever precious returns. |  | 
| These are the non-array single massage steps for which json is assumed being implied for a starting point. Basically a list of valid, single massage steps for a more readable json output. |     else if _.include ["inspect", "indent"], @settings.out
      massage = new Massage ["json", @settings.out]
      massage.pipe ephemeris, stream | 
| The most readable output of  |     else if @settings.out is "phase"
      phase (@pre ephemeris), stream | 
| Unprocessed - straight from precious, whatever didn't get caught above.
For example  |     else @pre(ephemeris).pipe stream | 
| Special (error) cases. |     ephemeris.on "error", (data) -> console.log data.toString() | 
| Know when all the data has been got.
Useful for post-formatting with trailing  |     ephemeris.on "end", -> stream.emit "end"
module.exports = Ephemeris
 |