Giter Club home page Giter Club logo

getopts's Introduction

getopts

A Rust library for option parsing for CLI utilities.

Documentation

Usage

Add this to your Cargo.toml:

[dependencies]
getopts = "0.2"

Contributing

The getopts library is used by rustc, so we have to be careful about not changing its behavior.

getopts's People

Contributors

alexcrichton avatar bgermann avatar daingun avatar johntitor avatar jridgewell avatar klutzy avatar kodraus avatar kornelski avatar ltratt avatar mark-simulacrum avatar ms2ger avatar n1000 avatar prasannavl avatar prataprc avatar r-52 avatar razrfalcon avatar remram44 avatar samgiles avatar shepmaster avatar simonsapin avatar steveklabnik avatar t-rapp avatar tisonkun avatar tromey avatar varkor avatar withoutboats avatar xfbs avatar zachdaniel avatar zaechus avatar zdenek-crha 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

getopts's Issues

[Feature Request] Support single dash long names

I'm trying to port an old C application to Rust at the moment. All of the options look like -stop; I can't find an argument parsing library in Rust which supports this format. It'd be great if getopts could support this legacy argument style for compatibility with old applications where that style is still required.

Usage: seperate options, print whitespace for long only options

For example cp --help prints:

Mandatory arguments to long options are mandatory for short options too.
  -a, --archive                same as -dR --preserve=all
      --attributes-only        don't copy the file data, just the attributes

Though the current implementation of usage would print this as:

Mandatory arguments to long options are mandatory for short options too.
  -a --archive                same as -dR --preserve=all
  --attributes-only           don't copy the file data, just the attributes

minimal supported version of Rust missing from Contributing section

The 'contributing' section of the readme contains note that the getopts crate is used by compiler and contributors must be careful to not break anything. Is there also consensus on what is the minimal supported version of rust compiler used to build the crate?

Example: I want to contribute by writing example code, but I'm not sure if using std::maches!() macro is a good idea or not since it is supported only from Rust 1.42.0.

I have err-ed on the side of caution and used different approach. But it would be nice to know what version to target so that example code do not use outdated idioms.

Better usage examples

There are a lot of pieces to this that are uncovered in the example supplied in the docs. More examples would help to better show off how to use this

getopts panics parsing non-UTF-8 arguments

Arguments are OsString objects. While parse() takes an IntoIterator<Item=AsRef<OsStr>> (which can safely accept env::args_os()), the Matches structure only gives out String objects, which can only be built for UTF-8.

I don't know if this can possibly be fixed without breaking anything, but new safe methods on Matches could certainly be introduced.

[Question/Feature Request]

[Question/Feature Request]

Can you take parameters that aren't flags? apt for example does...

apt install
apt upgrade

If so how does one implement that?

Question 2

How does one implement their own fail for each argument? Instead of seeing

Argument to option 'S' missing

I'd like

error: no targets specified (use -h for help)

and have multiple different options for different arguments.

test-threads option is unrecognised

When building rust-getopts with tests enabled on Guix, I got the following error message:

Running .guix-tests/smoke

running 1 test
test main ... FAILED

failures:

---- main stdout ----
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: UnrecognizedOption("test-threads")', tests/smoke.rs:7:48
stack backtrace:
   0:     0x7ffff7e4795b - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h190bc4e71a974fd5
   1:     0x7ffff7ea2cfc - core::fmt::write::h5ab597cdd0c00db2
   2:     0x7ffff7e00701 - <unknown>
   3:     0x7ffff7e23c6e - <unknown>
   4:     0x7ffff7e23952 - std::panicking::default_hook::hcffd5d909668cc52
   5:     0x7ffff7e242ae - std::panicking::rust_panic_with_hook::h67db5ff340e389bf
   6:     0x7ffff7e48277 - <unknown>
   7:     0x7ffff7e47a74 - <unknown>
   8:     0x7ffff7e23db2 - rust_begin_unwind
   9:     0x7ffff7df5ff3 - core::panicking::panic_fmt::h4b9cfd185dab4fab
  10:     0x7ffff7df6343 - core::result::unwrap_failed::h1d2e795ba7bc1e45
  11:     0x5555555588f4 - core::result::Result<T,E>::unwrap::hc3c37c10d473db0e
                               at /tmp/guix-build-rust-1.60.0.drv-0/rustc-1.60.0-src/library/core/src/result.rs:1065:23
  12:     0x5555555588f4 - smoke::main::hddc6ec79ca47762a
                               at /tmp/guix-build-rust-getopts-0.2.21.drv-0/getopts-0.2.21/tests/smoke.rs:7:5
  13:     0x5555555588f4 - smoke::main::{{closure}}::h14f4e8f31826c44b
                               at /tmp/guix-build-rust-getopts-0.2.21.drv-0/getopts-0.2.21/tests/smoke.rs:6:1
  14:     0x5555555588f4 - core::ops::function::FnOnce::call_once::hd8dc59dd743cb5eb
                               at /tmp/guix-build-rust-1.60.0.drv-0/rustc-1.60.0-src/library/core/src/ops/function.rs:227:5
  15:     0x7ffff7f68723 - <unknown>
  16:     0x7ffff7f688e4 - <unknown>
  17:     0x7ffff7f5b80d - <unknown>
  18:     0x7ffff7f7cd2f - <unknown>
  19:     0x7ffff7e1c233 - <unknown>
  20:     0x7ffff7bfe3aa - start_thread
  21:     0x7ffff7c7ef7c - clone3
  22:                0x0 - <unknown>


failures:
    main

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: ".guix-tests/smoke" arguments: ("--test-threads" "16") exit-status: 101 term-signal: #f stop-signal: #f> 
phase `check' failed after 0.0 seconds
command ".guix-tests/smoke" "--test-threads" "16" failed with status 101

Looks like --test-threads isn't supported yet.

Feature request: Parsing style that saves all unrecognized flags

Hi. So currently it seems that getopts does not support a parsing style that tries to match as many flags as possible, while saving the ones that it does not recognize to allow later user inspection. (such parsing style would be useful to mix up two different types of flags, one type which the user controls and the other type forwarded to a subprocess, etc.)

An example scenario: Node.js extracts flags it recognizes, which forwarding the remaining ones to the underlying v8 JavaScript engine.

It is possible to support this parsing style? Or is there some alternative way that this could be achieved?

"long name" specified with a single "-" is recognized as "short name+argument"

Steps to reproduce:

  • Use both long and short names (e.g. "c" & "config")
  • Specify long name on the CLI with a single "-" (e.g. "-config")

Expectation:

  • Option is not matched

Observed:

  • getopts matches as short name with rest of the string returned as argument (e.g. with "-config" matches "c" and returns "onfig" as the argument)

Sample code:

`

  fn main() -> std::io::Result<()> {
     let args: Vec<String> = env::args().collect(); 
     let program = args[0].clone();
     let mut opts = Options::new();

     opts.reqopt("c", "config", "Configuration file", "FILE");
     opts.optflag("h", "help", "Print this help menu");

     let matches = match opts.parse(&args[1..]) {
         Ok(m) => {
             println!("Match found..." );
             println!("{:?}", m.opt_str("config"));
             m
         }
         Err(_f) => { 
             println!("No match found...");
          }
     };

     Ok(())
}

`

Add a way of adding "help" flag which works with required options

I tried to add a --help flag with optflag and a required option.
I expected my_command --help worked, but it didn't because Options::parse() failed due to the lack of the required option.

let mut opts = Options::new();
opts.optflag("h", "help", "Description");
opts.reqopt("r", "required", "Description", "TEST");

let result = opts.parse(&["--help"]);
// Failed with "Required option 'required' missing"!
assert!(result.is_ok());

So, how about have a method to add a help flag, which is an optional and makes parse() work without a required options if it's passed?

let mut opts = Options::new();
opts.helpflag("Description");
opts.reqopt("r", "required", "Description", "TEST");
let result = opts.parse(&["--help"]);
assert!(result.is_ok());

Invalid string returned by Matches::opt_str

I've been working on some bugs in uutils and I think I've found a bug in how getopts handles options with dashes and underscores in the name. Check this sample program:

let args: Vec<String> = env::args().collect();
let mut opts = Options::new();
opts.optflag("", "foo_bar", "");
opts.optopt("", "reference", "", "");

let matches = match opts.parse(&args[1..]) {
    Ok(m) => m,
    Err(_) => { panic!("Error") }
};

matches.opt_present("foo_bar");
let result = matches.opt_str("reference").and_then(|fname| {
    let mut stat = unsafe { mem::uninitialized() };
    let ret = unsafe { libc::stat(fname.as_ptr() as *const _, &mut stat as *mut libc::stat) };
    if ret == 0 {
        println!("Stat ok");
        Some(fname)
    } else {
        println!("FAIL!");
        None
    }
});

Launch the program with touch some_string; ./test --reference some_string.
I have observed the following:

  • if the optional flag is called "foobar", the stat is successful. If it's called "foo_bar" or "foo-bar", the stat always fails;
  • moving the opt_str("reference") block before the opt_present block always works;
  • using a &str instead of fname inside the closure always works;
  • inside the and_then closure, Rust code executes correctly. Calling libc::stat fails;
  • moving the code inside and_then into a standalone program works;
  • a C program that does a stat on the same file works.

This is my first attempt at writing Rust code, so I'm out of ideas on how to debug this further. It seems that fname.as_ptr() is somehow invalid in this example.

Version on crates.io is out of date.

Crates.io only has version 0.2.12 of getopts, but the documentation is about 0.2.13.

This has caused me to spend a while trying to figure out why Error wasn't implemented for Fail.

undocumented/hidden options

Occasionally I want to have undocumented/hidden options that do not appear in the --help list, either due to experimental status, or deprecation. I was wondering if this is currently possible, or if this is feature people would be interested in having?

-- separator

In many CLI parsers, it is a common convention to use -- as a special argument which will force all subsequent arguments to be read as positional/"free". After a quick glance at documentation and code of this crate, I could not find any information on this. How does this crate currently handle the presence of -- options? If it doesn't then consider this a feature request.

OptionMissing using --help with a required option

Sorry for my newbie question, but I can't find a way to exit without error when the --help flag is present and the Options object has a required option.

extern crate getopts;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "print this help menu and exit");
    opts.reqopt("R", "required", "Required option", "VALUE");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f)  =>  {
            // myprogram --help
            println!("Error: {}", f);
            print!("{}", opts.usage("Usage: myprogram [options]"));
            std::process::exit(1);
        }
    };
    if matches.opt_present("h") {
        // myprogram --help --required VALUE
        print!("{}", opts.usage("Usage: myprogram [options]"));
        std::process::exit(0);
    }
    // myprogram --required VALUE
    println!("Running program");
}

Flag with optional value is parsed differently from getopt_long

When using C getopt_long a long option with optional_argument will have a value only if --flag=value syntax is used. --flag arg is parsed as a flag without an argument, and a free argument (I've verified that on macOS and Linux/glibc).

getopts' optflagopt behaves differently. It always takes the next argument as the value, even if the = syntax is not used.

This is problematic for me, because I can't faithfully port C getopt_long program to Rust. I also think it's a less useful behavior, because it makes it impossible to set a optflagopt flag without a value if it's not the last/only argument.

extern crate getopts;

fn main() {
    let mut o = getopts::Options::new();
    o.optflagopt("", "value", "", "");
    
    let m = o.parse(&["--value", "foo", "bar"]).unwrap();
    println!("with space {:?} + {:?}", m.opt_str("value"), m.free);

    let m = o.parse(&["--value=foo", "bar"]).unwrap();
    println!("with = {:?} + {:?}", m.opt_str("value"), m.free);
}

This prints:

with space Some("foo") + ["bar"]
with = Some("foo") + ["bar"]

I'd prefer it to parse as:

with space None + ["foo", "bar"]
with = Some("foo") + ["bar"]

Positional Arguments

I can't seem to find a way to add a positional argument. i.e I don't want to pass a flag.

my_cmd foo instead of my_cmd -v value

Is it possible?

Bug in optflagopt

I've bumped into some weird behaviour in another project whereas the use of an optflagopt option seemed to render unexpected behaviour of the option not being properly parsed.

I decided to come to the source and I extended the mod.rs test to show that something was amiss
pecastro@de5e4db

I've managed to make the test panic when you use an optflagopt in combination with other options.
Initial investigations from debugging the test show that the vals Vec of the Matches struct will have a Vec with Given rather than the option value specified and that is what's causing the return of None and triggering the panic.

self.vals:

[[(0, Val("foo"))], [(1, Val("bar"))], [], [(2, Given)]]

Multiple arguments to a matching option

I am not entirely sure if I missed something in the documentation but is there anyway to catch multiple arguments for a matching option? For example in prog -n file1.txt file2.txt, only file1.txt will be put into a vector for opt_strs in the matching option -n and file2.txt will be in free. Is it possible to catch all arguments following an option with getopts?

getopts: handling of embedded `=` differs for `--name string` and `--name=string`

Issue by pnkfelix
Thursday May 15, 2014 at 08:12 GMT

For earlier discussion, see rust-lang/rust#14223

This issue was labelled with: A-libs in the Rust repository


Sample program:

extern crate getopts;
use getopts::{optopt,optflagopt,getopts};
use std::os;

fn main() {
    let args = os::args();
    let opts =
        [optopt(    "o", "output", "set output file name", "NAME"),
         optflagopt("a", "attrib", "set attribute", "KEY=VALUE")];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };
    let output = matches.opt_str("o");
    let keyval = matches.opt_str("a");

    println!("output: {}", output);
    println!("attrib: {}", keyval);
}

Here is a transcript illustrating some interesting invocations

% rustc /tmp/g.rs
% ./g --output=hm
output: Some(hm)
attrib: None
% ./g --attrib
output: None
attrib: None
% ./g --attrib hi
output: None
attrib: Some(hi)
% ./g --attrib hi=world
output: None
attrib: Some(hi=world)
% ./g -a=hi=world
output: None
attrib: Some(=hi=world)
% ./g -a hi=world
output: None
attrib: Some(hi=world)
% ./g --attrib=hi=world
output: None
attrib: Some(hi)
% 

I think that --attrib hi=world and --attrib=hi=world should be treated as equivalent inputs.

From skimming getopts, this should be relatively easy to fix by replacing the call to split('=') with splitn('=', 1).

Maximum opt description not documented

I used getopts to create an .optopt() with a fairly long description string, and was surprised to see that when I printed the usage, my program panicked with a "... longer than limit!" error message from getopts. I haven't experimented to see what the maximum allowed string length is yet, but I'm surprised that this wasn't documented in .optopt(). Also it would be nice if the library was smart enough to print a multiline usage message instead of panicking.

Add a convenience method to parse from std::env::args

std::os::args is deprecated in favor of std::env::args, which returns an Iterator<OsString>. getopts should include a parse function that accepts this iterator directly, rather than requiring boilerplate to convert it to a Vec<String>.

optflagopt requires `=` form of argument

If you have an optopt option (e.g., --help) then you can have an argument with either a space or an equals sign (--help foo or --help=foo). However, optflagopt requires the = form (--help=foo works but --help foo is treated the same as --help), and this is not documented (and furthermore the help message does not indicate the = form is required, it looks like --help [TOPIC], not --help[=TOPIC] or --help=[TOPIC]).

Panic if the only args are "-"

Given this Rust program:

extern crate getopts;

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let matches = getopts::Options::new().parse(args);
}

The following invocation will create a panic:

$ ./demonstrate_bug -
thread '<main>' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:1

This is using version getopts 0.2.4 with rustc 1.0.0-nightly (6c065fc8c 2015-02-17).

Build failing with the latest nightly compiler build

/Users/uh/.cargo/registry/src/github.com-1ecc6299db9ec823/getopts-0.2.9/src/lib.rs:797:7: 797:56 error: stability attributes may not be used outside of the standard library
/Users/uh/.cargo/registry/src/github.com-1ecc6299db9ec823/getopts-0.2.9/src/lib.rs:797     #[deprecated="use `Debug` (`{}` format specifier)"]

This is the version I used:

uh@macaron:~$ rustc --version
rustc 1.0.0-nightly (2baf34825 2015-04-21) (built 2015-04-21)

Add a getopt flag that consumes all remaining arguments

Issue by Jurily
Sunday Feb 16, 2014 at 03:30 GMT

For earlier discussion, see rust-lang/rust#12306

This issue was labelled with: in the Rust repository


On Unix, some programs run other programs. It is standard convention to pass along the tail of the command line unprocessed.

Examples:

bash -c command [args]
time command [args]
schedtool -e command [args]
chroot /newroot command [args]

Option Groups

Are there any plans of supporting option grouping in the style of Python's argparse module? At least for me that would be on top of the whishlist because I think thematic grouping of options on the usage output can improve readability very much.
I could imagine having a similar API as the argparse one:

...
options.optflag("v", "version", "Print program version");
let optgroup = options.add_option_group("Output options", 
                                        "Options for defining the output file and format");
optgroup.optopt("o", "outfile", "Output file", "FILE");
optgroup.optflag("c", "compress", "Compress output with GZIP");
print!("{}", opts.usage("Usage: mytool [options] <input>"));

output:

Usage: mytool [options] <input>

Options:
    [...]
    -v --version        Print version info and exit

Output Options:
    Options for defining the output file and format

    -o --outfile FILE Output file (output defaults to stdin)
    -c --compress    Compress output with GZIP

There are other things that I like about argparse such as handling of positional arguments and the possibility allow undefined arguments, but I don't know whether there is an intention to keep getopts as simple as possible...

[discuss] special argument group

When using getopts to write rust coreutils, I encounter this problem.
In chmod command, there is arguments like chmod -x file or chmod -0700 file, which will cause getopts return UnrecognizedOption
Of course we can add string "01234567rwx" into optflag, but that is quite weird because they are not expected to show up in opt.usage.
I'm not quite sure how getopts should be modified to deal with this situation.

Enum Occur requires 1 or more

Change current enum Occur to looks like this:

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Occur {
    /// The option occurs once.
    Req,
    /// The option occurs at most once.
    Optional,
    /// The option occurs zero or more times.
    Multi,
    // NEW PART:
    /// The option occurs 1 or more times
    OneOrMore, // other name?
}

Refactor `usage` method, and add `usage_with_format`

Currently the usage method does the formatting, and there's no way to change it. So, I was trying to accomplish this:

    /// Derive a formatted usage message from a set of options.
    pub fn usage(&self, brief: &str) -> String {
        let rows = self.usage_items();
        format!("{}\n\nOptions:\n{}\n", brief,
                rows.collect::<Vec<String>>().join("\n"))
    }

    /// Derive usage items from a set of options.
    pub fn usage_items<'a>(&'a self) -> ReturnIter {
              // Current usage method, except for the formatting line
    }

In order to accomplish this:

  • First thing I noticed was that it I needed to Box up the iterator. So that makes it ReturnIter = Box<__>. Is there a way to do it without?
  • I thought the nicest way to do this would be to have Box<Iterator<Item=String>>. Is there a better approach?

Yank versions 0.1.0 to 0.2.16

As of Rust 1.36, those versions don't compile. This was fixed for 0.2.17 by #61. I think it would be useful to yank those versions for cargo update -Z minimal-versions builds (rust-lang/cargo#5657).

For convenience, commands that can be used to yank all those versions.

cargo yank --vers 0.1.0
cargo yank --vers 0.1.1
cargo yank --vers 0.1.2
cargo yank --vers 0.1.3
cargo yank --vers 0.1.4
cargo yank --vers 0.2.0
cargo yank --vers 0.2.1
cargo yank --vers 0.2.2
cargo yank --vers 0.2.3
cargo yank --vers 0.2.4
cargo yank --vers 0.2.5
cargo yank --vers 0.2.6
cargo yank --vers 0.2.7
cargo yank --vers 0.2.8
cargo yank --vers 0.2.9
cargo yank --vers 0.2.10
cargo yank --vers 0.2.11
cargo yank --vers 0.2.12
cargo yank --vers 0.2.13
cargo yank --vers 0.2.14
cargo yank --vers 0.2.15
cargo yank --vers 0.2.16

Move Repository to rust-lang

Hello, the current rust-lang-nursery organisation is considered deprecated, and the Rust Programming Language organisation is trying to consolidate managing Rust's GitHub organisations, as such we'd like you to consider moving your repository to the main rust-lang organisation instead.

How Do I Move To rust-lang?

You won't be able to transfer your repository directly, you'll need to transfer your repository to @Mark-Simulacrum, who will then move your repository to the rust-lang organisation.

Deprecating

If you no longer intend to maintain this repository, please let us know and we will take of deprecating the project.

getopts should use grapheme clusters for text alignment

Issue by Kimundi
Saturday Mar 23, 2013 at 13:52 GMT

For earlier discussion, see rust-lang/rust#5516

This issue was labelled with: A-libs, E-easy in the Rust repository


It should at minimum align to number of codepoints (characters), (and now that PR #8710 has landed, it should be doing that minimum), but the only correct thing would be to align to grapheme clusters.

test case

extern mod extra;
use extra::getopts::groups;

fn main() {
    let optgroups = ~[
        groups::optflag("a", "apple",        "apple description"),
        groups::optflag("b", "banana\u00AB", "banana description"),
        groups::optflag("c", "br\xfbl\xe9e", "br\xfbl\xe9e quite long description"),
        groups::optflag("k", "kiwi\u20AC",   "kiwi description"),
        groups::optflag("o", "orange\u2039", "orange description"),
        groups::optflag("r",
                        "raspberry-but-making-this-option-way-too-long",
                        "raspberry description is also quite long indeed longer than every other piece of text we might encounter here and thus will be automatically broken up"),
    ];
    println(usage("Usage: fruits", optgroups));
}

current output:

% rustc /tmp/issue5516.rs && /tmp/issue5516 --help
warning: no debug symbols in executable (-arch x86_64)
Usage: fruits

Options:
    -a --apple          apple description
    -b --banana«        banana description
    -c --brûlée         brûlée quite long descripti
    -k --kiwi€          kiwi description
    -o --orange‹        orange description
    -r --raspberry-but-making-this-option-way-too-long 
                        raspberry description is also quite long indeed longer
                        than every other piece of text we might encounter here
                        and thus will be automatically broken up


Note that in addition to things failing to line up, it is also cutting off the end of the text for the brûlée case. That issue should also be fixed.

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.