GithubHelp home page GithubHelp logo

raine / ramda-cli Goto Github PK

View Code? Open in Web Editor NEW
573.0 15.0 12.0 3.17 MB

:ram: A CLI tool for processing data with functional pipelines

License: ISC License

JavaScript 18.06% LiveScript 67.56% Makefile 1.56% HTML 0.28% CSS 12.54%
json ramda livescript cli

ramda-cli's Introduction

๐Ÿ‘ ramda-cli npm version Gitter

A tool for processing data with functional pipelines. In the command-line or interactively in browser.

$ npm install -g ramda-cli
$ curl -Ls https://bit.ly/gist-people-json | ramda \
  'filter (p) -> p.city?.match /Port/ or p.name.match /^Dr\./' \
  'map pick ["name", "city", "mac"]' \
  'take 3' \
  -o table --compact
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ name             โ”‚ city            โ”‚ mac               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Dr. Araceli Lang โ”‚ Yvettemouth     โ”‚ 9e:ea:28:41:2a:50 โ”‚
โ”‚ Terrell Boyle    โ”‚ Port Reaganfort โ”‚ c5:32:09:5a:f7:15 โ”‚
โ”‚ Libby Renner     โ”‚ Port Reneeside  โ”‚ 9c:63:13:31:c4:ac โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Or, pass in --interactive to launch in browser.

โœจ highlights

  • Build elegant data-processing pipelines in the command-line with Ramda's data-last API
  • No new syntax to learn: Use LiveScript or JavaScript, and the functions you know from Ramda
  • Use any npm module seamlessly
  • Interactive mode for building pipelines iteratively with instant feedback
Table of Contents
Resources

install

npm install -g ramda-cli

synopsis

cat data.json | ramda [function] ...

The idea is to compose functions into a pipeline of operations that when applied to given data, produces the desired output.

By default, the function is applied to a stream of JSON data read from stdin, and the output data is sent to standard out as JSON.

Technically, function should be a snippet of LiveScript (or JavaScript with --js) that evaluates into a function. If multiple function arguments are supplied as positional arguments, they are composed into a pipeline in order from left to right.

For example, the command

echo '[1,2,3]' | ramda 'filter (> 1)' 'map multiply 2' 'product'
24

is roughly equivalent in the following operation:

R.pipe(
  JSON.parse,
  R.filter(x => x > 1),
  R.map(R.multiply(2)),
  R.product,
  JSON.stringify
)('[1,2,3]') // "24"

(see R.pipe).

All Ramda's functions are available directly in the context. See http://ramdajs.com/docs/ for a full list and Evaluation context section for other functions.

interactive mode

New in v4.0

When launched with the --interactive parameter, ramda-cli opens in the browser. The pipeline, if given, is placed in an embedded code editor that emulates the prompt in command-line. As the pipeline is edited, changes to output are reflected below in the output panel.

In interactive mode, ramda-cli is generally operated the same way as on the command-line. The key benefit is being able to develop pipelines incrementally with much shorter feedback cycle.

Input is passed to interactive mode in stdin, as usual.

You may pipe stdout to other commands even when using interactive mode. When the interactive mode tab is closed, the result will printed to stdout.

copy-pasteable example

curl -Ls http://bit.ly/gist-people-json | npx ramda-cli \
  'filter (p) -> p.city is /Port/ or p.name is /^Dr\./' \
  'filter (p) -> p.email?.includes ".info"' \
  'project <[ name city mac email ]>' \
  'take 100' \
  --interactive \
  -o table --compact

examples

# Add 1 to each value in a list
echo [1,2,3] | ramda 'map add 1'
[
  2,
  3,
  4
]
# Add 1 to each value with inline ES6 lambda and take product of all
echo [1,2,3] | ramda --js 'map(x => x + 1)' product
24

Ramda functions used: add, map, product

Get a list of people whose first name starts with "B"
cat people.json | ramda 'pluck \name' 'filter (name) -> name.0 is \B)' -o raw
Brando Jacobson
Betsy Bayer
Beverly Gleichner
Beryl Lindgren

Ramda functions used: pluck, filter Data: people.json

Create a markdown TODO list
curl -s http://jsonplaceholder.typicode.com/todos |\
  ramda --raw-output \
    'filter where-eq user-id: 10' \
    'map (t) -> "- [#{t.completed && "x" || " "}] #{t.title}"' \
    'take 5' \
    'unlines'

Output

  • ut cupiditate sequi aliquam fuga maiores
  • inventore saepe cumque et aut illum enim
  • omnis nulla eum aliquam distinctio
  • molestias modi perferendis perspiciatis
  • voluptates dignissimos sed doloribus animi quaerat aut

Ramda functions used: filter, where-eq, map

List versions of a npm module with ISO times formatted using a module from npm
npm view ramda --json | ramda --import time-ago:ta \
  'prop "time"' \
  'to-pairs' \
  'map -> version: it.0, time: ta.ago(it.1)' \
  'reverse' \
  -o table --compact
...
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ version       โ”‚ time         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0.26.1        โ”‚ 1 month ago  โ”‚
โ”‚ 0.26.0        โ”‚ 2 months ago โ”‚
โ”‚ 0.25.0        โ”‚ 1 year ago   โ”‚
โ”‚ 0.24.1-es.rc3 โ”‚ 1 year ago   โ”‚
โ”‚ 0.24.1-es.rc2 โ”‚ 1 year ago   โ”‚
...
Search twitter for people who tweeted about ramda and pretty print the result
twarc.py --search '#ramda' | ramda --slurp -p 'map path [\user, \screen_name]' uniq

Ramda functions used: map, path

Pull response status data from Graphite and visualize

HTTP status codes per minute for last hour:

graphite -t "summarize(stats_counts.status_codes.*, '1min', 'sum', false)" -f '-1h' -o json | \
  ramda --import sparkline 'map evolve datapoints: (map head) >> sparkline \
    'sort-by prop \target' -o table

Ramda functions used: evolve, sortBy

Use --slurp to read multiple JSON objects into a single list before any operations
cat <<EOF | ramda --slurp identity
"foo bar"
"test lol"
"hello world"
EOF
[
  "foo bar",
  "test lol",
  "hello world"
]
Solution to the credit card JSON to CSV challenge using --output-type csv
#!/usr/bin/env bash

data_url=https://gist.githubusercontent.com/jorinvo/7f19ce95a9a842956358/raw/e319340c2f6691f9cc8d8cc57ed532b5093e3619/data.json
curl $data_url | ramda \
  'filter where creditcard: (!= null)' `# filter out those who don't have credit card` \
  'project [\name, \creditcard]'       `# pick name and creditcard fields from all objects` \
  -o csv > `date "+%Y%m%d"`.csv        `# print output as csv to a file named as the current date`
List a project's dependencies in a table
npm ls --json | ramda 'prop \dependencies' 'map-obj prop \version' -o table --compact
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ JSONStream    โ”‚ 1.0.4  โ”‚
โ”‚ treis         โ”‚ 2.3.9  โ”‚
โ”‚ ramda         โ”‚ 0.14.0 โ”‚
โ”‚ livescript    โ”‚ 1.4.0  โ”‚
โ”‚ cli-table     โ”‚ 0.3.1  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Ramda functions used: filter, where, project, mapObj, prop

Generate HTML with hyperscript
cat <<EOF > shopping.txt
milk
cheese
peanuts
EOF
cat shopping.txt | ramda --import hyperscript:h \
  -rR --slurp           `# read raw input into a list` \
  'map (h \li.item, _)' `# apply <li class="item"> into each item` \
  'h \ul#list, _'       `# wrap list inside <ul id="list">` \
  '.outer-HTML'         `# finally, grab the HTML`
<ul id="list">
  <li class="item">milk</li>
  <li class="item">cheese</li>
  <li class="item">peanuts</li>
</ul>

Reason for underscores (e.g. h \ul, _) is that hyperscript API is not curried (and can't be because it's variadic). We need to explicitly state that this function is waiting for one more argument.

For more examples, see the Cookbook.

using javascript

If LiveScript is not your thing, you may write pipelines in JavaScript using the --js parameter.

echo '[1,2,3]' | ramda --js 'map(x => x + 1)'
[
  2,
  3,
  4
]

options

Usage: ramda [options] [function] ...

  -I, --interactive    run interactively in browser
  -f, --file           read a function from a js/ls file instead of args; useful for
                       larger scripts
  -c, --compact        compact output for JSON and tables
  -s, --slurp          read JSON objects from stdin as one big list
  -S, --unslurp        unwraps a list before output so that each item is formatted and
                       printed separately
  -t, --transduce      use pipeline as a transducer to transform stdin
  -P, --json-path      parse stream with JSONPath expression
  -i, --input-type     read input from stdin as (#{format-enum-list INPUT_TYPES})
  -o, --output-type    format output sent to stdout (#{format-enum-list OUTPUT_TYPES})
  -p, --pretty         pretty-printed output with colors, alias to -o pretty
  -D, --pretty-depth   set how deep objects are pretty printed
  -r, --raw-input      alias for --input-type raw
  -R, --raw-output     alias for --output-type raw
  -n, --no-stdin       don't read input from stdin
      --[no-]headers   csv/tsv has a header row
      --csv-delimiter  custom csv delimiter character
      --js             use javascript instead of livescript
      --import         import a module from npm
  -C, --configure      edit config in $EDITOR
  -v, --verbose        print debugging information (use -vv for even more)
      --version        print version
  -h, --help           displays help

-I, --interactive

Launch interactive mode in browser.

See Interactive mode.

-f, --file

Load a function pipeline from a file. Useful for scripts difficult to express in command-line.

Example

// shout.js
var R = require('ramda');
module.exports = R.pipe(R.toUpper, R.add(R.__, '!'));
echo -n '"hello world"' | ramda --file shout.js
"HELLO WORLD!"

You can overwrite command-line arguments through the script by exporting a string in property opts.

module.exports = function() { /* ... */ }
module.exports.opts = '--slurp -o table'

-c, --compact

Print compact tables and JSON output without whitespace.

When used with --output-type raw, no line breaks are added to output.

Example

seq 10 | ramda --input-type raw --output-type raw --compact identity # or -rRc
12345678910%

-s, --slurp

Read all input from stdin and wrap the data in a list before operations.

Example

cat <<EOF | ramda --slurp 'map to-upper'
"foo"
"bar"
"xyz"
EOF
[
  "FOO",
  "BAR",
  "XYZ"
]

-S, --unslurp

After the pipeline is applied to an item and if the result is an array, its items are printed separately.

Example

echo '[1,2,3]' | ramda --unslurp 'map inc'
2
3
4

-t, --transduce

Transform the input stream using the pipeline as a transducer. Requires all functions in the pipeline to be able to act as transducers.

This option essentially allows performing operations like R.map or R.filter on items as they come without waiting for the stream to complete or wrapping the input stream in a collection with --slurp.

Example

echo '1 2 2 3 3 4' | ramda --transduce drop-repeats
1
2
3
4

-P, --json-path

Parse the input stream with given JSONPath expression.

See also: JSONStream documentation

Examples

Process a huge JSON array one by one without reading the whole thing first.

* as JSON path unwraps the array and objects are passed to identity one by one.

curl -Ls http://bit.do/countries-json | ramda --json-path '*' --compact identity
{"name":"Afghanistan","code":"AF"}
{"name":"ร…land Islands","code":"AX"}
{"name":"Albania","code":"AL"}
...

-i, --input-type

Parse stdin as one of these formats: raw, csv, tsv.

Examples

echo foo | ramda --input-type raw to-upper
"FOO"
$ cat <<EOF | ramda --input-type csv identity
id,name
1,Bob
2,Alice
EOF
[
  { "id": "1", "name": "Bob" },
  { "id": "2", "name": "Alice" }
]

-o, --output-type

Instead of JSON, format output as one of: pretty, raw, csv, tsv, table.

-o pretty

Print pretty output.

-o raw

With raw output type when a string value is produced, the result will be written to stdout as is without any formatting.

-o csv and -o tsv

CSV or TSV output type can be used when pipeline evaluates to an array of objects, an array of arrays or when stdin consists of a stream of bare objects. First object's keys will determine the headers.

-o table

Print nearly any type of data as a table. If used with a list of objects, uses the first object's keys as headers.

Example

curl -Ls http://bit.do/countries-json | ramda 'take 3' -o table --compact
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ name          โ”‚ code โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Afghanistan   โ”‚ AF   โ”‚
โ”‚ ร…land Islands โ”‚ AX   โ”‚
โ”‚ Albania       โ”‚ AL   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”˜

-p, --pretty

Alias of --output-type pretty.

-D, --pretty-depth

When using pretty-printed output, set how deep structures are verbosely printed.

Useful when output is huge and you want to see the general structure of an object or list.

See documentation of util.inspect(object[, options])

-n, --no-stdin

Don't read stdin for input. Useful when starting a pipeline with a constant function.

Example

ramda --no-stdin 'always "hello world"' 'add __, \!'
"hello world!"

--[no-]headers

Set if input csv/tsv contains a header row.

By default, csv/tsv input is assumed to contain headers.

--csv-delimiter

Use a custom csv delimiter. Delimiter is comma by default.

Example: --csv-delimiter=';'

--js

Interpret positional arguments as JavaScript instead of LiveScript.

Example

echo '[1,2,3]' | ramda --js 'map(x => Math.pow(x, 2))'
[
  1,
  4,
  9
]

--import <package>

Install given package from npm, and make it available in the pipeline.

Symbol : combined with a name can be used to declare the variable name module should appear as. Otherwise, it is imported as camelcased name of the module.

Can be used multiple times to import more than one module.

Example

echo test | ramda -rR --import chalk:c 'c.bold'
**test**

-C, --configure

Edit ramda-cli config file in $EDITOR.

See Configuration.

evaluation context

functions

All of Ramda's functions are available, and also:

function signature description
id a โ†’ a Alias to R.identity
flat * โ†’ Object Flatten a deep structure into a shallow object
readFile filePath โ†’ String Read a file as string
lines String โ†’ [String] Split a string into lines
words String โ†’ [String] Split a string into words
unlines [String] โ†’ String Join a list of lines into a string
unwords [String] โ†’ String Join a list of words into a string
then Function โ†’ Promise Map a value inside Promise
pickDotPaths [k] โ†’ {k: v} โ†’ {k: v} Like R.pick but deep using dot delimited paths
renameKeysBy Function โ†’ {k: v} โ†’ {k: v} Like R.map but for keys instead of values

objects

object description
process https://nodejs.org/api/process.html
console https://nodejs.org/api/console.html

process.exit() can be used to short-circuit pipeline in case of an error, for example:

curl api | ramda 'tap (res) -> if res.error then console.error(res); process.exit(1)'

An alternative is to use Maybe type.

configuration

config file

Path: $HOME/.config/ramda-cli.{js,ls}

The purpose of a global config file is to carry functions you might find useful to have around. The functions it exports in an object are made available.

For example,

// ~/.config/ramda-cli.js
exports.date = (val) => new Date(val);
exports.timeago = require('timeago');
exports.debug = (val) => {
  console.log('debug:', val);
  return val;
};
echo 1442667243000 | ramda date debug timeago
debug: Sat Sep 19 2015 12:54:03 GMT+0000 (UTC)
"12 minutes ago"

default options

To make some options be passed by default, it is best to use a shell alias. For example:

# always interpret as javascript
alias ramda="ramda --js"
echo 1 | ramda '(x) => x + 1'
2

using packages from npm

New in v5.0: ramda-cli installs specified modules transparently from npm, manual installation is no longer required.

With the --importย parameter, any module from npm can be installed and imported into the pipeline context. Invocations with a particular module will be instant once installed.

promises

Promise values are unwrapped at the end of pipeline.

then helper function can be used to map promise values.

echo 1 | ramda --js 'x => Promise.resolve(x)' 'then(add(5))'
6
echo '192.168.1.1\ngoogle.com\nyahoo.com' | \
  ramda -r --js --import ping 'ping.promise.probe' 'then(omit(["output", "numeric_host"]))' | \
  ramda --slurp -o table --compact
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ host        โ”‚ alive โ”‚ time    โ”‚ min     โ”‚ max     โ”‚ avg     โ”‚ stddev โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 192.168.1.1 โ”‚ true  โ”‚ 1.325   โ”‚ 1.325   โ”‚ 1.325   โ”‚ 1.325   โ”‚ 0.000  โ”‚
โ”‚ google.com  โ”‚ true  โ”‚ 10.729  โ”‚ 10.729  โ”‚ 10.729  โ”‚ 10.729  โ”‚ 0.000  โ”‚
โ”‚ yahoo.com   โ”‚ true  โ”‚ 115.418 โ”‚ 115.418 โ”‚ 115.418 โ”‚ 115.418 โ”‚ 0.000  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

debugging

You can turn on the debug output with -v, --verbose flag. Use -vv for even more verbose output.

Verbose output shows what entered LiveScript compiled to.

To debug individual functions in the pipeline, you can use something like treis.

echo 1 | ramda --import treis 'treis(add(1))'
f1 a: 1
f1 => 2
2

livescript?

LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate.

comparison table

All expressions in the table evaluate to a function, and are valid in ramda-cli.

Ramda LiveScript JavaScript
not (not) x => !x
nth(0) (.0) x => x[0]
prop('name') (.name) x => x.name
add(1) (+ 1) x => x + 1
add(__, '!') (+ '!') x => x + '!'
gt(__, 2) (> 2) x => x > 2
contains(__, xs) (in xs) x => xs.includes(x)
pipe(length, gt(__, 2)) (.length > 2) x => x.length > 2
isNil (~= null) x => x == null
complement(isNil) (!~= null) x => x != null
match(/foo/) (is /foo/) x => x.match(/foo/)
replace('a', '') (- 'a') x => x.replace('a', '')
join(',') (* ',') x => x.join(',')
split(',') (/ ',') x => x.split(',')
toUpper (.to-upper-case!) x => x.toUpperCase()

See also: Essential LiveScript for ramda-cli

questions or suggestions?

Open an issue

contributors

ramda-cli's People

Contributors

mmqmzk avatar raine avatar waldyrious 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  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  avatar  avatar

Watchers

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

ramda-cli's Issues

Reducing stream without intermediate collections

I'd like to find a simple way to fold a stream into a single value.

Currently the only way to do that is by having an intermediate list:

$ echo 1 2 3 4 5 | R --slurp sum
15

Transducers (and transduce-stream) offer a way to map and filter a stream without creating an intermediate collections, but they don't seem like a solution in this case. It would probably require some kind of reducing transformer just before transduce-stream pushes values to the next stream. Reducing transformer seems unorthodox because normally you'd just use a reduce iterator with transduce.

Investigate possibility of parameterizing a custom reduce stream.

Along the lines of but something nicer than:

$ echo  | R inc --reduce-fn 'add' --reduce-acc '0'
20

Suggestion: add option to ignore CSV/TSV column header mismatch.

Sometimes it is useful to ignore some CSV/TSV syntax errors.
The ps command output some headers separated by only one space, so I can't split the output by / +/, but / +/, then some lines get more fields than the headers. If ramda-cli can ignore those fields, then we can use ramda with ps and more commands.

ps aux | sed -E 's/ +/,/g'

USER,PID,%CPU,%MEM,VSZ,RSS,TTY,STAT,START,TIME,COMMAND 
root,1,0.0,0.0,8324,156,?,Ss,15:55,0:00,/init,ro
root,3,0.0,0.0,8332,164,tty1,Ss,15:55,0:00,/init,ro
zhoukun,4,0.1,0.0,21096,6792,tty1,S,15:55,0:03,zsh
zhoukun,127,0.0,0.0,0,0,tty1,Z,15:56,0:00,[tr],<defunct>
root,692,0.0,0.0,8332,164,tty2,Ss,16:16,0:00,/init,ro
zhoukun,693,0.4,0.0,21096,6868,tty2,S,16:16,0:02,zsh
root,1037,0.0,0.0,8332,164,tty3,Ss,16:17,0:00,/init,ro
zhoukun,1042,1.3,0.0,21228,7176,tty3,S,16:17,0:06,zsh 
zhoukun,2821,0.0,0.0,0,0,tty3,Z,16:22,0:00,[sed],<defunct>
zhoukun,3223,0.0,0.0,17400,1864,tty3,R,16:25,0:00,ps,aux
zhoukun,3224,0.0,0.0,14668,1040,tty3,S,16:25,0:00,sed,-E,s/,+/,/g
ps aux | sed -E 's/ +/,/g' | ramda -i csv 'id'
                
Error: Unexpected Error: column header mismatch expected: 11 columns got: 12

I suggest adding an option named unstrict mode to process CSV/TSV data, if a row has more fields than the headers, the extra fields will be ignored, and if fewer fields will consider as empty string fields.

ramda-cli-tutorial.md

https://gist.github.com/raine/d12d0ec3e72b2945510b

Thanks for the tutorial!
A few things:

  • After installing ramda-cli, I have command ramda, not R. I see that alias R='ramda' is in the readme but it could also go in this tutorial at the beginning.
  • I was confused by reverse 'take 10' -- initially thinking that reverse takes take 10 as an argument. I suggest putting reverse on a newline. I think this makes it more consistent by showing each line is equivalent to one argument to R.pipe:
curl -s $url | R -p 'filter where-eq fork: false' \
  'project [\name \stargazers_count]' \
  'sort-by prop \stargazers_count' \
  reverse \
  'take 10'
  • Regarding run from file: Can I require the version of ramda installed by ramda-cli in my script? Or should I install npm install -g ramda separately?

Alias for identity

identity gets typed a lot, and I already have a keyboard macro \id โ†’ identity for it.

Thinking if it should be aliased to something like I, as it used to be in ramda.

Question: how to make destructing of object?

Hi, thanks for your awesome lib. I am wondering if there any way to do destructuring on some object with it. For example:
cat channels_list.json | R keys - gives me

[
"ok",
"channels"
]

And I want to get channels
cat channels_list.json | R '(x => x.channels)' - does not work

Big files

Imagine you have a huge file that you want to transform/filter. It won't fit in memory.

One might expect that using the -S option solves their issue. They try, and discover it does not. Instead they'll have to split the huge file using other tools, only then are they able to use Ramda-cli.

Does Ramda-cli want to cover the use case of files which exceed the size of memory?

jq is a tool which can solve your issues. Assuming Ramda-cli will support bigger files, it can compete/compliment jq:

  1. People can leverage their existing JS and Ramda experience to make parallelized shell pipelines.
  2. jq does not have a good use case for performing aggregations. FP and Ramda-cli makes this easy.

Using Ramda and Ramda-cli functions in cli.js

I was trying to alias dotAllPaths to paths in order to be more like the newer version of Ramda and I found that I couldn't. I also couldn't access regular Ramda functions like map. If there is no way to do that right now, it would be a nice addition.

a couple thoughts

I was thinking of a similar project but you beat me to it (by a mile ๐Ÿ˜„ ) Looks really great! A couple thoughts I had:

  • support different input types. I would say maybe change -i, --inspect to -p, --pretty-print and use -i, --input-type and support at least csv/tsv out of the box. Also would be cool to support "white-space columns" input type (not sure what the accepted name is for that), eg the output of ls -l, top -n 1, ps aux etc. This may be a little more work than csv as I couldn't find any packages that already do this but I also am not sure exactly what terms to search for. Others?
  • support different output types. I see you've added -r, --raw-output, maybe get rid of that and add -o, --output-type to be a companion to -i (and handle -o raw) and support all the same input types
  • add an option to "save" your snippet. This is of course somewhat unnecessary (bash history, good old copy paste), but it hints to users/potential users how awesome ramda-cli can be as they can easily reuse the awesome cli stuff they've built. So I could do something like cat friends.json |\ ramda --save-as ~/bin/first-names.ramda 'first-word=(head . split " "); prop(\friends) >> map(first-word . prop(\fullName)) >> sortBy length' which would write the associated snippet to the file, and then in the future I can just run cat friends.json | first-names.ramda and I'm good to go ๐Ÿ˜„

I was going to submit a PR but I've never used livescript and while it looks neat I don't have much free time at the moment.

Markdown Table?

Markdown tables would be pretty amazing for sharing data output from a ramda-cli pipeline.

readme.md

Hi @raine -- I read through the readme. Really liked your examples. Some comments:

  1. I think it is important to say that you have to use quotes '' for functions with arity greater than 1. But also, quotes aren't required when the function has arity 1.
  2. Also, I would have a paragraph at the beginning of the readme explaining the main livescript syntaxes you are using in the examples: function calls without parentheses, using single underscore _ for "gaps" in curried functions, and using dash-casing function names (using regular camelCasing also seems to works). I am not really familiar with livescript, so it would be helpful to say those specifics upfront before showing examples.
  3. Ramda function double underscore __ does not work for me. I assume this has to do with conflict with livescript singe underscore _?
  4. Add links for example dependencies Graphite, twarc.py
  5. The "credit card JSON to csv" example refers to a broken/unknown url
  6. In example "List a project's dependencies," I get error: the map-obj function is unknown. I do not see a mapObj function in the current Ramda documentation.

Edit:
You may also want to add: I noticed in the case of csv, if there is an empty input value, it returns a property with a empty string (maybe that is obvious for other people?).

$ cat <<EOF | ramda --input-type csv id
,name
1, 
,Alice
EOF
[
  {
    "": "1",
    "name": ""
  },
  {
    "": "",
    "name": "Alice"
  }
]

Import no longer works with npm 8+

Using the --import flag with node 16/npm 8 returns an error like:

/usr/local/node-v16.13.1-linux-x64/lib/node_modules/ramda-cli/node_modules/global-npm/index.js:37
      throw e
      ^

Error: The programmatic API was removed in npm v8.0.0
    at Object.<anonymous> (/usr/local/node-v16.13.1-linux-x64/lib/node_modules/npm/index.js:4:9)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at /usr/local/node-v16.13.1-linux-x64/lib/node_modules/ramda-cli/node_modules/global-npm/index.js:29:15
    at Object.<anonymous> (/usr/local/node-v16.13.1-linux-x64/lib/node_modules/ramda-cli/node_modules/global-npm/index.js:41:3)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)

Specifically, I was trying to use the time-ago module like in the cookbook example.

doesn't seem to be working on windows

I'm not fully familiar with how node/npm does console apps and I don't have much time for more debugging (I might have time later). But this is a start.

Not sure what exactly is going on but when I run this command (the others give errors too, but one thing at a time :-) ):

ramda --no-stdin 'always "hello world"' 'add __, \!'

I get this output

ramda : Error: Cannot find module 'C:\Users\1198462\.config\ramda-cli'
At line:2 char:1
+ ramda --no-stdin 'always "hello world"' 'add __, \!'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Error: Cannot f...nfig\ramda-cli':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

when I intercept the call in C:\Program Files (x86)\nodejs\node_modules\ramda-cli\bin with
console.log(process.argv, process.stdin, process.stdout, process.stderr):

[ 'C:\\Program Files (x86)\\nodejs\\\\node.exe',
  'C:\\Program Files (x86)\\nodejs\\node_modules\\ramda-cli\\bin\\ramda',
  '--no-stdin',
  'always hello',
  'world',
  'add __, \\!' ] { _connecting: false,
  _hadError: false,
  _handle: 
   { fd: undefined,
     writeQueueSize: 0,
     owner: [Circular],
     onread: [Function: onread],
     reading: false },
  _parent: null,
  _host: null,
  _readableState: 
   { objectMode: false,
     highWaterMark: 0,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: false,
     needReadable: true,
     emittedReadable: false,
     readableListening: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: 
   { end: { [Function: g] listener: [Function: onend] },
     finish: [Function: onSocketFinish],
     _socketEnd: [Function: onSocketEnd],
     pause: [Function] },
  _maxListeners: undefined,
  _writableState: 
   { objectMode: false,
     highWaterMark: 0,
     needDrain: false,
     ending: false,
     ended: false,
     finished: false,
     decodeStrings: false,
     defaultEncoding: 'utf8',
     length: 0,
     writing: false,
     corked: 0,
     sync: true,
     bufferProcessing: false,
     onwrite: [Function],
     writecb: null,
     writelen: 0,
     bufferedRequest: null,
     lastBufferedRequest: null,
     pendingcb: 0,
     prefinished: false,
     errorEmitted: false },
  writable: false,
  allowHalfOpen: false,
  destroyed: false,
  bytesRead: 0,
  _bytesDispatched: 0,
  _writev: null,
  _pendingData: null,
  _pendingEncoding: '',
  isRaw: false,
  isTTY: true,
  fd: 0 } { _connecting: false,
  _hadError: false,
  _handle: 
   { fd: undefined,
     writeQueueSize: 0,
     owner: [Circular],
     onread: [Function: onread] },
  _parent: null,
  _host: null,
  _readableState: 
   { objectMode: false,
     highWaterMark: 16384,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: false,
  domain: null,
  _events: 
   { end: { [Function: g] listener: [Function: onend] },
     finish: [Function: onSocketFinish],
     _socketEnd: [Function: onSocketEnd] },
  _maxListeners: undefined,
  _writableState: 
   { objectMode: false,
     highWaterMark: 16384,
     needDrain: false,
     ending: false,
     ended: false,
     finished: false,
     decodeStrings: false,
     defaultEncoding: 'utf8',
     length: 0,
     writing: false,
     corked: 0,
     sync: true,
     bufferProcessing: false,
     onwrite: [Function],
     writecb: null,
     writelen: 0,
     bufferedRequest: null,
     lastBufferedRequest: null,
     pendingcb: 0,
     prefinished: false,
     errorEmitted: false },
  writable: true,
  allowHalfOpen: false,
  destroyed: false,
  bytesRead: 0,
  _bytesDispatched: 0,
  _writev: null,
  _pendingData: null,
  _pendingEncoding: '',
  read: null,
  _type: 'pipe',
  fd: 1,
  _isStdio: true,
  destroySoon: [Function],
  destroy: [Function] } { _connecting: false,
  _hadError: false,
  _handle: 
   { fd: undefined,
     writeQueueSize: 0,
     owner: [Circular],
     onread: [Function: onread] },
  _parent: null,
  _host: null,
  _readableState: 
   { objectMode: false,
     highWaterMark: 16384,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: null,
     ended: false,
     endEmitted: false,
     reading: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: false,
  domain: null,
  _events: 
   { end: { [Function: g] listener: [Function: onend] },
     finish: [Function: onSocketFinish],
     _socketEnd: [Function: onSocketEnd] },
  _maxListeners: undefined,
  _writableState: 
   { objectMode: false,
     highWaterMark: 16384,
     needDrain: false,
     ending: false,
     ended: false,
     finished: false,
     decodeStrings: false,
     defaultEncoding: 'utf8',
     length: 0,
     writing: false,
     corked: 0,
     sync: true,
     bufferProcessing: false,
     onwrite: [Function],
     writecb: null,
     writelen: 0,
     bufferedRequest: null,
     lastBufferedRequest: null,
     pendingcb: 0,
     prefinished: false,
     errorEmitted: false },
  writable: true,
  allowHalfOpen: false,
  destroyed: false,
  bytesRead: 0,
  _bytesDispatched: 0,
  _writev: null,
  _pendingData: null,
  _pendingEncoding: '',
  read: null,
  _type: 'pipe',
  fd: 2,
  _isStdio: true,
  destroySoon: [Function],
  destroy: [Function] }

Per project library inclusion

This library is incredible. I'm wondering if its possible to configure included libraries on a per project basis.
I'd like to include Sanctuary but I need these commands to run in a CI environment. I could drop stuff into the HOME directory but it'd be a lot nicer for ramda cli to piggy back of modules that already exist in a project.

Would you be open to a PR that enables piggy backing on ./node_modules/.bin in the cwd? I'd be fine if it was guarded by a flag. Maybe something like:

ramda --include sanctuary

I'd like the functions to be injected as globals but I'd be ok to namespace them if that's better, something like?

ramda --include T=data.task

What do you think?

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.